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.cxfse;
018    
019    import java.lang.reflect.Field;
020    import java.lang.reflect.Method;
021    import java.util.HashMap;
022    import java.util.List;
023    import java.util.Map;
024    import java.util.concurrent.CopyOnWriteArrayList;
025    
026    import javax.annotation.PostConstruct;
027    import javax.annotation.PreDestroy;
028    import javax.jbi.component.ComponentContext;
029    import javax.jbi.management.DeploymentException;
030    import javax.jbi.messaging.DeliveryChannel;
031    import javax.jbi.messaging.ExchangeStatus;
032    import javax.jbi.messaging.MessageExchange;
033    import javax.wsdl.WSDLException;
034    import javax.wsdl.factory.WSDLFactory;
035    import javax.xml.namespace.QName;
036    import javax.xml.ws.WebServiceRef;
037    
038    import org.apache.cxf.Bus;
039    import org.apache.cxf.interceptor.Fault;
040    import org.apache.cxf.interceptor.Interceptor;
041    import org.apache.cxf.interceptor.InterceptorProvider;
042    import org.apache.cxf.jaxws.EndpointImpl;
043    import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
044    import org.apache.cxf.jaxws.ServiceImpl;
045    import org.apache.cxf.jaxws.support.JaxWsImplementorInfo;
046    import org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean;
047    import org.apache.cxf.service.model.EndpointInfo;
048    import org.apache.cxf.transport.ConduitInitiatorManager;
049    import org.apache.cxf.transport.jbi.JBIDestination;
050    import org.apache.cxf.transport.jbi.JBIDispatcherUtil;
051    import org.apache.cxf.transport.jbi.JBITransportFactory;
052    import org.apache.cxf.wsdl11.ServiceWSDLBuilder;
053    import org.apache.servicemix.common.endpoints.ProviderEndpoint;
054    import org.apache.servicemix.cxfse.interceptors.AttachmentInInterceptor;
055    import org.apache.servicemix.cxfse.interceptors.AttachmentOutInterceptor;
056    import org.apache.servicemix.cxfse.support.ReflectionUtils;
057    import org.apache.servicemix.id.IdGenerator;
058    import org.springframework.util.ReflectionUtils.FieldCallback;
059    
060    /**
061     * 
062     * @author gnodet
063     * @org.apache.xbean.XBean element="endpoint"
064     */
065    public class CxfSeEndpoint extends ProviderEndpoint implements
066            InterceptorProvider {
067    
068        private static final IdGenerator ID_GENERATOR = new IdGenerator();
069    
070        private Object pojo;
071    
072        private EndpointImpl endpoint;
073    
074        private String address;
075    
076        private List<Interceptor> in = new CopyOnWriteArrayList<Interceptor>();
077    
078        private List<Interceptor> out = new CopyOnWriteArrayList<Interceptor>();
079    
080        private List<Interceptor> outFault = new CopyOnWriteArrayList<Interceptor>();
081    
082        private List<Interceptor> inFault = new CopyOnWriteArrayList<Interceptor>();
083        
084        private Map properties;
085        
086        private boolean mtomEnabled;
087    
088        private boolean schemaValidationEnabled;
089    
090        private boolean useJBIWrapper = true;
091        
092        
093        /**
094         * @return the pojo
095         */
096        public Object getPojo() {
097            return pojo;
098        }
099    
100        /**
101         * @param pojo
102         *            the pojo to set
103         */
104        public void setPojo(Object pojo) {
105            this.pojo = pojo;
106        }
107    
108        public List<Interceptor> getOutFaultInterceptors() {
109            return outFault;
110        }
111    
112        public List<Interceptor> getInFaultInterceptors() {
113            return inFault;
114        }
115    
116        public List<Interceptor> getInInterceptors() {
117            return in;
118        }
119    
120        public List<Interceptor> getOutInterceptors() {
121            return out;
122        }
123    
124        public void setInInterceptors(List<Interceptor> interceptors) {
125            in = interceptors;
126        }
127    
128        public void setInFaultInterceptors(List<Interceptor> interceptors) {
129            inFault = interceptors;
130        }
131    
132        public void setOutInterceptors(List<Interceptor> interceptors) {
133            out = interceptors;
134        }
135    
136        public void setOutFaultInterceptors(List<Interceptor> interceptors) {
137            outFault = interceptors;
138        }
139    
140        public Map getProperties() {
141            return properties;
142        }
143    
144        public void setProperties(Map properties) {
145            this.properties = properties;
146        }
147    
148    
149        /*
150         * (non-Javadoc)
151         * 
152         * @see org.apache.servicemix.common.Endpoint#validate()
153         */
154        @Override
155        public void validate() throws DeploymentException {
156            if (getPojo() == null) {
157                throw new DeploymentException("pojo must be set");
158            }
159            JaxWsServiceFactoryBean serviceFactory = new JaxWsServiceFactoryBean();
160            serviceFactory.setPopulateFromClass(true);
161            endpoint = new EndpointImpl(getBus(), getPojo(),
162                    new JaxWsServerFactoryBean(serviceFactory));
163            if (isUseJBIWrapper()) {
164                endpoint.setBindingUri(org.apache.cxf.binding.jbi.JBIConstants.NS_JBI_BINDING);
165            }
166            endpoint.setInInterceptors(getInInterceptors());
167            endpoint.setInFaultInterceptors(getInFaultInterceptors());
168            endpoint.setOutInterceptors(getOutInterceptors());
169            endpoint.setOutFaultInterceptors(getOutFaultInterceptors());
170            if (isMtomEnabled()) {
171                endpoint.getInInterceptors().add(new AttachmentInInterceptor());
172                endpoint.getOutInterceptors().add(new AttachmentOutInterceptor());
173            }
174            if (isSchemaValidationEnabled()) {
175                if (endpoint.getProperties() == null) {
176                    endpoint.setProperties(new HashMap<String, Object>());
177                }
178                endpoint.getProperties().put(org.apache.cxf.message.Message.SCHEMA_VALIDATION_ENABLED, true);
179            }
180            JaxWsImplementorInfo implInfo = new JaxWsImplementorInfo(getPojo()
181                    .getClass());
182            setService(implInfo.getServiceName());
183            setInterfaceName(implInfo.getInterfaceName());
184            setEndpoint(implInfo.getEndpointName().getLocalPart());
185            super.validate();
186        }
187    
188        /*
189         * (non-Javadoc)
190         * 
191         * @see org.apache.servicemix.common.endpoints.ProviderEndpoint#process(javax.jbi.messaging.MessageExchange)
192         */
193        @Override
194        public void process(MessageExchange exchange) throws Exception {
195            
196            QName opeName = exchange.getOperation();
197            EndpointInfo ei = endpoint.getServer().getEndpoint().getEndpointInfo();
198            if (opeName == null) {
199                // if interface only have one operation, may not specify the opeName in MessageExchange
200                if (ei.getBinding().getOperations().size() == 1) {
201                    opeName = ei.getBinding().getOperations().iterator().next().getName();
202                    exchange.setOperation(opeName);
203                } else {
204                    throw new Fault(
205                                new Exception("Operation not bound on this MessageExchange"));
206                    
207                }
208            } 
209            
210            JBITransportFactory jbiTransportFactory = (JBITransportFactory) getBus()
211                    .getExtension(ConduitInitiatorManager.class)
212                    .getConduitInitiator(CxfSeComponent.JBI_TRANSPORT_ID);
213            
214            QName serviceName = exchange.getService();
215            if (serviceName == null) {
216                serviceName = getService();
217                exchange.setService(serviceName);
218            }
219            QName interfaceName = exchange.getInterfaceName();
220            if (interfaceName == null) {
221                interfaceName = getInterfaceName();
222                exchange.setInterfaceName(interfaceName);
223            }
224            JBIDestination jbiDestination = jbiTransportFactory
225                    .getDestination(serviceName.toString()
226                            + interfaceName.toString());
227            DeliveryChannel dc = getContext().getDeliveryChannel();
228            jbiTransportFactory.setDeliveryChannel(dc);
229            
230            jbiDestination.setDeliveryChannel(dc);
231            if (exchange.getStatus() == ExchangeStatus.ACTIVE) {
232                jbiDestination.getJBIDispatcherUtil().dispatch(exchange);
233            }
234            
235        }
236    
237        /*
238         * (non-Javadoc)
239         * 
240         * @see org.apache.servicemix.common.endpoints.ProviderEndpoint#start()
241         */
242        @Override
243        public void start() throws Exception {
244            super.start();
245            address = "jbi://" + ID_GENERATOR.generateSanitizedId();
246            try {
247                endpoint.publish(address);
248            } catch (Exception e) {
249                e.printStackTrace();
250            }
251            
252            setService(endpoint.getServer().getEndpoint().getService().getName());
253            setEndpoint(endpoint.getServer().getEndpoint().getEndpointInfo()
254                    .getName().getLocalPart());
255            try {
256                definition = new ServiceWSDLBuilder(getBus(), endpoint.getServer()
257                        .getEndpoint().getService().getServiceInfos().iterator()
258                        .next()).build();
259                description = WSDLFactory.newInstance().newWSDLWriter().getDocument(definition);
260            } catch (WSDLException e) {
261                throw new DeploymentException(e);
262            }
263            ReflectionUtils.doWithFields(getPojo().getClass(), new FieldCallback() {
264                public void doWith(Field field) throws IllegalArgumentException,
265                        IllegalAccessException {
266                    if (field.getAnnotation(WebServiceRef.class) != null) {
267                        ServiceImpl s = new ServiceImpl(getBus(), null, null, field
268                                .getType());
269                        s.addPort(new QName("port"),
270                                JBITransportFactory.TRANSPORT_ID, "jbi://"
271                                        + ID_GENERATOR.generateSanitizedId());
272                        Object o = s.getPort(new QName("port"), field.getType());
273                        field.setAccessible(true);
274                        field.set(getPojo(), o);
275                    }
276                }
277            });
278            ReflectionUtils.callLifecycleMethod(getPojo(), PostConstruct.class);
279            injectPojo();
280        }
281    
282    
283        /*
284         * (non-Javadoc)
285         * 
286         * @see org.apache.servicemix.common.endpoints.ProviderEndpoint#stop()
287         */
288        @Override
289        public void stop() throws Exception {
290            endpoint.stop();
291            ReflectionUtils.callLifecycleMethod(getPojo(), PreDestroy.class);
292            JBIDispatcherUtil.clean();
293            JBITransportFactory jbiTransportFactory = (JBITransportFactory) getBus()
294                .getExtension(ConduitInitiatorManager.class)
295                .getConduitInitiator(CxfSeComponent.JBI_TRANSPORT_ID);
296            jbiTransportFactory.removeDestination(getService().toString()
297                        + getInterfaceName().toString());
298            super.stop();
299        }
300    
301        protected Bus getBus() {
302            return ((CxfSeComponent) getServiceUnit().getComponent()).getBus();
303        }
304    
305        
306        @PostConstruct
307        protected void injectPojo() {
308            try {
309                ComponentContext context = getContext();
310                Method mth = pojo.getClass().getMethod("setContext", new Class[] {ComponentContext.class });
311                if (mth != null) {
312                    mth.invoke(pojo, new Object[] {context});
313                }
314            } catch (Exception e) {
315                logger.debug("Unable to inject ComponentContext: " + e.getMessage());
316            }
317            
318        }
319    
320        public void setMtomEnabled(boolean mtomEnabled) {
321            this.mtomEnabled = mtomEnabled;
322        }
323    
324        public boolean isMtomEnabled() {
325            return mtomEnabled;
326        }
327    
328        public boolean isSchemaValidationEnabled() {
329            return schemaValidationEnabled;
330        }
331    
332        public void setSchemaValidationEnabled(boolean schemaValidationEnabled) {
333            this.schemaValidationEnabled = schemaValidationEnabled;
334        }
335    
336        public void setUseJBIWrapper(boolean useJBIWrapper) {
337            this.useJBIWrapper = useJBIWrapper;
338        }
339    
340        public boolean isUseJBIWrapper() {
341            return useJBIWrapper;
342        }
343    }