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.IOException;
020    import java.util.ArrayList;
021    import java.util.Iterator;
022    import java.util.List;
023    import java.util.Map;
024    import java.util.ResourceBundle;
025    import java.util.Set;
026    import java.util.concurrent.ConcurrentHashMap;
027    import java.util.concurrent.CopyOnWriteArrayList;
028    
029    import javax.activation.DataHandler;
030    import javax.jbi.JBIException;
031    import javax.jbi.component.ComponentContext;
032    import javax.jbi.management.DeploymentException;
033    import javax.jbi.messaging.ExchangeStatus;
034    import javax.jbi.messaging.MessageExchange;
035    import javax.jbi.messaging.NormalizedMessage;
036    import javax.jbi.servicedesc.ServiceEndpoint;
037    import javax.transaction.TransactionManager;
038    import javax.wsdl.WSDLException;
039    import javax.wsdl.extensions.soap.SOAPBinding;
040    import javax.xml.namespace.QName;
041    import javax.xml.transform.Source;
042    
043    import org.w3c.dom.Element;
044    import org.w3c.dom.Node;
045    import org.w3c.dom.NodeList;
046    import com.ibm.wsdl.extensions.soap.SOAPAddressImpl;
047    import com.ibm.wsdl.extensions.soap.SOAPBindingImpl;
048    
049    import org.apache.cxf.Bus;
050    import org.apache.cxf.BusFactory;
051    import org.apache.cxf.attachment.AttachmentImpl;
052    import org.apache.cxf.binding.AbstractBindingFactory;
053    import org.apache.cxf.binding.jbi.JBIFault;
054    import org.apache.cxf.binding.soap.SoapFault;
055    import org.apache.cxf.binding.soap.SoapMessage;
056    import org.apache.cxf.binding.soap.interceptor.MustUnderstandInterceptor;
057    import org.apache.cxf.binding.soap.interceptor.ReadHeadersInterceptor;
058    import org.apache.cxf.binding.soap.interceptor.SoapActionOutInterceptor;
059    import org.apache.cxf.binding.soap.interceptor.SoapOutInterceptor;
060    import org.apache.cxf.binding.soap.interceptor.SoapPreProtocolOutInterceptor;
061    import org.apache.cxf.bus.spring.SpringBusFactory;
062    import org.apache.cxf.catalog.OASISCatalogManager;
063    import org.apache.cxf.continuations.Continuation;
064    import org.apache.cxf.continuations.ContinuationProvider;
065    import org.apache.cxf.endpoint.Endpoint;
066    import org.apache.cxf.endpoint.EndpointImpl;
067    import org.apache.cxf.endpoint.Server;
068    import org.apache.cxf.endpoint.ServerImpl;
069    import org.apache.cxf.endpoint.ServerRegistry;
070    import org.apache.cxf.feature.AbstractFeature;
071    import org.apache.cxf.helpers.DOMUtils;
072    import org.apache.cxf.interceptor.AttachmentInInterceptor;
073    import org.apache.cxf.interceptor.AttachmentOutInterceptor;
074    import org.apache.cxf.interceptor.Fault;
075    import org.apache.cxf.interceptor.Interceptor;
076    import org.apache.cxf.interceptor.OutgoingChainInterceptor;
077    import org.apache.cxf.interceptor.StaxInInterceptor;
078    import org.apache.cxf.interceptor.StaxOutInterceptor;
079    import org.apache.cxf.message.Attachment;
080    import org.apache.cxf.message.Exchange;
081    import org.apache.cxf.message.Message;
082    import org.apache.cxf.message.MessageContentsList;
083    import org.apache.cxf.phase.AbstractPhaseInterceptor;
084    import org.apache.cxf.phase.Phase;
085    import org.apache.cxf.service.Service;
086    import org.apache.cxf.service.invoker.Invoker;
087    import org.apache.cxf.service.model.BindingFaultInfo;
088    import org.apache.cxf.service.model.BindingOperationInfo;
089    import org.apache.cxf.service.model.EndpointInfo;
090    import org.apache.cxf.service.model.FaultInfo;
091    import org.apache.cxf.service.model.MessagePartInfo;
092    import org.apache.cxf.service.model.ServiceInfo;
093    import org.apache.cxf.transport.ChainInitiationObserver;
094    import org.apache.cxf.transport.Destination;
095    import org.apache.cxf.transport.http_jetty.JettyHTTPDestination;
096    import org.apache.cxf.transport.http_jetty.JettyHTTPServerEngine;
097    import org.apache.cxf.transport.jms.JMSConfiguration;
098    import org.apache.cxf.transport.jms.JMSDestination;
099    import org.apache.cxf.ws.addressing.AddressingProperties;
100    import org.apache.cxf.ws.rm.Servant;
101    import org.apache.cxf.wsdl.WSDLManager;
102    import org.apache.cxf.wsdl11.WSDLServiceFactory;
103    import org.apache.servicemix.common.endpoints.ConsumerEndpoint;
104    import org.apache.servicemix.cxfbc.interceptors.JbiInInterceptor;
105    import org.apache.servicemix.cxfbc.interceptors.JbiInWsdl1Interceptor;
106    import org.apache.servicemix.cxfbc.interceptors.JbiJAASInterceptor;
107    import org.apache.servicemix.cxfbc.interceptors.JbiOperationInterceptor;
108    import org.apache.servicemix.cxfbc.interceptors.JbiOutWsdl1Interceptor;
109    import org.apache.servicemix.cxfbc.interceptors.MtomCheckInterceptor;
110    import org.apache.servicemix.jbi.jaxp.SourceTransformer;
111    import org.apache.servicemix.soap.util.DomUtil;
112    import org.mortbay.jetty.Handler;
113    import org.springframework.core.io.Resource;
114    import org.springframework.transaction.PlatformTransactionManager;
115    
116    /**
117     *
118     * @author gnodet
119     * @org.apache.xbean.XBean element="consumer" description="a consumer endpoint
120     *                         that is capable of using SOAP/HTTP or SOAP/JMS"
121     */
122    public class CxfBcConsumer extends ConsumerEndpoint implements
123            CxfBcEndpointWithInterceptor {
124    
125        List<Interceptor> in = new CopyOnWriteArrayList<Interceptor>();
126    
127        List<Interceptor> out = new CopyOnWriteArrayList<Interceptor>();
128    
129        List<Interceptor> outFault = new CopyOnWriteArrayList<Interceptor>();
130    
131        List<Interceptor> inFault = new CopyOnWriteArrayList<Interceptor>();
132    
133        private Resource wsdl;
134    
135        private Endpoint ep;
136    
137        private ChainInitiationObserver chain;
138    
139        private Server server;
140    
141        private Map<String, Message> messages = new ConcurrentHashMap<String, Message>();
142    
143        private boolean synchronous = true;
144    
145        private boolean isOneway;
146    
147        private String busCfg;
148    
149        private BindingFaultInfo faultWanted;
150    
151        private Bus bus;
152    
153        private boolean mtomEnabled;
154    
155        private String locationURI;
156    
157        private int timeout = 10;
158    
159        private boolean useJBIWrapper = true;
160    
161        private boolean useSOAPEnvelope = true;
162    
163        private EndpointInfo ei;
164        
165        private List<AbstractFeature> features = new CopyOnWriteArrayList<AbstractFeature>();
166        
167        private boolean transactionEnabled;
168        
169        private boolean isSTFlow; 
170            
171        private ClassLoader suClassLoader;
172        
173        /**
174         * @return the wsdl
175         */
176        public Resource getWsdl() {
177            return wsdl;
178        }
179    
180        /**
181         * Specifies the location of the WSDL defining the endpoint's interface.
182         * 
183         * @param wsdl
184         *            the location of the WSDL contract as a <code>Resource</code>
185         *            object
186         * @org.apache.xbean.Property description="the location of the WSDL document
187         *                            defining the endpoint's interface"
188         */
189        public void setWsdl(Resource wsdl) {
190            this.wsdl = wsdl;
191        }
192    
193        /**
194         * Returns the list of interceptors used to process fault messages being
195         * sent to the provider.
196         * 
197         * @return a list of <code>Interceptor</code> objects
198         */
199        public List<Interceptor> getOutFaultInterceptors() {
200            return outFault;
201        }
202    
203        /**
204         * Returns the list of interceptors used to process fault messages being
205         * recieved by the endpoint.
206         * 
207         * @return a list of <code>Interceptor</code> objects
208         */
209        public List<Interceptor> getInFaultInterceptors() {
210            return inFault;
211        }
212    
213        /**
214         * Returns the list of interceptors used to process responses being recieved
215         * by the endpoint.
216         * 
217         * @return a list of <code>Interceptor</code> objects
218         */
219        public List<Interceptor> getInInterceptors() {
220            return in;
221        }
222    
223        /**
224         * Returns the list of interceptors used to process requests being sent to
225         * the provider.
226         * 
227         * @return a list of <code>Interceptor</code> objects
228         */
229        public List<Interceptor> getOutInterceptors() {
230            return out;
231        }
232    
233        /**
234         * Specifies a list of interceptors used to process responses recieved by
235         * the endpoint.
236         * 
237         * @param interceptors
238         *            a list of <code>Interceptor</code> objects
239         * @org.apache.xbean.Property description="a list of beans configuring
240         *                            interceptors that process incoming responses"
241         */
242        public void setInInterceptors(List<Interceptor> interceptors) {
243            in.addAll(interceptors);
244        }
245    
246        /**
247         * Specifies a list of interceptors used to process faults recieved by the
248         * endpoint.
249         * 
250         * @param interceptors
251         *            a list of <code>Interceptor</code> objects
252         * @org.apache.xbean.Property description="a list of beans configuring
253         *                            interceptors that process incoming faults"
254         */
255        public void setInFaultInterceptors(List<Interceptor> interceptors) {
256            inFault.addAll(interceptors);
257        }
258    
259        /**
260         * Specifies a list of interceptors used to process requests sent by the
261         * endpoint.
262         * 
263         * @param interceptors
264         *            a list of <code>Interceptor</code> objects
265         * @org.apache.xbean.Property description="a list of beans configuring
266         *                            interceptors that process requests"
267         */
268        public void setOutInterceptors(List<Interceptor> interceptors) {
269            out.addAll(interceptors);
270        }
271    
272        /**
273         * Specifies a list of interceptors used to process faults sent by the
274         * endpoint.
275         * 
276         * @param interceptors
277         *            a list of <code>Interceptor</code> objects
278         * @org.apache.xbean.Property description="a list of beans configuring
279         *                            interceptors that process fault messages being
280         *                            returned to the consumer"
281         */
282        public void setOutFaultInterceptors(List<Interceptor> interceptors) {
283            outFault.addAll(interceptors);
284        }
285    
286        public void process(MessageExchange exchange) throws Exception {
287            
288            
289            if (exchange.getStatus() != ExchangeStatus.ACTIVE) {
290                return;
291            }
292            
293            Message message = messages.remove(exchange.getExchangeId());
294                                   
295            synchronized (message.getInterceptorChain()) {
296                boolean oneway = message.getExchange().get(
297                        BindingOperationInfo.class).getOperationInfo().isOneWay();
298                if (!isSynchronous() && !oneway) {
299                    ContinuationProvider continuationProvider = (ContinuationProvider) message
300                            .get(ContinuationProvider.class.getName());
301                    Continuation continuation = continuationProvider.getContinuation();
302                    if (continuation.isPending()) {
303                        continuation.resume();
304                        isSTFlow = false;
305                    } else {
306                        isSTFlow = true;
307                    }
308                } 
309                if (exchange.getStatus() == ExchangeStatus.ACTIVE) {
310                    exchange.setStatus(ExchangeStatus.DONE);
311                    message.getExchange().get(ComponentContext.class)
312                        .getDeliveryChannel().send(exchange);
313                }
314            }
315            
316            
317        }
318    
319        @Override
320        public void start() throws Exception {
321            super.start();
322            try {
323                registerListServiceHandler();
324                applyFeatures();
325                checkJmsTransportTransaction();
326                server.start();
327            } catch (Exception ex) {
328                super.stop();
329                throw ex;
330            }
331        }
332        
333        private void checkJmsTransportTransaction() {
334            Destination destination = server.getDestination();
335            if (destination instanceof JMSDestination) {
336                JMSDestination jmsDestination = (JMSDestination)destination;
337                JMSConfiguration jmsConfig = jmsDestination.getJmsConfig();
338                if (jmsConfig.isSessionTransacted()) {
339                    TransactionManager tm = (TransactionManager) getContext().getTransactionManager();
340                    if (tm == null) {
341                        throw new IllegalStateException("No TransactionManager available");
342                    } else if (tm instanceof PlatformTransactionManager) {
343                        jmsConfig.setSessionTransacted(true);
344                        jmsConfig.setTransactionManager((PlatformTransactionManager)tm);
345                        setSynchronous(true);
346                        transactionEnabled = true;
347                    }
348                }
349            } 
350            
351        }
352    
353        private void applyFeatures() {
354            if (getFeatures() != null) {
355                for (AbstractFeature feature : getFeatures()) {
356                    feature.initialize(server, getBus());
357                }
358            }
359        }
360    
361        private void registerListServiceHandler() {
362            if (server.getDestination() instanceof JettyHTTPDestination) {
363                JettyHTTPDestination jettyDest = (JettyHTTPDestination) server
364                        .getDestination();
365                JettyHTTPServerEngine jettyEng = (JettyHTTPServerEngine) jettyDest
366                        .getEngine();
367                List<Handler> handlers = jettyEng.getHandlers();
368                if (handlers == null) {
369                    handlers = new ArrayList<Handler>();
370                    jettyEng.setHandlers(handlers);
371                }
372                handlers.add(new ListServiceHandler(getBus().getExtension(
373                        ServerRegistry.class)));
374    
375            }
376        }
377    
378        @Override
379        public void stop() throws Exception {
380            server.stop();
381            if (ei.getAddress() != null && ei.getAddress().startsWith("https")) {
382                bus.shutdown(false);
383                bus = null;
384            }
385            if (!isComponentBus()) {
386                //if use the endpoint own bus, then shutdown it
387                bus.shutdown(true);
388                bus = null;
389            }
390            super.stop();
391        }
392    
393        @Override
394        public void validate() throws DeploymentException {
395            try {
396                suClassLoader = Thread.currentThread().getContextClassLoader(); 
397                if (definition == null) {
398                    retrieveWSDL();
399                }
400                if (service == null) {
401                    // looking for the servicename according to targetServiceName
402                    // first
403                    if (definition.getServices().containsKey(getTargetService())) {
404                        service = getTargetService();
405                    } else {
406                        service = (QName) definition.getServices().keySet()
407                                .iterator().next();
408                    }
409                }
410                WSDLServiceFactory factory = new WSDLServiceFactory(getBus(),
411                        definition, service);
412    
413                Service cxfService = factory.create();
414    
415                ei = cxfService.getServiceInfos().iterator().next().getEndpoints()
416                        .iterator().next();
417                for (ServiceInfo serviceInfo : cxfService.getServiceInfos()) {
418                    if (serviceInfo.getName().equals(service)
419                            && getEndpoint() != null
420                            && serviceInfo.getEndpoint(new QName(serviceInfo
421                                    .getName().getNamespaceURI(), getEndpoint())) != null) {
422                        ei = serviceInfo.getEndpoint(new QName(serviceInfo
423                                .getName().getNamespaceURI(), getEndpoint()));
424    
425                    }
426                }
427    
428    
429                if (endpoint == null) {
430                    endpoint = ei.getName().getLocalPart();
431                }
432    
433                if (locationURI != null) {
434                    ei.setAddress(locationURI);
435                }
436    
437                ei.getBinding().setProperty(
438                        AbstractBindingFactory.DATABINDING_DISABLED, Boolean.TRUE);
439    
440                cxfService.getInInterceptors().add(new MustUnderstandInterceptor());
441                cxfService.getInInterceptors().add(new AttachmentInInterceptor());
442                cxfService.getInInterceptors().add(new StaxInInterceptor());
443                cxfService.getInInterceptors().add(
444                        new ReadHeadersInterceptor(getBus()));
445                cxfService.getInInterceptors().add(new JbiOperationInterceptor());
446                cxfService.getInInterceptors().add(
447                        new JbiInWsdl1Interceptor(isUseJBIWrapper(),
448                                isUseSOAPEnvelope()));
449                cxfService.getInInterceptors().add(new JbiInInterceptor());
450                cxfService.getInInterceptors().add(
451                        new JbiJAASInterceptor(((CxfBcComponent) this
452                                .getServiceUnit().getComponent())
453                                .getConfiguration().getAuthenticationService()));
454                cxfService.getInInterceptors().add(new JbiInvokerInterceptor());
455                    
456                cxfService.getInInterceptors().add(new JbiPostInvokerInterceptor());
457    
458                cxfService.getInInterceptors().add(new OutgoingChainInterceptor());
459    
460                cxfService.getOutInterceptors().add(
461                        new JbiOutWsdl1Interceptor(isUseJBIWrapper()));
462    
463                cxfService.getOutInterceptors().add(new SoapActionOutInterceptor());
464                cxfService.getOutInterceptors().add(new AttachmentOutInterceptor());
465                cxfService.getOutInterceptors().add(
466                        new MtomCheckInterceptor(isMtomEnabled()));
467    
468                cxfService.getOutInterceptors().add(new StaxOutInterceptor());
469                cxfService.getOutInterceptors().add(
470                        new SoapPreProtocolOutInterceptor());
471                cxfService.getOutInterceptors().add(
472                        new SoapOutInterceptor(getBus()));
473                cxfService.getOutFaultInterceptors().add(
474                        new SoapOutInterceptor(getBus()));
475    
476                ep = new EndpointImpl(getBus(), cxfService, ei);
477                getInInterceptors().addAll(getBus().getInInterceptors());
478                getInFaultInterceptors().addAll(getBus().getInFaultInterceptors());
479                getOutInterceptors().addAll(getBus().getOutInterceptors());
480                getOutFaultInterceptors()
481                        .addAll(getBus().getOutFaultInterceptors());
482    
483                cxfService.getInInterceptors().addAll(getInInterceptors());
484                cxfService.getInFaultInterceptors()
485                        .addAll(getInFaultInterceptors());
486                cxfService.getOutInterceptors().addAll(getOutInterceptors());
487                cxfService.getOutFaultInterceptors().addAll(
488                        getOutFaultInterceptors());
489    
490                ep.getInInterceptors().addAll(getInInterceptors());
491                ep.getInFaultInterceptors().addAll(getInFaultInterceptors());
492                ep.getOutInterceptors().addAll(getOutInterceptors());
493                ep.getOutFaultInterceptors().addAll(getOutFaultInterceptors());
494    
495                ep.getOutInterceptors().add(new SoapActionOutInterceptor());
496                ep.getOutInterceptors().add(new AttachmentOutInterceptor());
497                ep.getOutInterceptors().add(new StaxOutInterceptor());
498                ep.getOutInterceptors().add(new SoapOutInterceptor(getBus()));
499    
500                cxfService.getInInterceptors().addAll(getBus().getInInterceptors());
501                cxfService.getInFaultInterceptors().addAll(
502                        getBus().getInFaultInterceptors());
503                cxfService.getOutInterceptors().addAll(
504                        getBus().getOutInterceptors());
505                cxfService.getOutFaultInterceptors().addAll(
506                        getBus().getOutFaultInterceptors());
507    
508                chain = new JbiChainInitiationObserver(ep, getBus());
509                server = new ServerImpl(getBus(), ep, null, chain);
510                super.validate();
511            } catch (DeploymentException e) {
512                throw e;
513            } catch (Exception e) {
514                throw new DeploymentException(e);
515            }
516        }
517    
518        private void retrieveWSDL() throws JBIException, WSDLException,
519                DeploymentException, IOException {
520            if (wsdl == null) {
521                if (getTargetService() != null && getTargetEndpoint() != null) {
522                    ServiceEndpoint serviceEndpoint = getServiceUnit()
523                            .getComponent().getComponentContext().getEndpoint(
524                                    getTargetService(), getTargetEndpoint());
525                    if (serviceEndpoint != null) {
526                        description = this.getServiceUnit().getComponent()
527                                .getComponentContext().getEndpointDescriptor(
528                                        serviceEndpoint);
529                        definition = getBus().getExtension(WSDLManager.class)
530                                .getDefinition(
531                                        (Element) description.getFirstChild());
532                        List address = definition.getService(getTargetService())
533                                .getPort(getTargetEndpoint())
534                                .getExtensibilityElements();
535                        if (address == null || address.size() == 0) {
536                            SOAPAddressImpl soapAddress = new SOAPAddressImpl();
537                            // specify default transport if there is no one in the
538                            // internal wsdl
539                            soapAddress.setLocationURI("http://localhost");
540                            definition.getService(getTargetService()).getPort(
541                                    getTargetEndpoint()).addExtensibilityElement(
542                                    soapAddress);
543                        }
544                        List binding = definition.getService(getTargetService())
545                                .getPort(getTargetEndpoint()).getBinding()
546                                .getExtensibilityElements();
547                        if (binding == null || binding.size() == 0) {
548                            // no binding info in the internal wsdl so we need add
549                            // default soap11 binding
550                            SOAPBinding soapBinding = new SOAPBindingImpl();
551                            soapBinding
552                                    .setTransportURI("http://schemas.xmlsoap.org/soap/http");
553                            soapBinding.setStyle("document");
554                            definition.getService(getTargetService()).getPort(
555                                    getTargetEndpoint()).getBinding()
556                                    .addExtensibilityElement(soapBinding);
557                        }
558    
559                    }
560                } else {
561                    throw new DeploymentException("can't get wsdl");
562                }
563    
564            } else {
565                description = DomUtil.parse(wsdl.getInputStream());
566                try {
567                    //ensure the jax-ws-catalog is loaded
568                    OASISCatalogManager.getCatalogManager(getBus()).loadContextCatalogs();
569                    // use wsdl manager to parse wsdl or get cached
570                    // definition
571                    definition = getBus().getExtension(WSDLManager.class)
572                            .getDefinition(wsdl.getURL());
573                } catch (WSDLException ex) {
574                    // throw new ServiceConstructionException(new
575                    // Message("SERVICE_CREATION_MSG", LOG), ex);
576                }
577            }
578        }
579    
580        protected Bus getBus() {
581            if (getBusCfg() != null) {
582                if (bus == null) {
583                    SpringBusFactory bf = new SpringBusFactory();
584                    bus = bf.createBus(getBusCfg());
585                    if (locationURI != null && locationURI.startsWith("/")) {
586                        //it's in the servlet container
587                        //set this bus so that it could be used in CXFManagerServlet
588                        BusFactory.setDefaultBus(bus);
589                    }
590                }
591                return bus;
592            } else {
593                return ((CxfBcComponent) getServiceUnit().getComponent()).getBus();
594            }
595        }
596    
597        private boolean isComponentBus() {
598            return getBus() ==  ((CxfBcComponent) getServiceUnit().getComponent()).getBus();
599        }
600        
601        /**
602         * Specifies the HTTP address to which requests are sent. This value will
603         * overide any value specified in the WSDL.
604         * 
605         * @param locationURI
606         *            the URI as a string
607         * @org.apache.xbean.Property description="the HTTP address to which
608         *                            requests are sent. This value will overide any
609         *                            value specified in the WSDL."
610         */
611        public void setLocationURI(String locationURI) {
612            this.locationURI = locationURI;
613        }
614    
615        public String getLocationURI() {
616            return locationURI;
617        }
618        
619        
620    
621        protected class JbiChainInitiationObserver extends ChainInitiationObserver {
622    
623            public JbiChainInitiationObserver(Endpoint endpoint, Bus bus) {
624                super(endpoint, bus);
625            }
626    
627            protected void setExchangeProperties(Exchange exchange, Message m) {
628                super.setExchangeProperties(exchange, m);
629                exchange.put(ComponentContext.class, CxfBcConsumer.this
630                        .getContext());
631                exchange.put(CxfBcConsumer.class, CxfBcConsumer.this);
632            }
633            
634            public void onMessage(Message m) {
635                m.put("suClassloader", suClassLoader);
636                ClassLoader oldCl = Thread.currentThread().getContextClassLoader();
637                if (oldCl != suClassLoader) {
638                    try {
639                        Thread.currentThread().setContextClassLoader(suClassLoader);
640                        super.onMessage(m);
641                    } finally {
642                        Thread.currentThread().setContextClassLoader(oldCl);
643                    }
644                } else {
645                    super.onMessage(m);
646                }
647            }
648        }
649    
650        public class JbiInvokerInterceptor extends
651                AbstractPhaseInterceptor<Message> {
652    
653            public JbiInvokerInterceptor() {
654                super(Phase.INVOKE);
655            }
656    
657            private Object getInvokee(Message message) {
658                Object invokee = message.getContent(List.class);
659                if (invokee == null) {
660                    invokee = message.getContent(Object.class);
661                }
662                return invokee;
663            }
664    
665            private void copyJaxwsProperties(Message inMsg, Message outMsg) {
666                outMsg.put(Message.WSDL_OPERATION, inMsg
667                        .get(Message.WSDL_OPERATION));
668                outMsg.put(Message.WSDL_SERVICE, inMsg.get(Message.WSDL_SERVICE));
669                outMsg.put(Message.WSDL_INTERFACE, inMsg
670                        .get(Message.WSDL_INTERFACE));
671                outMsg.put(Message.WSDL_PORT, inMsg.get(Message.WSDL_PORT));
672                outMsg.put(Message.WSDL_DESCRIPTION, inMsg
673                        .get(Message.WSDL_DESCRIPTION));
674            }
675    
676            public void handleMessage(final Message message) throws Fault {
677    
678                final Exchange cxfExchange = message.getExchange();
679                final Endpoint endpoint = cxfExchange.get(Endpoint.class);
680                final Service service = endpoint.getService();
681                final Invoker invoker = service.getInvoker();
682    
683                if (invoker instanceof Servant) {
684                    // it's rm request, run the invocation directly in bc, not send
685                    // to se.
686    
687                    Exchange runableEx = message.getExchange();
688    
689                    Object result = invoker.invoke(runableEx, getInvokee(message));
690                    if (!cxfExchange.isOneWay()) {
691                        Endpoint end = cxfExchange.get(Endpoint.class);
692    
693                        Message outMessage = runableEx.getOutMessage();
694                        if (outMessage == null) {
695                            outMessage = end.getBinding().createMessage();
696                            cxfExchange.setOutMessage(outMessage);
697                        }
698                        copyJaxwsProperties(message, outMessage);
699                        if (result != null) {
700                            MessageContentsList resList = null;
701                            if (result instanceof MessageContentsList) {
702                                resList = (MessageContentsList) result;
703                            } else if (result instanceof List) {
704                                resList = new MessageContentsList((List) result);
705                            } else if (result.getClass().isArray()) {
706                                resList = new MessageContentsList((Object[]) result);
707                            } else {
708                                outMessage.setContent(Object.class, result);
709                            }
710                            if (resList != null) {
711                                outMessage.setContent(List.class, resList);
712                            }
713                        }
714                    }
715    
716                    return;
717                }
718    
719                MessageExchange exchange = message
720                        .getContent(MessageExchange.class);
721                ComponentContext context = message.getExchange().get(
722                        ComponentContext.class);
723                CxfBcConsumer.this.configureExchangeTarget(exchange);
724                CxfBcConsumer.this.isOneway = message.getExchange().get(
725                        BindingOperationInfo.class).getOperationInfo().isOneWay();
726                message.getExchange().setOneWay(CxfBcConsumer.this.isOneway);
727    
728                try {
729                    if (CxfBcConsumer.this.isOneway) {
730                        CxfBcConsumer.this.messages.put(exchange.getExchangeId(), message);
731                        context.getDeliveryChannel().send(exchange);
732                    } else if (CxfBcConsumer.this.isSynchronous()) {
733                        CxfBcConsumer.this.messages.put(exchange.getExchangeId(), message);
734                        context.getDeliveryChannel().sendSync(exchange,
735                            timeout * 1000);
736                        process(exchange);
737                    } else {
738                        synchronized (((ContinuationProvider) message.get(
739                                ContinuationProvider.class.getName())).getContinuation()) {
740                            ContinuationProvider continuationProvider = 
741                                (ContinuationProvider) message.get(ContinuationProvider.class.getName());
742                            Continuation continuation = continuationProvider.getContinuation();
743                            if (!continuation.isPending()) {
744                                CxfBcConsumer.this.messages.put(exchange.getExchangeId(), message);
745                                context.getDeliveryChannel().send(exchange);
746                                if (!isSTFlow) {
747                                    continuation.suspend(timeout * 1000);
748                                }
749                            } else {
750                                //retry or timeout
751                                if (!continuation.isResumed()) {
752                                    //exchange timeout
753                                    messages.remove(exchange.getExchangeId());
754                                    throw new Exception("Exchange timed out: " + exchange.getExchangeId());
755                                }
756                                                           
757                            }
758    
759                        }
760                    }
761                } catch (org.apache.cxf.continuations.SuspendedInvocationException e) {
762                    throw e;
763                } catch (Exception e) {
764                    throw new Fault(e);
765                }
766            }
767    
768        }
769    
770        protected class JbiPostInvokerInterceptor extends
771                AbstractPhaseInterceptor<Message> {
772            public JbiPostInvokerInterceptor() {
773                super(Phase.POST_INVOKE);
774                addBefore(OutgoingChainInterceptor.class.getName());
775            }
776    
777            public void handleMessage(final Message message) throws Fault {
778                MessageExchange exchange = message
779                        .getContent(MessageExchange.class);
780                Exchange ex = message.getExchange();
781                if (exchange.getStatus() == ExchangeStatus.ERROR) {
782                    throw new Fault(exchange.getError());
783                }
784                if (!ex.isOneWay()) {
785                    if (exchange.getFault() != null) {
786                        Fault f = null;
787                        if (isUseJBIWrapper()) {
788                            f = new JBIFault(
789                                    new org.apache.cxf.common.i18n.Message(
790                                            "Fault occured", (ResourceBundle) null));
791                            if (exchange.getProperty("faultstring") != null) {
792                                f.setMessage((String) exchange
793                                        .getProperty("faultstring"));
794                            }
795                            if (exchange.getProperty("faultcode") != null) {
796                                f.setFaultCode((QName) exchange
797                                        .getProperty("faultcode"));
798                            } 
799                            if (exchange.getProperty("hasdetail") == null) {
800                                Element details = toElement(exchange.getFault()
801                                        .getContent());
802                                f.setDetail(details);
803                            }
804    
805                        } else {
806                            Element details = toElement(exchange.getFault()
807                                    .getContent());
808    
809                            if (isUseSOAPEnvelope()) {
810                                details = (Element) details.getElementsByTagNameNS(
811                                        details.getNamespaceURI(), "Body").item(0);
812                                assert details != null;
813                                details = (Element) details.getElementsByTagNameNS(
814                                        details.getNamespaceURI(), "Fault").item(0);
815                            }
816                            assert details != null;
817                            if (exchange.getProperty("faultstring") != null) {
818                                details = (Element) details.getElementsByTagName(
819                                        "faultstring").item(0);
820                            } else {
821                                details = (Element) details.getElementsByTagName(
822                                        "detail").item(0);
823                            }
824    
825                            assert details != null;
826                            f = new SoapFault(
827                                    new org.apache.cxf.common.i18n.Message(
828                                            "Fault occured", (ResourceBundle) null),
829                                    new QName(details.getNamespaceURI(), "detail"));
830                            f.setDetail(details);
831                            if (exchange.getProperty("faultstring") != null) {
832                                f.setMessage((String) exchange
833                                        .getProperty("faultstring"));
834                            }
835    
836                        }
837                        processFaultDetail(f, message);
838                        message.put(BindingFaultInfo.class, faultWanted);
839    
840                        throw f;
841                    } else if (exchange.getMessage("out") != null) {
842                        Endpoint endpoint = ex.get(Endpoint.class);
843                        Message outMessage = ex.getOutMessage();
844                        if (outMessage == null) {
845                            outMessage = endpoint.getBinding().createMessage();
846                            ex.setOutMessage(outMessage);
847                        }
848    
849                        NormalizedMessage norMessage = (NormalizedMessage) exchange
850                                .getMessage("out");
851    
852                        if (outMessage instanceof SoapMessage) {
853                            AddressingProperties addressingProperties = WSAUtils
854                                    .getCXFAddressingPropertiesFromMap((Map<String, String>) norMessage
855                                            .getProperty(WSAUtils.WSA_HEADERS_OUTBOUND));
856                            outMessage.put(WSAUtils.WSA_HEADERS_OUTBOUND,
857                                    addressingProperties);
858                        }
859                        List<Attachment> attachmentList = new ArrayList<Attachment>();
860                        outMessage.setContent(Source.class, exchange.getMessage(
861                                "out").getContent());
862                        Set attachmentNames = norMessage.getAttachmentNames();
863    
864                        Iterator iter = attachmentNames.iterator();
865                        while (iter.hasNext()) {
866                            String id = (String) iter.next();
867                            DataHandler dh = norMessage.getAttachment(id);
868                            attachmentList.add(new AttachmentImpl(id, dh));
869                        }
870    
871                        outMessage.setAttachments(attachmentList);
872                    }
873                }
874                
875            }
876            
877            public void handleFault(Message message) {
878                if (transactionEnabled) {
879                    //detect if the fault is defined in the wsdl, which means need return to client and 
880                    //jms transactionManger just commit
881                    Exchange ex = message.getExchange();
882                    BindingOperationInfo boi = ex.get(BindingOperationInfo.class);
883                    for (BindingFaultInfo bfi : boi.getFaults()) {
884                        FaultInfo fi = bfi.getFaultInfo();
885                        //get fault details
886                        MessagePartInfo mpi = fi.getMessageParts().get(0);
887                        if (mpi != null) {
888                            Fault fault = (Fault) message.getContent(Exception.class);
889                            Element detail = fault.getDetail();
890                            if (detail != null 
891                                    && detail.getFirstChild().getLocalName().equals(mpi.getName().getLocalPart())) {
892                                //it's fault defined in the wsdl, so let it go back to the client
893                                return;
894                            }
895                        }
896                    }
897                    //this exception is undefined in the wsdl, so tell the transactionManager injected into
898                    //jms transport need rollback
899                    throw new Error("rollback");
900                }
901            }
902    
903    
904            // this method is used for ws-policy to set BindingFaultInfo
905            protected void processFaultDetail(Fault fault, Message msg) {
906                if (fault.getDetail() == null) {
907                    return;
908                }
909    
910                Element exDetail = (Element) DOMUtils.getChild(fault.getDetail(),
911                        Node.ELEMENT_NODE);
912                if (exDetail == null) {
913                    return;
914                }
915                QName qname = new QName(exDetail.getNamespaceURI(), exDetail
916                        .getLocalName());
917    
918                faultWanted = null;
919                BindingOperationInfo boi = msg.getExchange().get(
920                        BindingOperationInfo.class);
921                if (boi.isUnwrapped()) {
922                    boi = boi.getWrappedOperation();
923                }
924                for (BindingFaultInfo bfi : boi.getFaults()) {
925                    for (MessagePartInfo mpi : bfi.getFaultInfo().getMessageParts()) {
926                        if (qname.equals(mpi.getConcreteName())) {
927                            faultWanted = bfi;
928                            msg.put(BindingFaultInfo.class, faultWanted);
929                            break;
930                        }
931                    }
932                    if (faultWanted != null) {
933                        break;
934                    }
935                }
936    
937            }
938    
939        }
940    
941        private static Element toElement(Source src) throws Fault {
942            try {
943                SourceTransformer transformer = new SourceTransformer();
944                Element ret = transformer.toDOMElement(src);
945                ret = removeEmptyDefaultTns(ret);
946                return ret;
947            } catch (Exception e) {
948                throw new Fault(e);
949            }
950        }
951    
952        private static Element removeEmptyDefaultTns(Element ret) {
953            // to make unquailied fault work
954            if (ret.hasAttribute("xmlns")
955                    && ret.getAttribute("xmlns").length() == 0) {
956                ret.removeAttribute("xmlns");
957            }
958            NodeList nodes = ret.getChildNodes();
959            for (int i = 0; i < nodes.getLength(); i++) {
960                if (nodes.item(i) instanceof Element) {
961                    Element ele = (Element) nodes.item(i);
962                    ele = removeEmptyDefaultTns(ele);
963    
964                }
965            }
966            return ret;
967        }
968    
969        /**
970         * Specifies the location of the CXF configuraiton file used to configure
971         * the CXF bus. This allows you to access features like JMS runtime behavior
972         * and WS-RM.
973         * 
974         * @param busCfg
975         *            a string containing the relative path to the configuration
976         *            file
977         * @org.apache.xbean.Property description="the location of the CXF
978         *                            configuration file used to configure the CXF
979         *                            bus. This allows you to configure features
980         *                            like WS-RM and JMS runtime behavior."
981         */
982        public void setBusCfg(String busCfg) {
983            this.busCfg = busCfg;
984        }
985    
986        public String getBusCfg() {
987            return busCfg;
988        }
989    
990        /**
991         * Specifies if the endpoint can support binnary attachments.
992         * 
993         * @param mtomEnabled
994         *            a boolean
995         * @org.apache.xbean.Property description="Specifies if MTOM / attachment
996         *                            support is enabled. Default is
997         *                            <code>false</code>."
998         */
999        public void setMtomEnabled(boolean mtomEnabled) {
1000            this.mtomEnabled = mtomEnabled;
1001        }
1002    
1003        public boolean isMtomEnabled() {
1004            return mtomEnabled;
1005        }
1006    
1007        /**
1008         * Specifies the interval for which the endpoint will wait for a response,
1009         * This is specified in seconds.
1010         * 
1011         * @param timeout
1012         *            the number of second to wait for a response
1013         * @org.apache.xbean.Property description="the number of second the endpoint
1014         *                            will wait for a response. The default is 10 secs."
1015         */
1016        public void setTimeout(int timeout) {
1017            this.timeout = timeout;
1018        }
1019    
1020        public int getTimeout() {
1021            return timeout;
1022        }
1023    
1024        /**
1025         * Specifies if the endpoint expects messages to use the JBI wrapper for
1026         * SOAP messages.
1027         * 
1028         * @param useJBIWrapper
1029         *            a boolean
1030         * @org.apache.xbean.Property description="Specifies if the JBI wrapper is
1031         *                            sent in the body of the message. Default is
1032         *                            <code>true</code>. Ignore the value of
1033         *                            useSOAPEnvelope if useJBIWrapper is true"
1034         */
1035        public void setUseJBIWrapper(boolean useJBIWrapper) {
1036            this.useJBIWrapper = useJBIWrapper;
1037        }
1038    
1039        public boolean isUseJBIWrapper() {
1040            return useJBIWrapper;
1041        }
1042    
1043        /**
1044         * Specifies if the endpoint expects soap messages when useJBIWrapper is
1045         * false, if useJBIWrapper is true then ignore useSOAPEnvelope
1046         * 
1047         * @org.apache.xbean.Property description="Specifies if the endpoint expects
1048         *                            soap messages when useJBIWrapper is false, if
1049         *                            useJBIWrapper is true then ignore
1050         *                            useSOAPEnvelope. The default is
1051         *                            <code>true</code>.
1052         */
1053        public void setUseSOAPEnvelope(boolean useSOAPEnvelope) {
1054            this.useSOAPEnvelope = useSOAPEnvelope;
1055        }
1056    
1057        public boolean isUseSOAPEnvelope() {
1058            return useSOAPEnvelope;
1059        }
1060    
1061        /**
1062         * Specifies if the endpoint expects send messageExchange by sendSync
1063         * 
1064         * @param synchronous
1065         *            a boolean
1066         * @org.apache.xbean.Property description="Specifies if the endpoint expects
1067         *                            send messageExchange by sendSync . Default is
1068         *                            <code>true</code>."
1069         */
1070        public void setSynchronous(boolean synchronous) {
1071            this.synchronous = synchronous;
1072        }
1073    
1074        public boolean isSynchronous() {
1075            return synchronous;
1076        }
1077    
1078        public void setFeatures(List<AbstractFeature> features) {
1079            this.features = features;
1080        }
1081    
1082        public List<AbstractFeature> getFeatures() {
1083            return features;
1084        }
1085    
1086    }