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.Endpoint;
026 import org.apache.camel.Exchange;
027 import org.apache.camel.ExchangePattern;
028 import org.apache.camel.Processor;
029 import org.apache.camel.Producer;
030 import org.apache.camel.ProducerTemplate;
031 import org.apache.camel.RuntimeCamelException;
032 import org.apache.camel.component.cxf.CxfConstants;
033 import org.apache.camel.component.cxf.util.CxfHeaderHelper;
034 import org.apache.camel.component.cxf.util.CxfMessageHelper;
035 import org.apache.camel.impl.DefaultCamelContext;
036 import org.apache.camel.spi.HeaderFilterStrategy;
037 import org.apache.camel.util.IOHelper;
038 import org.apache.cxf.Bus;
039 import org.apache.cxf.common.logging.LogUtils;
040 import org.apache.cxf.configuration.Configurable;
041 import org.apache.cxf.configuration.Configurer;
042 import org.apache.cxf.io.CachedOutputStream;
043 import org.apache.cxf.message.Message;
044 import org.apache.cxf.service.model.EndpointInfo;
045 import org.apache.cxf.transport.AbstractConduit;
046 import org.apache.cxf.transport.Conduit;
047 import org.apache.cxf.transport.Destination;
048 import org.apache.cxf.transport.MessageObserver;
049 import org.apache.cxf.ws.addressing.EndpointReferenceType;
050
051 /**
052 * @version $Revision: 18641 $
053 */
054 public class CamelConduit extends AbstractConduit implements Configurable {
055 protected static final String BASE_BEAN_NAME_SUFFIX = ".camel-conduit";
056 private static final Logger LOG = LogUtils.getL7dLogger(CamelConduit.class);
057 private CamelContext camelContext;
058 private EndpointInfo endpointInfo;
059 private String targetCamelEndpointUri;
060 private Producer producer;
061 private ProducerTemplate camelTemplate;
062 private Bus bus;
063 private HeaderFilterStrategy headerFilterStrategy;
064
065 public CamelConduit(CamelContext context, Bus b, EndpointInfo endpointInfo) {
066 this(context, b, endpointInfo, null);
067 }
068
069 public CamelConduit(CamelContext context, Bus b, EndpointInfo epInfo, EndpointReferenceType targetReference) {
070 this(context, b, epInfo, targetReference, null);
071 }
072
073 public CamelConduit(CamelContext context, Bus b, EndpointInfo epInfo, EndpointReferenceType targetReference,
074 HeaderFilterStrategy headerFilterStrategy) {
075 super(getTargetReference(epInfo, targetReference, b));
076 String address = epInfo.getAddress();
077 if (address != null) {
078 targetCamelEndpointUri = address.substring(CxfConstants.CAMEL_TRANSPORT_PREFIX.length());
079 if (targetCamelEndpointUri.startsWith("//")) {
080 targetCamelEndpointUri = targetCamelEndpointUri.substring(2);
081 }
082 }
083 camelContext = context;
084 endpointInfo = epInfo;
085 bus = b;
086 initConfig();
087 this.headerFilterStrategy = headerFilterStrategy;
088 Endpoint target = getCamelContext().getEndpoint(targetCamelEndpointUri);
089 try {
090 producer = target.createProducer();
091 producer.start();
092 } catch (Exception e) {
093 throw new RuntimeCamelException("Cannot create the producer rightly", e);
094 }
095 }
096
097 public void setCamelContext(CamelContext context) {
098 camelContext = context;
099 }
100
101 public CamelContext getCamelContext() {
102 if (camelContext == null) {
103 getLogger().log(Level.INFO, "No CamelContext injected, create a default one");
104 camelContext = new DefaultCamelContext();
105 }
106 return camelContext;
107 }
108
109 // prepare the message for send out , not actually send out the message
110 public void prepare(Message message) throws IOException {
111 getLogger().log(Level.FINE, "CamelConduit send message");
112 message.setContent(OutputStream.class, new CamelOutputStream(message));
113 }
114
115 public void close() {
116 getLogger().log(Level.FINE, "CamelConduit closed ");
117 // shutdown the producer
118 try {
119 producer.stop();
120 } catch (Exception e) {
121 getLogger().log(Level.WARNING, "CamelConduit producer stop with the exception", e);
122 }
123 }
124
125 protected Logger getLogger() {
126 return LOG;
127 }
128
129 public String getBeanName() {
130 if (endpointInfo == null || endpointInfo.getName() == null) {
131 return "default" + BASE_BEAN_NAME_SUFFIX;
132 }
133 return endpointInfo.getName().toString() + BASE_BEAN_NAME_SUFFIX;
134 }
135
136 private void initConfig() {
137 // we could configure the camel context here
138 if (bus != null) {
139 Configurer configurer = bus.getExtension(Configurer.class);
140 if (null != configurer) {
141 configurer.configureBean(this);
142 }
143 }
144 }
145
146 @Deprecated
147 public ProducerTemplate getCamelTemplate() throws Exception {
148 if (camelTemplate == null) {
149 camelTemplate = getCamelContext().createProducerTemplate();
150 }
151 return camelTemplate;
152 }
153
154 @Deprecated
155 public void setCamelTemplate(ProducerTemplate template) {
156 camelTemplate = template;
157 }
158
159 private class CamelOutputStream extends CachedOutputStream {
160 private Message outMessage;
161 private boolean isOneWay;
162
163 public CamelOutputStream(Message m) {
164 outMessage = m;
165 }
166
167 protected void doFlush() throws IOException {
168 // do nothing here
169 }
170
171 protected void doClose() throws IOException {
172 isOneWay = outMessage.getExchange().isOneWay();
173 commitOutputMessage();
174 }
175
176 protected void onWrite() throws IOException {
177 // do nothing here
178 }
179
180
181 private void commitOutputMessage() throws IOException {
182 ExchangePattern pattern;
183 if (isOneWay) {
184 pattern = ExchangePattern.InOnly;
185 } else {
186 pattern = ExchangePattern.InOut;
187 }
188 getLogger().log(Level.FINE, "send the message to endpoint" + targetCamelEndpointUri);
189 org.apache.camel.Exchange exchange = producer.createExchange(pattern);
190
191 exchange.setProperty(Exchange.TO_ENDPOINT, targetCamelEndpointUri);
192 CachedOutputStream outputStream = (CachedOutputStream)outMessage.getContent(OutputStream.class);
193 // Send out the request message here, copy the protocolHeader back
194 CxfHeaderHelper.propagateCxfToCamel(headerFilterStrategy, outMessage, exchange.getIn().getHeaders(), exchange);
195
196 // TODO support different encoding
197 exchange.getIn().setBody(outputStream.getBytes());
198 getLogger().log(Level.FINE, "template sending request: ", exchange.getIn());
199 Exception exception = null;
200 try {
201 producer.process(exchange);
202 } catch (Exception ex) {
203 exception = ex;
204 }
205 // Throw the exception that the template get
206 exception = exchange.getException();
207 if (exception != null) {
208 throw IOHelper.createIOException("Can't send the request message.", exchange.getException());
209 }
210 exchange.setProperty(CxfConstants.CXF_EXCHANGE, outMessage.getExchange());
211 if (!isOneWay) {
212 handleResponse(exchange);
213 }
214
215 }
216
217 private void handleResponse(org.apache.camel.Exchange exchange) throws IOException {
218 org.apache.cxf.message.Message inMessage = null;
219 try {
220 inMessage = CxfMessageHelper.getCxfInMessage(headerFilterStrategy,
221 exchange, true);
222 } catch (Exception ex) {
223 // Throw IOException here
224 throw IOHelper.createIOException("Can't get the response message. ", ex);
225 }
226 incomingObserver.onMessage(inMessage);
227 }
228 }
229
230 /**
231 * Represented decoupled response endpoint.
232 */
233 protected class DecoupledDestination implements Destination {
234 protected MessageObserver decoupledMessageObserver;
235 private EndpointReferenceType address;
236
237 DecoupledDestination(EndpointReferenceType ref, MessageObserver incomingObserver) {
238 address = ref;
239 decoupledMessageObserver = incomingObserver;
240 }
241
242 public EndpointReferenceType getAddress() {
243 return address;
244 }
245
246 public Conduit getBackChannel(Message inMessage, Message partialResponse, EndpointReferenceType addr) throws IOException {
247 // shouldn't be called on decoupled endpoint
248 return null;
249 }
250
251 public void shutdown() {
252 }
253
254 public synchronized void setMessageObserver(MessageObserver observer) {
255 decoupledMessageObserver = observer;
256 }
257
258 public synchronized MessageObserver getMessageObserver() {
259 return decoupledMessageObserver;
260 }
261 }
262
263 }