Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||||||
CamelConduit |
|
| 1.55;1.55 |
1 | /** |
|
2 | * |
|
3 | * Licensed to the Apache Software Foundation (ASF) under one or more |
|
4 | * contributor license agreements. See the NOTICE file distributed with |
|
5 | * this work for additional information regarding copyright ownership. |
|
6 | * The ASF licenses this file to You under the Apache License, Version 2.0 |
|
7 | * (the "License"); you may not use this file except in compliance with |
|
8 | * the License. You may obtain a copy of the License at |
|
9 | * |
|
10 | * http://www.apache.org/licenses/LICENSE-2.0 |
|
11 | * |
|
12 | * Unless required by applicable law or agreed to in writing, software |
|
13 | * distributed under the License is distributed on an "AS IS" BASIS, |
|
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
15 | * See the License for the specific language governing permissions and |
|
16 | * limitations under the License. |
|
17 | */ |
|
18 | package org.apache.camel.component.cxf.transport; |
|
19 | ||
20 | import org.apache.camel.CamelContext; |
|
21 | import org.apache.camel.Processor; |
|
22 | import org.apache.cxf.Bus; |
|
23 | import org.apache.cxf.common.logging.LogUtils; |
|
24 | import org.apache.cxf.configuration.Configurable; |
|
25 | import org.apache.cxf.configuration.Configurer; |
|
26 | import org.apache.cxf.io.AbstractCachedOutputStream; |
|
27 | import org.apache.cxf.message.Message; |
|
28 | import org.apache.cxf.message.MessageImpl; |
|
29 | import org.apache.cxf.service.model.EndpointInfo; |
|
30 | import org.apache.cxf.transport.AbstractConduit; |
|
31 | import org.apache.cxf.transport.Conduit; |
|
32 | import org.apache.cxf.transport.Destination; |
|
33 | import org.apache.cxf.transport.MessageObserver; |
|
34 | import org.apache.cxf.ws.addressing.AttributedURIType; |
|
35 | import org.apache.cxf.ws.addressing.EndpointReferenceType; |
|
36 | ||
37 | import java.io.ByteArrayInputStream; |
|
38 | import java.io.ByteArrayOutputStream; |
|
39 | import java.io.IOException; |
|
40 | import java.io.InputStream; |
|
41 | import java.io.OutputStream; |
|
42 | import java.util.logging.Level; |
|
43 | import java.util.logging.Logger; |
|
44 | ||
45 | /** |
|
46 | * @version $Revision: 535478 $ |
|
47 | */ |
|
48 | 0 | public class CamelConduit extends AbstractConduit implements Configurable { |
49 | protected static final String BASE_BEAN_NAME_SUFFIX = ".camel-conduit-base"; |
|
50 | 0 | private static final Logger LOG = LogUtils.getL7dLogger(CamelConduit.class); |
51 | private final CamelTransportBase base; |
|
52 | private String targetCamelEndpointUri; |
|
53 | ||
54 | /* |
|
55 | protected ClientConfig clientConfig; |
|
56 | protected ClientBehaviorPolicyType runtimePolicy; |
|
57 | protected AddressType address; |
|
58 | protected SessionPoolType sessionPool; |
|
59 | */ |
|
60 | ||
61 | public CamelConduit(CamelContext camelContext, Bus bus, EndpointInfo endpointInfo, EndpointReferenceType targetReference) { |
|
62 | 0 | super(targetReference); |
63 | 0 | AttributedURIType address = targetReference.getAddress(); |
64 | 0 | if (address != null) { |
65 | 0 | this.targetCamelEndpointUri = address.getValue(); |
66 | } |
|
67 | ||
68 | 0 | base = new CamelTransportBase(camelContext, bus, endpointInfo, false, BASE_BEAN_NAME_SUFFIX); |
69 | ||
70 | 0 | initConfig(); |
71 | 0 | } |
72 | ||
73 | // prepare the message for send out , not actually send out the message |
|
74 | public void prepare(Message message) throws IOException { |
|
75 | 0 | getLogger().log(Level.FINE, "CamelConduit send message"); |
76 | ||
77 | 0 | message.setContent(OutputStream.class, |
78 | new CamelOutputStream(message)); |
|
79 | 0 | } |
80 | ||
81 | public void close() { |
|
82 | 0 | getLogger().log(Level.FINE, "CamelConduit closed "); |
83 | ||
84 | // ensure resources held by session factory are released |
|
85 | // |
|
86 | 0 | base.close(); |
87 | 0 | } |
88 | ||
89 | protected Logger getLogger() { |
|
90 | 0 | return LOG; |
91 | } |
|
92 | ||
93 | public String getBeanName() { |
|
94 | 0 | EndpointInfo info = base.endpointInfo; |
95 | 0 | if (info == null) { |
96 | 0 | return "default.camel-conduit"; |
97 | } |
|
98 | 0 | return info.getName() + ".camel-conduit"; |
99 | } |
|
100 | ||
101 | private void initConfig() { |
|
102 | ||
103 | /* |
|
104 | this.address = base.endpointInfo.getTraversedExtensor(new AddressType(), |
|
105 | AddressType.class); |
|
106 | this.sessionPool = base.endpointInfo.getTraversedExtensor(new SessionPoolType(), |
|
107 | SessionPoolType.class); |
|
108 | this.clientConfig = base.endpointInfo.getTraversedExtensor(new ClientConfig(), |
|
109 | ClientConfig.class); |
|
110 | this.runtimePolicy = base.endpointInfo.getTraversedExtensor(new ClientBehaviorPolicyType(), |
|
111 | ClientBehaviorPolicyType.class); |
|
112 | */ |
|
113 | ||
114 | 0 | Configurer configurer = base.bus.getExtension(Configurer.class); |
115 | 0 | if (null != configurer) { |
116 | 0 | configurer.configureBean(this); |
117 | } |
|
118 | 0 | } |
119 | ||
120 | 0 | private class CamelOutputStream extends AbstractCachedOutputStream { |
121 | private Message outMessage; |
|
122 | private boolean isOneWay; |
|
123 | ||
124 | 0 | public CamelOutputStream(Message m) { |
125 | 0 | outMessage = m; |
126 | 0 | } |
127 | ||
128 | protected void doFlush() throws IOException { |
|
129 | //do nothing here |
|
130 | 0 | } |
131 | ||
132 | protected void doClose() throws IOException { |
|
133 | 0 | isOneWay = outMessage.getExchange().isOneWay(); |
134 | 0 | commitOutputMessage(); |
135 | 0 | if (!isOneWay) { |
136 | 0 | handleResponse(); |
137 | } |
|
138 | 0 | } |
139 | ||
140 | protected void onWrite() throws IOException { |
|
141 | ||
142 | 0 | } |
143 | ||
144 | private void commitOutputMessage() { |
|
145 | 0 | base.template.send(targetCamelEndpointUri, new Processor() { |
146 | 0 | public void process(org.apache.camel.Exchange reply) { |
147 | 0 | Object request = null; |
148 | ||
149 | 0 | if (isTextPayload()) { |
150 | 0 | request = currentStream.toString(); |
151 | 0 | } |
152 | else { |
|
153 | 0 | request = ((ByteArrayOutputStream) currentStream).toByteArray(); |
154 | } |
|
155 | ||
156 | 0 | getLogger().log(Level.FINE, "Conduit Request is :[" + request + "]"); |
157 | 0 | String replyTo = base.getReplyDestination(); |
158 | ||
159 | //TODO setting up the responseExpected |
|
160 | ||
161 | 0 | base.marshal(request, replyTo, reply); |
162 | ||
163 | 0 | base.setMessageProperties(outMessage, reply); |
164 | ||
165 | 0 | String correlationID = null; |
166 | 0 | if (!isOneWay) { |
167 | // TODO create a correlationID |
|
168 | 0 | String id = null; |
169 | ||
170 | 0 | if (id != null) { |
171 | 0 | if (correlationID != null) { |
172 | 0 | String error = "User cannot set CamelCorrelationID when " |
173 | + "making a request/reply invocation using " |
|
174 | + "a static replyTo Queue."; |
|
175 | } |
|
176 | 0 | correlationID = id; |
177 | } |
|
178 | } |
|
179 | ||
180 | 0 | if (correlationID != null) { |
181 | 0 | reply.getIn().setHeader(CamelConstants.CAMEL_CORRELATION_ID, correlationID); |
182 | } |
|
183 | else { |
|
184 | //No message correlation id is set. Whatever comeback will be accepted as responses. |
|
185 | // We assume that it will only happen in case of the temp. reply queue. |
|
186 | } |
|
187 | ||
188 | 0 | getLogger().log(Level.FINE, "template sending request: ", reply.getIn()); |
189 | 0 | } |
190 | }); |
|
191 | 0 | } |
192 | ||
193 | private void handleResponse() throws IOException { |
|
194 | // REVISIT distinguish decoupled case or oneway call |
|
195 | 0 | Object response = null; |
196 | ||
197 | //TODO if outMessage need to get the response |
|
198 | 0 | Message inMessage = new MessageImpl(); |
199 | 0 | outMessage.getExchange().setInMessage(inMessage); |
200 | //set the message header back to the incomeMessage |
|
201 | //inMessage.put(CamelConstants.CAMEL_CLIENT_RESPONSE_HEADERS, |
|
202 | // outMessage.get(CamelConstants.CAMEL_CLIENT_RESPONSE_HEADERS)); |
|
203 | ||
204 | /* |
|
205 | Object result1; |
|
206 | ||
207 | Object result = null; |
|
208 | ||
209 | javax.camel.Message camelMessage1 = pooledSession.consumer().receive(timeout); |
|
210 | getLogger().log(Level.FINE, "template received reply: " , camelMessage1); |
|
211 | ||
212 | if (camelMessage1 != null) { |
|
213 | ||
214 | base.populateIncomingContext(camelMessage1, outMessage, CamelConstants.CAMEL_CLIENT_RESPONSE_HEADERS); |
|
215 | String messageType = camelMessage1 instanceof TextMessage |
|
216 | ? CamelConstants.TEXT_MESSAGE_TYPE : CamelConstants.BINARY_MESSAGE_TYPE; |
|
217 | result = base.unmarshal((org.apache.camel.Exchange) outMessage); |
|
218 | result1 = result; |
|
219 | } else { |
|
220 | String error = "CamelClientTransport.receive() timed out. No message available."; |
|
221 | getLogger().log(Level.SEVERE, error); |
|
222 | //TODO: Review what exception should we throw. |
|
223 | throw new CamelException(error); |
|
224 | ||
225 | } |
|
226 | response = result1; |
|
227 | ||
228 | //set the message header back to the incomeMessage |
|
229 | inMessage.put(CamelConstants.CAMEL_CLIENT_RESPONSE_HEADERS, |
|
230 | outMessage.get(CamelConstants.CAMEL_CLIENT_RESPONSE_HEADERS)); |
|
231 | ||
232 | */ |
|
233 | ||
234 | 0 | getLogger().log(Level.FINE, "The Response Message is : [" + response + "]"); |
235 | ||
236 | // setup the inMessage response stream |
|
237 | 0 | byte[] bytes = null; |
238 | 0 | if (response instanceof String) { |
239 | 0 | String requestString = (String) response; |
240 | 0 | bytes = requestString.getBytes(); |
241 | 0 | } |
242 | else { |
|
243 | 0 | bytes = (byte[]) response; |
244 | } |
|
245 | 0 | inMessage.setContent(InputStream.class, new ByteArrayInputStream(bytes)); |
246 | 0 | getLogger().log(Level.FINE, "incoming observer is " + incomingObserver); |
247 | 0 | incomingObserver.onMessage(inMessage); |
248 | 0 | } |
249 | } |
|
250 | ||
251 | private boolean isTextPayload() { |
|
252 | // TODO use runtime policy |
|
253 | 0 | return true; |
254 | } |
|
255 | ||
256 | /** |
|
257 | * Represented decoupled response endpoint. |
|
258 | */ |
|
259 | protected class DecoupledDestination implements Destination { |
|
260 | protected MessageObserver decoupledMessageObserver; |
|
261 | private EndpointReferenceType address; |
|
262 | ||
263 | DecoupledDestination(EndpointReferenceType ref, |
|
264 | 0 | MessageObserver incomingObserver) { |
265 | 0 | address = ref; |
266 | 0 | decoupledMessageObserver = incomingObserver; |
267 | 0 | } |
268 | ||
269 | public EndpointReferenceType getAddress() { |
|
270 | 0 | return address; |
271 | } |
|
272 | ||
273 | public Conduit getBackChannel(Message inMessage, |
|
274 | Message partialResponse, |
|
275 | EndpointReferenceType addr) |
|
276 | throws IOException { |
|
277 | // shouldn't be called on decoupled endpoint |
|
278 | 0 | return null; |
279 | } |
|
280 | ||
281 | public void shutdown() { |
|
282 | // TODO Auto-generated method stub |
|
283 | 0 | } |
284 | ||
285 | public synchronized void setMessageObserver(MessageObserver observer) { |
|
286 | 0 | decoupledMessageObserver = observer; |
287 | 0 | } |
288 | ||
289 | public synchronized MessageObserver getMessageObserver() { |
|
290 | 0 | return decoupledMessageObserver; |
291 | } |
|
292 | } |
|
293 | ||
294 | } |