001 /** 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one or more 004 * contributor license agreements. See the NOTICE file distributed with 005 * this work for additional information regarding copyright ownership. 006 * The ASF licenses this file to You under the Apache License, Version 2.0 007 * (the "License"); you may not use this file except in compliance with 008 * the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 package org.apache.camel.component.cxf.transport; 019 020 import org.apache.camel.CamelContext; 021 import org.apache.camel.Processor; 022 import org.apache.cxf.Bus; 023 import org.apache.cxf.common.logging.LogUtils; 024 import org.apache.cxf.configuration.Configurable; 025 import org.apache.cxf.configuration.Configurer; 026 import org.apache.cxf.io.AbstractCachedOutputStream; 027 import org.apache.cxf.message.Message; 028 import org.apache.cxf.message.MessageImpl; 029 import org.apache.cxf.service.model.EndpointInfo; 030 import org.apache.cxf.transport.AbstractConduit; 031 import org.apache.cxf.transport.Conduit; 032 import org.apache.cxf.transport.Destination; 033 import org.apache.cxf.transport.MessageObserver; 034 import org.apache.cxf.ws.addressing.AttributedURIType; 035 import org.apache.cxf.ws.addressing.EndpointReferenceType; 036 037 import java.io.ByteArrayInputStream; 038 import java.io.ByteArrayOutputStream; 039 import java.io.IOException; 040 import java.io.InputStream; 041 import java.io.OutputStream; 042 import java.util.logging.Level; 043 import java.util.logging.Logger; 044 045 /** 046 * @version $Revision: 535478 $ 047 */ 048 public class CamelConduit extends AbstractConduit implements Configurable { 049 protected static final String BASE_BEAN_NAME_SUFFIX = ".camel-conduit-base"; 050 private static final Logger LOG = LogUtils.getL7dLogger(CamelConduit.class); 051 private final CamelTransportBase base; 052 private String targetCamelEndpointUri; 053 054 /* 055 protected ClientConfig clientConfig; 056 protected ClientBehaviorPolicyType runtimePolicy; 057 protected AddressType address; 058 protected SessionPoolType sessionPool; 059 */ 060 061 public CamelConduit(CamelContext camelContext, Bus bus, EndpointInfo endpointInfo, EndpointReferenceType targetReference) { 062 super(targetReference); 063 AttributedURIType address = targetReference.getAddress(); 064 if (address != null) { 065 this.targetCamelEndpointUri = address.getValue(); 066 } 067 068 base = new CamelTransportBase(camelContext, bus, endpointInfo, false, BASE_BEAN_NAME_SUFFIX); 069 070 initConfig(); 071 } 072 073 // prepare the message for send out , not actually send out the message 074 public void prepare(Message message) throws IOException { 075 getLogger().log(Level.FINE, "CamelConduit send message"); 076 077 message.setContent(OutputStream.class, 078 new CamelOutputStream(message)); 079 } 080 081 public void close() { 082 getLogger().log(Level.FINE, "CamelConduit closed "); 083 084 // ensure resources held by session factory are released 085 // 086 base.close(); 087 } 088 089 protected Logger getLogger() { 090 return LOG; 091 } 092 093 public String getBeanName() { 094 EndpointInfo info = base.endpointInfo; 095 if (info == null) { 096 return "default.camel-conduit"; 097 } 098 return info.getName() + ".camel-conduit"; 099 } 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 Configurer configurer = base.bus.getExtension(Configurer.class); 115 if (null != configurer) { 116 configurer.configureBean(this); 117 } 118 } 119 120 private class CamelOutputStream extends AbstractCachedOutputStream { 121 private Message outMessage; 122 private boolean isOneWay; 123 124 public CamelOutputStream(Message m) { 125 outMessage = m; 126 } 127 128 protected void doFlush() throws IOException { 129 //do nothing here 130 } 131 132 protected void doClose() throws IOException { 133 isOneWay = outMessage.getExchange().isOneWay(); 134 commitOutputMessage(); 135 if (!isOneWay) { 136 handleResponse(); 137 } 138 } 139 140 protected void onWrite() throws IOException { 141 142 } 143 144 private void commitOutputMessage() { 145 base.template.send(targetCamelEndpointUri, new Processor() { 146 public void process(org.apache.camel.Exchange reply) { 147 Object request = null; 148 149 if (isTextPayload()) { 150 request = currentStream.toString(); 151 } 152 else { 153 request = ((ByteArrayOutputStream) currentStream).toByteArray(); 154 } 155 156 getLogger().log(Level.FINE, "Conduit Request is :[" + request + "]"); 157 String replyTo = base.getReplyDestination(); 158 159 //TODO setting up the responseExpected 160 161 base.marshal(request, replyTo, reply); 162 163 base.setMessageProperties(outMessage, reply); 164 165 String correlationID = null; 166 if (!isOneWay) { 167 // TODO create a correlationID 168 String id = null; 169 170 if (id != null) { 171 if (correlationID != null) { 172 String error = "User cannot set CamelCorrelationID when " 173 + "making a request/reply invocation using " 174 + "a static replyTo Queue."; 175 } 176 correlationID = id; 177 } 178 } 179 180 if (correlationID != null) { 181 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 getLogger().log(Level.FINE, "template sending request: ", reply.getIn()); 189 } 190 }); 191 } 192 193 private void handleResponse() throws IOException { 194 // REVISIT distinguish decoupled case or oneway call 195 Object response = null; 196 197 //TODO if outMessage need to get the response 198 Message inMessage = new MessageImpl(); 199 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 getLogger().log(Level.FINE, "The Response Message is : [" + response + "]"); 235 236 // setup the inMessage response stream 237 byte[] bytes = null; 238 if (response instanceof String) { 239 String requestString = (String) response; 240 bytes = requestString.getBytes(); 241 } 242 else { 243 bytes = (byte[]) response; 244 } 245 inMessage.setContent(InputStream.class, new ByteArrayInputStream(bytes)); 246 getLogger().log(Level.FINE, "incoming observer is " + incomingObserver); 247 incomingObserver.onMessage(inMessage); 248 } 249 } 250 251 private boolean isTextPayload() { 252 // TODO use runtime policy 253 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 MessageObserver incomingObserver) { 265 address = ref; 266 decoupledMessageObserver = incomingObserver; 267 } 268 269 public EndpointReferenceType getAddress() { 270 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 return null; 279 } 280 281 public void shutdown() { 282 // TODO Auto-generated method stub 283 } 284 285 public synchronized void setMessageObserver(MessageObserver observer) { 286 decoupledMessageObserver = observer; 287 } 288 289 public synchronized MessageObserver getMessageObserver() { 290 return decoupledMessageObserver; 291 } 292 } 293 294 }