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.camel.component.cxf;
018    
019    
020    import java.util.HashMap;
021    import java.util.Map;
022    
023    import org.apache.camel.Processor;
024    import org.apache.camel.impl.DefaultConsumer;
025    import org.apache.commons.logging.Log;
026    import org.apache.commons.logging.LogFactory;
027    import org.apache.cxf.endpoint.Server;
028    import org.apache.cxf.frontend.ServerFactoryBean;
029    import org.apache.cxf.interceptor.Fault;
030    import org.apache.cxf.message.Exchange;
031    import org.apache.cxf.service.invoker.Invoker;
032    import org.apache.cxf.service.model.BindingOperationInfo;
033    
034    /**
035     * A Consumer of exchanges for a service in CXF.  CxfConsumer acts a CXF
036     * service to receive requests, convert them, and forward them to Camel 
037     * route for processing. It is also responsible for converting and sending
038     * back responses to CXF client.
039     *
040     * @version $Revision: 21400 $
041     */
042    public class CxfConsumer extends DefaultConsumer {
043        private static final Log LOG = LogFactory.getLog(CxfConsumer.class);
044        private Server server;
045    
046        public CxfConsumer(CxfEndpoint endpoint, Processor processor) throws Exception {
047            super(endpoint, processor);
048            
049            // create server
050            ServerFactoryBean svrBean = endpoint.createServerFactoryBean();
051            svrBean.setInvoker(new Invoker() {
052    
053                // we receive a CXF request when this method is called
054                public Object invoke(Exchange cxfExchange, Object o) {
055    
056                    if (LOG.isTraceEnabled()) {
057                        LOG.trace("Received CXF Request: " + cxfExchange);
058                    }
059                    
060                    // get CXF binding
061                    CxfEndpoint endpoint = (CxfEndpoint)getEndpoint();
062                    CxfBinding binding = endpoint.getCxfBinding();
063    
064                    // create a Camel exchange
065                    org.apache.camel.Exchange camelExchange = endpoint.createExchange();
066                    DataFormat dataFormat = endpoint.getDataFormat();
067    
068                    BindingOperationInfo boi = cxfExchange.getBindingOperationInfo();
069                    // make sure the "boi" is remained as wrapped in PAYLOAD mode
070                    if (dataFormat == DataFormat.PAYLOAD && boi.isUnwrapped()) {
071                        boi = boi.getWrappedOperation();
072                        cxfExchange.put(BindingOperationInfo.class, boi);
073                    }
074                    
075                    if (boi != null) {
076                        camelExchange.setProperty(BindingOperationInfo.class.getName(), boi);
077                        if (LOG.isTraceEnabled()) {
078                            LOG.trace("Set exchange property: BindingOperationInfo: " + boi);
079                        }
080                    }
081                    
082                    // set data format mode in Camel exchange
083                    camelExchange.setProperty(CxfConstants.DATA_FORMAT_PROPERTY, dataFormat);   
084                    if (LOG.isTraceEnabled()) {
085                        LOG.trace("Set Exchange property: " + DataFormat.class.getName() 
086                                + "=" + dataFormat);
087                    }
088                    
089                    // bind the CXF request into a Camel exchange
090                    binding.populateExchangeFromCxfRequest(cxfExchange, camelExchange);
091                    
092                    // extract the javax.xml.ws header
093                    Map<String, Object> context = new HashMap<String, Object>();
094                    binding.extractJaxWsContext(cxfExchange, context);                 
095                    // send Camel exchange to the target processor
096                    if (LOG.isTraceEnabled()) {
097                        LOG.trace("Processing +++ START +++");
098                    }
099                    try {
100                        getProcessor().process(camelExchange);
101                    } catch (Exception e) {
102                        throw new Fault(e);
103                    }
104                    if (LOG.isTraceEnabled()) {
105                        LOG.trace("Processing +++ END +++");
106                    }
107                    checkFailure(camelExchange);
108                  
109                    // bind the Camel response into a CXF response
110                    if (camelExchange.getPattern().isOutCapable()) {
111                        binding.populateCxfResponseFromExchange(camelExchange, cxfExchange);
112                    }
113                    
114                    // check failure again as fault could be discovered by converter
115                    checkFailure(camelExchange);
116    
117                    // copy the headers javax.xml.ws header back
118                    binding.copyJaxWsContext(cxfExchange, context);
119                    // response should have been set in outMessage's content
120                    return null;
121                }
122    
123                private void checkFailure(org.apache.camel.Exchange camelExchange) throws Fault {
124                    if (camelExchange.isFailed()) {
125                        // either Fault or Exception
126                        Throwable t = (camelExchange.hasOut() && camelExchange.getOut().isFault()) 
127                            ? camelExchange.getOut().getBody(Throwable.class) : camelExchange.getException();
128                        // There is no exception and the Fault message is set to the out message
129                        if (t != null) {
130                            throw (t instanceof Fault) ? (Fault)t : new Fault(t);
131                        }
132                    }
133                                    
134                }
135                
136            });
137            server = svrBean.create();        
138        }   
139        
140        @Override
141        protected void doStart() throws Exception {
142            super.doStart();
143            server.start();
144        }
145    
146        @Override
147        protected void doStop() throws Exception {
148            server.stop();
149            super.doStop();
150        }
151        
152        public Server getServer() {
153            return server;
154        }
155        
156    }