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