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.util.ArrayList;
023    import java.util.List;
024    
025    import javax.jbi.messaging.ExchangeStatus;
026    import javax.jbi.messaging.Fault;
027    import javax.jbi.messaging.InOptionalOut;
028    import javax.jbi.messaging.InOut;
029    import javax.jbi.messaging.MessageExchange;
030    import javax.jbi.messaging.MessagingException;
031    import javax.jbi.messaging.NormalizedMessage;
032    import javax.xml.namespace.QName;
033    import javax.xml.transform.Source;
034    
035    import org.apache.cxf.binding.soap.SoapMessage;
036    import org.apache.cxf.binding.soap.interceptor.MustUnderstandInterceptor;
037    import org.apache.cxf.binding.soap.interceptor.ReadHeadersInterceptor;
038    import org.apache.cxf.endpoint.Endpoint;
039    import org.apache.cxf.helpers.IOUtils;
040    import org.apache.cxf.interceptor.AttachmentInInterceptor;
041    import org.apache.cxf.interceptor.Interceptor;
042    import org.apache.cxf.interceptor.StaxInInterceptor;
043    import org.apache.cxf.io.CachedOutputStream;
044    import org.apache.cxf.message.Attachment;
045    import org.apache.cxf.message.Exchange;
046    import org.apache.cxf.message.ExchangeImpl;
047    import org.apache.cxf.message.Message;
048    import org.apache.cxf.phase.PhaseChainCache;
049    import org.apache.cxf.phase.PhaseInterceptorChain;
050    import org.apache.cxf.phase.PhaseManager;
051    import org.apache.cxf.service.model.BindingOperationInfo;
052    import org.apache.cxf.service.model.EndpointInfo;
053    import org.apache.cxf.transport.MessageObserver;
054    import org.apache.servicemix.JbiConstants;
055    import org.apache.servicemix.cxfbc.interceptors.JbiInWsdl1Interceptor;
056    
057    
058    
059    public class CxfBcProviderMessageObserver implements MessageObserver {
060        ByteArrayOutputStream response = new ByteArrayOutputStream();
061    
062        boolean written;
063    
064        String contentType;
065    
066        private CxfBcProvider providerEndpoint;
067    
068        public CxfBcProviderMessageObserver(CxfBcProvider providerEndpoint) {
069            this.providerEndpoint = providerEndpoint;
070        }
071    
072        public ByteArrayOutputStream getResponseStream() throws Exception {
073            synchronized (this) {
074                if (!written) {
075                    wait(1000000000);
076                }
077            }
078            return response;
079        }
080    
081        public String getResponseContentType() {
082            return contentType;
083        }
084    
085        public void onMessage(Message message) {
086            try {
087                MessageExchange messageExchange = message.getExchange().get(MessageExchange.class);
088                if (messageExchange == null) {
089                    // probably, that's a WS-RM Response; use the messageObserver defined in exchange
090                    MessageObserver messageObserver = message.getExchange().get(MessageObserver.class);
091                    if (messageObserver != null) {
092                        messageObserver.onMessage(message);
093                    }
094                    return;
095                }
096                if (messageExchange.getStatus() != ExchangeStatus.ACTIVE) {
097                    return;
098                }
099    
100                contentType = (String) message.get(Message.CONTENT_TYPE);
101                SoapMessage soapMessage = 
102                    (SoapMessage) this.providerEndpoint.getCxfEndpoint().getBinding().createMessage(message);
103                
104                EndpointInfo ei = this.providerEndpoint.getEndpointInfo();
105                QName opeName = messageExchange.getOperation();
106                BindingOperationInfo boi = null;
107                if (opeName == null) {
108                    // if interface only have one operation, may not specify the opeName in MessageExchange
109                    if (ei.getBinding().getOperations().size() == 1) {
110                        boi = ei.getBinding().getOperations().iterator().next();
111                    } else {
112                        throw new org.apache.cxf.interceptor.Fault(
113                                    new Exception("Operation not bound on this MessageExchange"));
114                        
115                    }
116                } else {
117                    boi = ei.getBinding().getOperation(messageExchange.getOperation());   
118                }
119                
120                if (boi.getOperationInfo().isOneWay()) {
121                    return;
122                }
123                
124                soapMessage
125                        .put(org.apache.cxf.message.Message.REQUESTOR_ROLE, true);
126                Exchange cxfExchange = new ExchangeImpl();
127                soapMessage.setExchange(cxfExchange);
128    
129                cxfExchange.put(BindingOperationInfo.class, boi);
130                cxfExchange.put(Endpoint.class, providerEndpoint.getCxfEndpoint());
131                // create Interceptor chain
132    
133                PhaseChainCache inboundChainCache = new PhaseChainCache();
134                PhaseManager pm = providerEndpoint.getBus().getExtension(
135                        PhaseManager.class);
136                List<Interceptor> inList = new ArrayList<Interceptor>();
137                inList.add(new ReadHeadersInterceptor(this.providerEndpoint.getBus()));
138                inList.add(new MustUnderstandInterceptor());
139                inList.add(new StaxInInterceptor());
140                inList.add(new JbiInWsdl1Interceptor(this.providerEndpoint.isUseJBIWrapper(),
141                        this.providerEndpoint.isUseSOAPEnvelope()));
142                inList.add(new AttachmentInInterceptor());
143                PhaseInterceptorChain inChain = inboundChainCache.get(pm
144                        .getInPhases(), inList);
145                inChain.add(providerEndpoint.getInInterceptors());
146                inChain.add(providerEndpoint.getInFaultInterceptors());
147                inChain.add(this.providerEndpoint.getInInterceptors());
148                inChain.add(this.providerEndpoint.getInFaultInterceptors());
149                soapMessage.setInterceptorChain(inChain);
150                inChain.doIntercept(soapMessage);
151                closeConnectionStream(soapMessage);
152                setMessageStatus(soapMessage, boi, messageExchange);
153                boolean txSync = messageExchange.getStatus() == ExchangeStatus.ACTIVE
154                        && messageExchange.isTransacted()
155                        && Boolean.TRUE.equals(messageExchange
156                                .getProperty(JbiConstants.SEND_SYNC));
157                if (txSync) {
158                    providerEndpoint.getContext().getDeliveryChannel().sendSync(
159                            messageExchange);
160                } else {
161                    providerEndpoint.getContext().getDeliveryChannel().send(
162                            messageExchange);
163                }
164    
165            } catch (Exception e) {
166                e.printStackTrace();
167            } finally {
168                synchronized (this) {
169                    written = true;
170                    notifyAll();
171                }
172            }
173        }
174    
175        private void closeConnectionStream(SoapMessage soapMessage) throws IOException {
176            InputStream is = soapMessage.getContent(InputStream.class);
177            if (is != null) {
178                CachedOutputStream bos = new CachedOutputStream();
179                IOUtils.copy(is, bos);
180    
181                bos.flush();
182                is.close();
183    
184                soapMessage.setContent(InputStream.class, bos.getInputStream());
185    
186                bos.close();
187            }
188    
189        }
190    
191        private void setMessageStatus(SoapMessage soapMessage, BindingOperationInfo boi, MessageExchange messageExchange) 
192            throws MessagingException {
193            if (boi.getOperationInfo().isOneWay()) {
194                messageExchange.setStatus(ExchangeStatus.DONE);
195            } else if (soapMessage.get("jbiFault") != null
196                    && soapMessage.get("jbiFault").equals(true)) {
197                Fault fault = messageExchange.createFault();
198                fault.setContent(soapMessage.getContent(Source.class));
199                messageExchange.setFault(fault);
200                if (soapMessage.get("faultstring") != null) {
201                    messageExchange.setProperty("faultstring", soapMessage.get("faultstring"));
202                }
203                if (soapMessage.get("faultcode") != null) {
204                    messageExchange.setProperty("faultcode", soapMessage.get("faultcode"));
205                }
206                if (soapMessage.get("hasdetail") != null) {
207                    messageExchange.setProperty("hasdetail", soapMessage.get("hasdetail"));
208                }
209            } else if (messageExchange instanceof InOut) {
210                NormalizedMessage msg = messageExchange.createMessage();
211                msg.setContent(soapMessage.getContent(Source.class));
212                toNMSAttachments(msg, soapMessage);
213                messageExchange.setMessage(msg, "out");
214            } else if (messageExchange instanceof InOptionalOut) {
215                if (soapMessage.getContent(Source.class) != null) {
216                    NormalizedMessage msg = messageExchange.createMessage();
217                    msg.setContent(soapMessage.getContent(Source.class));
218                    toNMSAttachments(msg, soapMessage);
219                    messageExchange.setMessage(msg, "out");
220                } else {
221                    messageExchange.setStatus(ExchangeStatus.DONE);
222                }
223            } else {
224                messageExchange.setStatus(ExchangeStatus.DONE);
225    
226            }
227        }
228        
229        private void toNMSAttachments(NormalizedMessage normalizedMessage,
230                Message soapMessage) throws MessagingException {
231            if (soapMessage.getAttachments() != null) {
232                for (Attachment att : soapMessage.getAttachments()) {
233                    normalizedMessage.addAttachment(att.getId(), att
234                            .getDataHandler());
235                }
236            }
237        }
238    
239    }