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.Method;
020    import java.util.List;
021    
022    import javax.jbi.component.ComponentContext;
023    import javax.jbi.messaging.DeliveryChannel;
024    import javax.naming.InitialContext;
025    import javax.xml.namespace.QName;
026    
027    import org.apache.cxf.Bus;
028    import org.apache.cxf.BusFactory;
029    import org.apache.cxf.bus.spring.SpringBusFactory;
030    import org.apache.cxf.frontend.ClientProxy;
031    import org.apache.cxf.interceptor.Interceptor;
032    import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
033    import org.apache.cxf.transport.ConduitInitiatorManager;
034    import org.apache.cxf.transport.jbi.JBITransportFactory;
035    import org.apache.servicemix.cxfse.interceptors.AttachmentInInterceptor;
036    import org.apache.servicemix.cxfse.interceptors.AttachmentOutInterceptor;
037    import org.apache.servicemix.id.IdGenerator;
038    import org.apache.servicemix.jbi.api.ClientFactory;
039    import org.apache.servicemix.jbi.api.Container;
040    import org.apache.servicemix.jbi.api.ServiceMixClient;
041    
042    import org.springframework.beans.factory.DisposableBean;
043    import org.springframework.beans.factory.FactoryBean;
044    import org.springframework.beans.factory.InitializingBean;
045    
046    /**
047     * 
048     * @author ffang
049     * @org.apache.xbean.XBean element="proxy" description="A CXF proxy"
050     * 
051     */
052    public class CxfSeProxyFactoryBean implements FactoryBean, InitializingBean,
053            DisposableBean {
054        
055        private static final String[] CXF_CONFIG = new String[] {
056            "META-INF/cxf/cxf.xml",
057            "META-INF/cxf/cxf-extension-soap.xml",
058            "META-INF/cxf/transport/jbi/cxf-transport-jbi.xml",
059            "META-INF/cxf/binding/jbi/cxf-binding-jbi.xml"
060        };
061    
062        private String name = ClientFactory.DEFAULT_JNDI_NAME;
063    
064        private Container container;
065    
066        private ClientFactory factory;
067    
068        private ComponentContext context;
069    
070        private Class type;
071    
072        private Object proxy;
073    
074        private QName service;
075    
076        private QName interfaceName;
077    
078        private String endpoint;
079    
080        private boolean propagateSecuritySubject;
081    
082        private ServiceMixClient client;
083        
084        private boolean useJBIWrapper = true;
085        
086        private boolean useSOAPEnvelope = true;
087    
088        private boolean mtomEnabled;
089        
090        private Object componentRegistry;
091    
092        public Object getObject() throws Exception {
093            if (proxy == null) {
094                proxy = createProxy();
095            }
096            return proxy;
097        }
098    
099        private Object createProxy() throws Exception {
100            JaxWsProxyFactoryBean cf = new JaxWsProxyFactoryBean();
101            cf.setServiceName(getService());
102            if (getEndpoint() != null) {
103                cf.setEndpointName(new QName(getService().getNamespaceURI(), getEndpoint()));
104            }
105            cf.setServiceClass(type);
106            cf.setAddress("jbi://" + new IdGenerator().generateSanitizedId());
107            if (isUseJBIWrapper()) {
108                cf.setBindingId(org.apache.cxf.binding.jbi.JBIConstants.NS_JBI_BINDING);
109            }
110            ComponentContext internalContext = getInternalContext();
111           
112            Bus bus = new SpringBusFactory().createBus(CXF_CONFIG);;
113            JBITransportFactory jbiTransportFactory = (JBITransportFactory) bus
114                    .getExtension(ConduitInitiatorManager.class)
115                    .getConduitInitiator(JBITransportFactory.TRANSPORT_ID);
116            if (internalContext != null) { 
117                DeliveryChannel dc = internalContext.getDeliveryChannel();
118                if (dc != null) {
119                    jbiTransportFactory.setDeliveryChannel(dc);
120                }
121            }
122            cf.setBus(bus);
123            Object proxy = cf.create();
124            if (!isUseJBIWrapper() && !isUseSOAPEnvelope()) {
125                    removeInterceptor(ClientProxy.getClient(proxy).getEndpoint().getBinding().getInInterceptors(), 
126                                    "ReadHeadersInterceptor");
127                    removeInterceptor(ClientProxy.getClient(proxy).getEndpoint().getBinding().getInFaultInterceptors(), 
128                            "ReadHeadersInterceptor");
129                    removeInterceptor(ClientProxy.getClient(proxy).getEndpoint().getBinding().getOutInterceptors(), 
130                                    "SoapOutInterceptor");
131                    removeInterceptor(ClientProxy.getClient(proxy).getEndpoint().getBinding().getOutFaultInterceptors(), 
132                                    "SoapOutInterceptor");
133                    removeInterceptor(ClientProxy.getClient(proxy).getEndpoint().getBinding().getOutInterceptors(), 
134                            "StaxOutInterceptor");
135            }
136            if (isMtomEnabled()) {
137                ClientProxy.getClient(proxy).getEndpoint()
138                    .getBinding().getInInterceptors().add(new AttachmentInInterceptor());
139                ClientProxy.getClient(proxy).getEndpoint()
140                    .getBinding().getOutInterceptors().add(new AttachmentOutInterceptor());
141            }
142            return proxy;
143        }
144    
145        private void removeInterceptor(List<Interceptor> interceptors, String whichInterceptor) {
146                    for (Interceptor interceptor : interceptors) {
147                            if (interceptor.getClass().getName().endsWith(whichInterceptor)) {
148                                    interceptors.remove(interceptor);
149                            }
150                    }
151            }
152        
153        public Class getObjectType() {
154            return type;
155        }
156    
157        public boolean isSingleton() {
158            return true;
159        }
160    
161        protected ComponentContext getInternalContext() throws Exception {
162            if (CxfSeComponent.getComponentRegistry() != null) {
163                //in osgi container, use ComponentRegistry from CxfSeComponent
164                Object componentRegistry = CxfSeComponent.getComponentRegistry();
165                //use reflection to avoid nmr project dependency
166                Method mth = componentRegistry.getClass().getMethod("createComponentContext");
167                if (mth != null) {
168                    context = (ComponentContext) mth.invoke(componentRegistry);
169                }
170            } else if (getComponentRegistry() != null) {
171                //in osgi container, use ComponentRegistry from Proxy directly, 
172                //this won't depend on the CxfSeComponent Bundle start first
173                Object componentRegistry = getComponentRegistry();
174                //use reflection to avoid nmr project dependency
175                Method mth = componentRegistry.getClass().getMethod("createComponentContext");
176                if (mth != null) {
177                    context = (ComponentContext) mth.invoke(componentRegistry);
178                }
179            }
180            
181            if (context == null) {
182                if (factory == null) {
183                    if (container != null) {
184                        factory = container.getClientFactory();
185                    } else {
186                        factory = (ClientFactory) new InitialContext().lookup(name);
187                    }
188                }
189                client = factory.createClient();
190                context = client.getContext();
191            }
192            return context;
193        }
194    
195        public Class getType() {
196            return type;
197        }
198    
199        public void setType(Class type) {
200            this.type = type;
201        }
202    
203        public String getEndpoint() {
204            return endpoint;
205        }
206    
207        public void setEndpoint(String endpointName) {
208            this.endpoint = endpointName;
209        }
210    
211        public QName getInterfaceName() {
212            return interfaceName;
213        }
214    
215        public void setInterfaceName(QName interfaceName) {
216            this.interfaceName = interfaceName;
217        }
218    
219        public QName getService() {
220            return service;
221        }
222    
223        public void setService(QName service) {
224            this.service = service;
225        }
226    
227        /**
228         * @return the context
229         */
230        public ComponentContext getContext() {
231            return context;
232        }
233    
234        /**
235         * @param context
236         *            the context to set
237         */
238        public void setContext(ComponentContext context) {
239            this.context = context;
240        }
241    
242        /**
243         * @return the container
244         */
245        public Container getContainer() {
246            return container;
247        }
248    
249        /**
250         * @param container
251         *            the container to set
252         */
253        public void setContainer(Container container) {
254            this.container = container;
255        }
256    
257        /**
258         * @return the factory
259         */
260        public ClientFactory getFactory() {
261            return factory;
262        }
263    
264        /**
265         * @param factory
266         *            the factory to set
267         */
268        public void setFactory(ClientFactory factory) {
269            this.factory = factory;
270        }
271    
272        /**
273         * @return the name
274         */
275        public String getName() {
276            return name;
277        }
278    
279        /**
280         * @param name
281         *            the name to set
282         */
283        public void setName(String name) {
284            this.name = name;
285        }
286    
287        /**
288         * @return the propagateSecuritySubject
289         */
290        public boolean isPropagateSecuritySubject() {
291            return propagateSecuritySubject;
292        }
293    
294        /**
295         * @param propagateSecuritySubject
296         *            the propagateSecuritySubject to set
297         */
298        public void setPropagateSecuritySubject(boolean propagateSecuritySubject) {
299            this.propagateSecuritySubject = propagateSecuritySubject;
300        }
301    
302        public void afterPropertiesSet() throws Exception {
303            if (type == null) {
304                throw new IllegalArgumentException("type must be set");
305            }
306        }
307    
308        public void destroy() throws Exception {
309            if (client != null) {
310                client.close();
311                client = null;
312            }
313        }
314    
315        /**
316         * Specifies if the endpoint expects messages that are encased in the 
317         * JBI wrapper used for SOAP messages. Ignore the value of useSOAPEnvelope 
318         * if useJBIWrapper is true
319         *
320         * @org.apache.xbean.Property description="Specifies if the endpoint expects to receive the JBI wrapper in the message received from the NMR. The  default is <code>true</code>.
321         *                  Ignore the value of useSOAPEnvelope if useJBIWrapper is true"
322         * */
323        public void setUseJBIWrapper(boolean useJBIWrapper) {
324            this.useJBIWrapper = useJBIWrapper;
325        }
326    
327        public boolean isUseJBIWrapper() {
328            return useJBIWrapper;
329        }
330        
331        /**
332         * Specifies if the endpoint expects soap messages when useJBIWrapper is false, 
333         * if useJBIWrapper is true then ignore useSOAPEnvelope
334         *
335         * @org.apache.xbean.Property description="Specifies if the endpoint expects soap messages when useJBIWrapper is false, 
336         *                          if useJBIWrapper is true then ignore useSOAPEnvelope. The  default is <code>true</code>.
337         * */
338            public void setUseSOAPEnvelope(boolean useSOAPEnvelope) {
339                    this.useSOAPEnvelope = useSOAPEnvelope;
340            }
341    
342            public boolean isUseSOAPEnvelope() {
343                    return useSOAPEnvelope;
344            }
345    
346        public void setMtomEnabled(boolean mtomEnabled) {
347            this.mtomEnabled = mtomEnabled;
348        }
349    
350        public boolean isMtomEnabled() {
351            return mtomEnabled;
352        }
353    
354        public void setComponentRegistry(Object componentRegistry) {
355            this.componentRegistry = componentRegistry;
356        }
357    
358        public Object getComponentRegistry() {
359            return componentRegistry;
360        }
361    
362    }