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