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.servicemix.cxfbc;
018
019 import java.io.ByteArrayOutputStream;
020 import java.io.IOException;
021 import java.io.InputStream;
022 import java.net.HttpURLConnection;
023 import java.util.ArrayList;
024 import java.util.Iterator;
025 import java.util.List;
026
027 import javax.jbi.messaging.ExchangeStatus;
028 import javax.jbi.messaging.Fault;
029 import javax.jbi.messaging.InOnly;
030 import javax.jbi.messaging.InOptionalOut;
031 import javax.jbi.messaging.InOut;
032 import javax.jbi.messaging.MessageExchange;
033 import javax.jbi.messaging.MessagingException;
034 import javax.jbi.messaging.NormalizedMessage;
035 import javax.xml.bind.JAXBException;
036 import javax.xml.namespace.QName;
037 import javax.xml.stream.XMLStreamReader;
038 import javax.xml.transform.Source;
039
040 import org.apache.cxf.Bus;
041 import org.apache.cxf.binding.soap.SoapMessage;
042 import org.apache.cxf.binding.soap.interceptor.MustUnderstandInterceptor;
043 import org.apache.cxf.binding.soap.interceptor.ReadHeadersInterceptor;
044 import org.apache.cxf.binding.soap.interceptor.StartBodyInterceptor;
045 import org.apache.cxf.endpoint.Endpoint;
046 import org.apache.cxf.helpers.IOUtils;
047 import org.apache.cxf.interceptor.AttachmentInInterceptor;
048 import org.apache.cxf.interceptor.Interceptor;
049 import org.apache.cxf.interceptor.StaxInInterceptor;
050 import org.apache.cxf.io.CachedOutputStream;
051 import org.apache.cxf.message.Attachment;
052 import org.apache.cxf.message.Exchange;
053 import org.apache.cxf.message.ExchangeImpl;
054 import org.apache.cxf.message.Message;
055 import org.apache.cxf.message.MessageUtils;
056 import org.apache.cxf.phase.PhaseInterceptorChain;
057 import org.apache.cxf.phase.PhaseManager;
058 import org.apache.cxf.service.model.BindingOperationInfo;
059 import org.apache.cxf.service.model.EndpointInfo;
060 import org.apache.cxf.staxutils.StaxUtils;
061 import org.apache.cxf.transport.MessageObserver;
062 import org.apache.cxf.ws.addressing.AddressingProperties;
063 import org.apache.cxf.ws.addressing.Names;
064 import org.apache.cxf.ws.addressing.RelatesToType;
065 import org.apache.cxf.ws.addressing.soap.MAPCodec;
066 import org.apache.servicemix.common.JbiConstants;
067 import org.apache.servicemix.cxfbc.interceptors.JbiInWsdl1Interceptor;
068 import org.apache.servicemix.cxfbc.interceptors.SchemaValidationInInterceptor;
069
070 import org.xml.sax.SAXException;
071
072 import com.sun.xml.bind.v2.runtime.reflect.ListIterator;
073
074 public class CxfBcProviderMessageObserver implements MessageObserver {
075 ByteArrayOutputStream response = new ByteArrayOutputStream();
076
077 boolean written;
078
079 String contentType;
080
081
082 private CxfBcProvider providerEndpoint;
083
084 private MessageObserver sharedMessageObserver;
085
086 public CxfBcProviderMessageObserver(CxfBcProvider providerEndpoint) {
087 this.providerEndpoint = providerEndpoint;
088 }
089
090 public ByteArrayOutputStream getResponseStream() throws Exception {
091 synchronized (this) {
092 if (!written) {
093 wait(1000000000);
094 }
095 }
096 return response;
097 }
098
099 public String getResponseContentType() {
100 return contentType;
101 }
102
103 public void onMessage(Message message) {
104 try {
105 // create Interceptor chain
106
107 PhaseManager pm = providerEndpoint.getBus().getExtension(
108 PhaseManager.class);
109 List<Interceptor<? extends Message>> inList = new ArrayList<Interceptor<? extends Message>>();
110 inList.add(new ReadHeadersInterceptor(this.providerEndpoint.getBus()));
111 inList.add(new StartBodyInterceptor());
112 inList.add(new MustUnderstandInterceptor());
113 inList.add(new StaxInInterceptor());
114 inList.add(new JbiInWsdl1Interceptor(this.providerEndpoint.isUseJBIWrapper(),
115 this.providerEndpoint.isUseSOAPEnvelope()));
116 if (this.providerEndpoint.isSchemaValidationEnabled()) {
117 inList.add(new SchemaValidationInInterceptor(this.providerEndpoint.isUseJBIWrapper(),
118 this.providerEndpoint.isUseSOAPEnvelope()));
119 }
120 inList.add(new AttachmentInInterceptor());
121 PhaseInterceptorChain inChain = new PhaseInterceptorChain(pm.getInPhases());
122 inChain.add(providerEndpoint.getBus().getInInterceptors());
123 inChain.add(inList);
124 inChain.add(providerEndpoint.getInInterceptors());
125
126 contentType = (String) message.get(Message.CONTENT_TYPE);
127 SoapMessage soapMessage =
128 (SoapMessage) this.providerEndpoint.getCxfEndpoint().getBinding().createMessage(message);
129
130 soapMessage
131 .put(org.apache.cxf.message.Message.REQUESTOR_ROLE, true);
132 soapMessage.setInterceptorChain(inChain);
133 MessageExchange messageExchange = soapMessage.getExchange().get(MessageExchange.class);
134 if (messageExchange == null) {
135 // probably, that's a WS-RM Response; use the messageObserver defined in exchange
136 MessageObserver messageObserver = message.getExchange().get(MessageObserver.class);
137 if (messageObserver != null) {
138 messageObserver.onMessage(message);
139 return;
140 } else {
141 //decoupled endpoint case we need try to restore the exchange first;
142 Exchange exchange = restoreExchange(soapMessage);
143 if (exchange != null) {
144 MessageObserver rmMessageObserver = exchange.get(MessageObserver.class);
145 if (rmMessageObserver != null) {
146 //means it createsequence messagee
147 sharedMessageObserver = rmMessageObserver;
148 rmMessageObserver.onMessage(soapMessage);
149 return;
150 }
151 } else {
152 //means it acknowlagement message
153 if (sharedMessageObserver != null) {
154 sharedMessageObserver.onMessage(soapMessage);
155 return;
156 }
157 }
158 }
159 }
160 if (messageExchange != null && messageExchange.getStatus() != ExchangeStatus.ACTIVE) {
161 return;
162 }
163
164
165
166 inChain.doIntercept(soapMessage);
167 closeConnectionStream(soapMessage);
168 if (soapMessage.getContent(Exception.class) != null || soapMessage.getContent(Source.class) == null) {
169 Exception ex = soapMessage.getContent(Exception.class);
170 if (!(soapMessage.getExchange().get(MessageExchange.class) instanceof InOnly) && ex != null) {
171 messageExchange.setStatus(ExchangeStatus.ERROR);
172 messageExchange.setError(ex);
173 providerEndpoint.getContext().getDeliveryChannel().send(
174 messageExchange);
175 }
176 return;
177 }
178
179 messageExchange = soapMessage.getExchange().get(MessageExchange.class);
180 if (MessageUtils.isPartialResponse(soapMessage)) {
181 //partial response for origianl channel when use decoupled endpoint
182 return;
183 }
184 if (soapMessage.getExchange().get(BindingOperationInfo.class).getOperationInfo().isOneWay()) {
185 messageExchange.setStatus(ExchangeStatus.DONE);
186 } else if (soapMessage.get("jbiFault") != null
187 && soapMessage.get("jbiFault").equals(true)) {
188 Fault fault = messageExchange.createFault();
189 fault.setContent(soapMessage.getContent(Source.class));
190 messageExchange.setFault(fault);
191 if (soapMessage.get("faultstring") != null) {
192 messageExchange.setProperty("faultstring", soapMessage.get("faultstring"));
193 }
194 if (soapMessage.get("faultcode") != null) {
195 messageExchange.setProperty("faultcode", soapMessage.get("faultcode"));
196 }
197 if (soapMessage.get("hasdetail") != null) {
198 messageExchange.setProperty("hasdetail", soapMessage.get("hasdetail"));
199 }
200
201 } else if (messageExchange instanceof InOut) {
202 NormalizedMessage msg = messageExchange.createMessage();
203 msg.setContent(soapMessage.getContent(Source.class));
204 toNMSAttachments(msg, soapMessage);
205 messageExchange.setMessage(msg, "out");
206 } else if (messageExchange instanceof InOptionalOut) {
207 if (soapMessage.getContent(Source.class) != null) {
208 NormalizedMessage msg = messageExchange.createMessage();
209 msg.setContent(soapMessage.getContent(Source.class));
210 toNMSAttachments(msg, soapMessage);
211 messageExchange.setMessage(msg, "out");
212 } else {
213 messageExchange.setStatus(ExchangeStatus.DONE);
214 }
215 } else {
216 messageExchange.setStatus(ExchangeStatus.DONE);
217
218 }
219 boolean txSync = messageExchange.getStatus() == ExchangeStatus.ACTIVE
220 && messageExchange.isTransacted()
221 && Boolean.TRUE.equals(messageExchange
222 .getProperty(JbiConstants.SEND_SYNC));
223 if (txSync) {
224 providerEndpoint.getContext().getDeliveryChannel().sendSync(
225 messageExchange);
226 } else {
227 providerEndpoint.getContext().getDeliveryChannel().send(
228 messageExchange);
229 }
230
231 } catch (Exception e) {
232 e.printStackTrace();
233 } finally {
234 synchronized (this) {
235 written = true;
236 notifyAll();
237 }
238 }
239 }
240
241 private Exchange restoreExchange(SoapMessage message) throws IOException, SAXException, JAXBException {
242 InputStream is = message.getContent(InputStream.class);
243 //cache the message
244 CachedOutputStream bos = new CachedOutputStream();
245 IOUtils.copy(is, bos);
246 bos.flush();
247 is.close();
248 message.setContent(InputStream.class, bos.getInputStream());
249 ReadHeadersInterceptor readHeadersInterceptor =
250 new ReadHeadersInterceptor(this.providerEndpoint.getBus());
251 readHeadersInterceptor.handleMessage(message);
252 for (Interceptor<?> interceptor : this.providerEndpoint.getBus().getOutInterceptors()) {
253 if (interceptor.getClass().getName().equals("org.apache.cxf.ws.addressing.soap.MAPCodec")) {
254 MAPCodec mapCodec = (MAPCodec) interceptor;
255 AddressingProperties maps = mapCodec.unmarshalMAPs(message);
256 if (maps != null
257 && maps.getRelatesTo() != null
258 && isRelationshipReply(maps.getRelatesTo())) {
259 Exchange correlatedExchange =
260 mapCodec.getUncorrelatedExchanges().get(maps.getRelatesTo().getValue());
261 message.setContent(InputStream.class, bos.getInputStream());
262 bos.close();
263 XMLStreamReader xmlReader =
264 StaxUtils.createXMLStreamReader(message.getContent(InputStream.class));
265 message.setContent(XMLStreamReader.class, xmlReader);
266 message.setContent(InputStream.class, bos.getInputStream());
267 return correlatedExchange;
268
269 }
270
271
272 }
273 }
274 message.setContent(InputStream.class, bos.getInputStream());
275 bos.close();
276 XMLStreamReader xmlReader =
277 StaxUtils.createXMLStreamReader(message.getContent(InputStream.class));
278 message.setContent(XMLStreamReader.class, xmlReader);
279 message.setContent(InputStream.class, bos.getInputStream());
280 return null;
281 }
282
283 private void closeConnectionStream(SoapMessage soapMessage) throws IOException {
284 InputStream is = soapMessage.getContent(InputStream.class);
285 if (is != null) {
286 CachedOutputStream bos = new CachedOutputStream();
287 IOUtils.copy(is, bos);
288 bos.flush();
289 is.close();
290 soapMessage.setContent(InputStream.class, bos.getInputStream());
291 bos.close();
292 }
293
294 }
295
296 private void toNMSAttachments(NormalizedMessage normalizedMessage,
297 Message soapMessage) throws MessagingException {
298 if (soapMessage.getAttachments() != null) {
299 for (Attachment att : soapMessage.getAttachments()) {
300 normalizedMessage.addAttachment(att.getId(), att
301 .getDataHandler());
302 }
303 }
304 }
305
306 private boolean isRelationshipReply(RelatesToType relatesTo) {
307 return Names.WSA_RELATIONSHIP_REPLY.equals(relatesTo.getRelationshipType());
308 }
309
310 }