001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.camel.component.cxf.transport;
018
019 import java.io.IOException;
020 import java.io.OutputStream;
021 import java.util.logging.Level;
022 import java.util.logging.Logger;
023
024 import org.apache.camel.CamelContext;
025 import org.apache.camel.Consumer;
026 import org.apache.camel.Endpoint;
027 import org.apache.camel.Exchange;
028 import org.apache.camel.Processor;
029 import org.apache.camel.ProducerTemplate;
030 import org.apache.camel.component.cxf.CxfConstants;
031 import org.apache.camel.component.cxf.util.CxfHeaderHelper;
032 import org.apache.camel.component.cxf.util.CxfMessageHelper;
033 import org.apache.camel.impl.DefaultCamelContext;
034 import org.apache.camel.spi.HeaderFilterStrategy;
035 import org.apache.cxf.Bus;
036 import org.apache.cxf.common.logging.LogUtils;
037 import org.apache.cxf.configuration.Configurable;
038 import org.apache.cxf.configuration.Configurer;
039 import org.apache.cxf.io.CachedOutputStream;
040 import org.apache.cxf.message.Message;
041 import org.apache.cxf.message.MessageImpl;
042 import org.apache.cxf.service.model.EndpointInfo;
043 import org.apache.cxf.transport.AbstractConduit;
044 import org.apache.cxf.transport.AbstractDestination;
045 import org.apache.cxf.transport.Conduit;
046 import org.apache.cxf.transport.ConduitInitiator;
047 import org.apache.cxf.transport.MessageObserver;
048 import org.apache.cxf.ws.addressing.EndpointReferenceType;
049 import org.apache.cxf.wsdl.EndpointReferenceUtils;
050
051 /**
052 * @version $Revision: 18641 $
053 */
054 public class CamelDestination extends AbstractDestination implements Configurable {
055 protected static final String BASE_BEAN_NAME_SUFFIX = ".camel-destination";
056 private static final Logger LOG = LogUtils.getL7dLogger(CamelDestination.class);
057 final ConduitInitiator conduitInitiator;
058 CamelContext camelContext;
059 Consumer consumer;
060 String camelDestinationUri;
061
062 private ProducerTemplate camelTemplate;
063 private Endpoint destinationEndpoint;
064 private HeaderFilterStrategy headerFilterStrategy;
065 private boolean checkException;
066
067 public CamelDestination(CamelContext camelContext, Bus bus, ConduitInitiator ci, EndpointInfo info) throws IOException {
068 this(camelContext, bus, ci, info, null, false);
069 }
070
071 public CamelDestination(CamelContext camelContext, Bus bus, ConduitInitiator ci, EndpointInfo info,
072 HeaderFilterStrategy headerFilterStrategy, boolean checkException) throws IOException {
073 super(bus, getTargetReference(info, bus), info);
074 this.camelContext = camelContext;
075 conduitInitiator = ci;
076 camelDestinationUri = endpointInfo.getAddress().substring(CxfConstants.CAMEL_TRANSPORT_PREFIX.length());
077 if (camelDestinationUri.startsWith("//")) {
078 camelDestinationUri = camelDestinationUri.substring(2);
079 }
080 initConfig();
081 this.headerFilterStrategy = headerFilterStrategy;
082 this.checkException = checkException;
083 }
084
085 protected Logger getLogger() {
086 return LOG;
087 }
088
089 public void setCheckException(boolean exception) {
090 checkException = exception;
091 }
092
093 public boolean isCheckException() {
094 return checkException;
095 }
096 /**
097 * @param inMessage the incoming message
098 * @return the inbuilt backchannel
099 */
100 protected Conduit getInbuiltBackChannel(Message inMessage) {
101 //we can pass the message back by looking up the camelExchange from inMessage
102 return new BackChannelConduit(inMessage);
103 }
104
105 public void activate() {
106 getLogger().log(Level.FINE, "CamelDestination activate().... ");
107
108 try {
109 getLogger().log(Level.FINE, "establishing Camel connection");
110 destinationEndpoint = getCamelContext().getEndpoint(camelDestinationUri);
111 consumer = destinationEndpoint.createConsumer(new ConsumerProcessor());
112 consumer.start();
113
114 } catch (Exception ex) {
115 // TODO: Is it okay just to log severe errors such as this?
116 getLogger().log(Level.SEVERE, "Camel connect failed with Exception : ", ex);
117 }
118 }
119
120 public void deactivate() {
121 try {
122 consumer.stop();
123 } catch (Exception e) {
124 // TODO: Is it okay just to log severe errors such as this?
125 getLogger().log(Level.SEVERE, "Camel stop failed with Exception : ", e);
126 }
127 }
128
129 public void shutdown() {
130 getLogger().log(Level.FINE, "CamelDestination shutdown()");
131 this.deactivate();
132 }
133
134 public ProducerTemplate getCamelTemplate() throws Exception {
135 if (camelTemplate == null) {
136 camelTemplate = getCamelContext().createProducerTemplate();
137 }
138 return camelTemplate;
139 }
140
141 public void setCamelTemplate(ProducerTemplate template) {
142 camelTemplate = template;
143 }
144
145 public void setCamelContext(CamelContext context) {
146 camelContext = context;
147 }
148
149 public CamelContext getCamelContext() {
150 if (camelContext == null) {
151 getLogger().log(Level.INFO, "No CamelContext injected, create a default one");
152 camelContext = new DefaultCamelContext();
153 }
154 return camelContext;
155 }
156
157 protected void incoming(org.apache.camel.Exchange camelExchange) {
158 getLogger().log(Level.FINE, "server received request: ", camelExchange);
159 org.apache.cxf.message.Message inMessage =
160 CxfMessageHelper.getCxfInMessage(headerFilterStrategy, camelExchange, false);
161
162 inMessage.put(CxfConstants.CAMEL_EXCHANGE, camelExchange);
163 ((MessageImpl)inMessage).setDestination(this);
164
165 // Handling the incoming message
166 // The response message will be send back by the outgoingchain
167 incomingObserver.onMessage(inMessage);
168
169 }
170
171 public String getBeanName() {
172 if (endpointInfo == null || endpointInfo.getName() == null) {
173 return "default" + BASE_BEAN_NAME_SUFFIX;
174 }
175 return endpointInfo.getName().toString() + BASE_BEAN_NAME_SUFFIX;
176 }
177
178 public String getCamelDestinationUri() {
179 return camelDestinationUri;
180 }
181
182 private void initConfig() {
183 //we could configure the camel context here
184 if (bus != null) {
185 Configurer configurer = bus.getExtension(Configurer.class);
186 if (null != configurer) {
187 configurer.configureBean(this);
188 }
189 }
190 }
191
192 protected class ConsumerProcessor implements Processor {
193 public void process(Exchange exchange) {
194 try {
195 incoming(exchange);
196 } catch (Throwable ex) {
197 getLogger().log(Level.WARNING, "Failed to process incoming message : ", ex);
198 }
199 }
200 }
201
202 // this should deal with the cxf message
203 protected class BackChannelConduit extends AbstractConduit {
204 protected Message inMessage;
205 Exchange camelExchange;
206 org.apache.cxf.message.Exchange cxfExchange;
207 BackChannelConduit(Message message) {
208 super(EndpointReferenceUtils.getAnonymousEndpointReference());
209 inMessage = message;
210 cxfExchange = inMessage.getExchange();
211 camelExchange = cxfExchange.get(Exchange.class);
212 }
213
214 /**
215 * Register a message observer for incoming messages.
216 *
217 * @param observer the observer to notify on receipt of incoming
218 */
219 public void setMessageObserver(MessageObserver observer) {
220 // shouldn't be called for a back channel conduit
221 }
222
223 /**
224 * Send an outbound message, assumed to contain all the name-value
225 * mappings of the corresponding input message (if any).
226 *
227 * @param message the message to be sent.
228 */
229 public void prepare(Message message) throws IOException {
230 message.put(CxfConstants.CAMEL_EXCHANGE, inMessage.get(CxfConstants.CAMEL_EXCHANGE));
231 message.setContent(OutputStream.class, new CamelOutputStream(message));
232
233 }
234
235 protected Logger getLogger() {
236 return LOG;
237 }
238
239 }
240
241 /**
242 * Mark message as a partial message.
243 *
244 * @param partialResponse the partial response message
245 * @param decoupledTarget the decoupled target
246 * @return <tt>true</tt> if partial responses is supported
247 */
248 protected boolean markPartialResponse(Message partialResponse,
249 EndpointReferenceType decoupledTarget) {
250 return true;
251 }
252
253 /**
254 * @return the associated conduit initiator
255 */
256 protected ConduitInitiator getConduitInitiator() {
257 return conduitInitiator;
258 }
259
260 /**
261 * @param outMessage
262 * @param camelExchange
263 */
264 protected void propagateResponseHeadersToCamel(Message outMessage, Exchange camelExchange) {
265 CxfHeaderHelper.propagateCxfToCamel(headerFilterStrategy, outMessage,
266 camelExchange.getOut().getHeaders(), camelExchange);
267 }
268
269 private class CamelOutputStream extends CachedOutputStream {
270 private Message outMessage;
271
272 public CamelOutputStream(Message m) {
273 super();
274 outMessage = m;
275 }
276
277 // Prepare the message and get the send out message
278 private void commitOutputMessage() throws IOException {
279 Exchange camelExchange = (Exchange)outMessage.get(CxfConstants.CAMEL_EXCHANGE);
280
281 propagateResponseHeadersToCamel(outMessage, camelExchange);
282
283 // check if the outMessage has the exception
284 Exception exception = outMessage.getContent(Exception.class);
285 if (checkException && exception != null) {
286 camelExchange.setException(exception);
287 }
288
289 CachedOutputStream outputStream = (CachedOutputStream)outMessage.getContent(OutputStream.class);
290 camelExchange.getOut().setBody(outputStream.getBytes());
291 getLogger().log(Level.FINE, "send the response message: " + outputStream);
292
293 }
294
295 @Override
296 protected void doFlush() throws IOException {
297 // Do nothing here
298 }
299
300 @Override
301 protected void doClose() throws IOException {
302 commitOutputMessage();
303 }
304
305 @Override
306 protected void onWrite() throws IOException {
307 // Do nothing here
308 }
309 }
310
311 }