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    import java.lang.reflect.Proxy;
020    
021    import javax.xml.namespace.QName;
022    
023    import org.apache.camel.CamelContext;
024    import org.apache.camel.component.cxf.spring.CxfEndpointBean;
025    import org.apache.camel.component.cxf.util.CxfEndpointUtils;
026    import org.apache.camel.spring.SpringCamelContext;
027    import org.apache.camel.util.ObjectHelper;
028    import org.apache.cxf.Bus;
029    import org.apache.cxf.common.classloader.ClassLoaderUtils;
030    import org.apache.cxf.configuration.spring.ConfigurerImpl;
031    import org.apache.cxf.endpoint.Client;
032    import org.apache.cxf.frontend.ClientFactoryBean;
033    import org.apache.cxf.frontend.ClientProxy;
034    import org.apache.cxf.frontend.ClientProxyFactoryBean;
035    import org.apache.cxf.frontend.ServerFactoryBean;
036    import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
037    import org.springframework.context.ConfigurableApplicationContext;
038    
039    /**
040     * Defines the <a href="http://camel.apache.org/cxf.html">CXF Endpoint</a>
041     *
042     * @version $Revision: 16003 $
043     */
044    public class CxfSpringEndpoint extends CxfEndpoint {
045    
046        private CxfEndpointBean bean;
047        private String beanId;
048        private ConfigurerImpl configurer;
049        private String serviceNamespace;
050        private String serviceLocalName;
051        private String endpointLocalName;
052        private String endpointNamespace;
053        
054        public CxfSpringEndpoint(CamelContext context, CxfEndpointBean bean) throws Exception {
055            super(bean.getAddress(), context);
056            init(bean);
057        }
058        
059        public CxfSpringEndpoint(CxfComponent component, CxfEndpointBean bean) throws Exception {
060            super(bean.getAddress(), component);
061            init(bean);
062        }
063        
064    
065        private void init(CxfEndpointBean bean) throws Exception {
066            this.bean = bean;        
067            // create configurer
068            configurer = new ConfigurerImpl(((SpringCamelContext)getCamelContext())
069                .getApplicationContext());
070        }
071    
072        
073        /**
074         * 
075         * A help to get the service class.  The serviceClass classname in URI 
076         * query takes precedence over the serviceClass in CxfEndpointBean.
077         */
078        private Class<?> getSEIClass() throws ClassNotFoundException {
079            
080            // get service class
081            Class<?> answer = null;
082            if (getServiceClass() != null) {
083                // classname is specified in URI which overrides the bean properties
084                answer = ClassLoaderUtils.loadClass(getServiceClass(), getClass());
085            } else {
086                answer = bean.getServiceClass();
087            }
088            return answer;
089        }
090        
091        protected Bus doGetBus() {
092            return bean.getBus();
093        }
094        
095        public CxfEndpointBean getBean() {
096            return bean;
097        }
098    
099        // Package private methods
100        // -------------------------------------------------------------------------
101    
102        /**
103         * Create a CXF Client
104         */
105        @Override
106        Client createClient() throws Exception {
107            
108            // get service class
109            Class<?> cls = getSEIClass();    
110            
111            if (getDataFormat().equals(DataFormat.POJO)) { 
112                ObjectHelper.notNull(cls, CxfConstants.SERVICE_CLASS);
113            }
114    
115            if (cls != null) {
116                // create client factory bean
117                ClientProxyFactoryBean factoryBean = createClientFactoryBean(cls);
118    
119                // configure client factory bean by CXF configurer
120                configure(factoryBean);
121    
122                // setup client factory bean
123                setupClientFactoryBean(factoryBean, cls);
124    
125                // fill in values that have not been filled.
126                QName serviceQName = null;
127                try {
128                    serviceQName = factoryBean.getServiceName();
129                } catch (IllegalStateException e) {
130                    // It throws IllegalStateException if serviceName has not been set.
131                }
132    
133                if (serviceQName == null && getServiceLocalName() != null) {
134                    factoryBean.setServiceName(new QName(getServiceNamespace(), getServiceLocalName()));
135                }
136                if (factoryBean.getEndpointName() == null && getEndpointLocalName() != null) {
137                    factoryBean.setEndpointName(new QName(getEndpointNamespace(), getEndpointLocalName()));
138                }
139    
140                return ((ClientProxy)Proxy.getInvocationHandler(factoryBean.create())).getClient();
141            } else {
142                ClientFactoryBean factoryBean = createClientFactoryBean();
143    
144                // configure client factory bean by CXF configurer
145                configure(factoryBean);
146                
147                // setup client factory bean
148                setupClientFactoryBean(factoryBean);
149                
150                // fill in values that have not been filled.
151                QName serviceQName = null;
152                try {
153                    serviceQName = factoryBean.getServiceName();
154                } catch (IllegalStateException e) {
155                    // It throws IllegalStateException if serviceName has not been set.
156                }
157                
158                if (serviceQName == null && getServiceLocalName() != null) {
159                    factoryBean.setServiceName(new QName(getServiceNamespace(), getServiceLocalName()));
160                }
161                if (factoryBean.getEndpointName() == null && getEndpointLocalName() != null) {
162                    factoryBean.setEndpointName(new QName(getEndpointNamespace(), getEndpointLocalName()));
163                }
164                
165                ObjectHelper.notNull(factoryBean.getEndpointName(), "Please provide endpoint/port name");
166                ObjectHelper.notNull(factoryBean.getServiceName(), "Please provide service name");
167                return (Client)factoryBean.create();
168            }
169        }
170    
171    
172        /**
173         * Create a service factory bean
174         */
175        @Override
176        ServerFactoryBean createServerFactoryBean() throws Exception  {
177            
178            // get service class
179            Class<?> cls = getSEIClass();                
180                    
181            // create server factory bean
182            // Shouldn't use CxfEndpointUtils.getServerFactoryBean(cls) as it is for
183            // CxfSoapComponent
184            ServerFactoryBean answer = null;
185    
186            if (cls == null) {
187                if (!getDataFormat().equals(DataFormat.POJO)) {
188                    answer = new ServerFactoryBean(new WSDLServiceFactoryBean());
189                } else {
190                    ObjectHelper.notNull(cls, CxfConstants.SERVICE_CLASS);
191                }
192            } else if (CxfEndpointUtils.hasWebServiceAnnotation(cls)) {
193                answer = new JaxWsServerFactoryBean();
194            } else {
195                answer = new ServerFactoryBean();
196            }
197    
198            // configure server factory bean by CXF configurer
199            configure(answer);
200            
201            // setup server factory bean
202            setupServerFactoryBean(answer, cls);
203    
204            // fill in values that have not been filled.
205            if (answer.getServiceName() == null && getServiceLocalName() != null) {
206                answer.setServiceName(new QName(getServiceNamespace(), getServiceLocalName()));
207            }
208            if (answer.getEndpointName() == null && getEndpointLocalName() != null) {
209                answer.setEndpointName(new QName(getEndpointNamespace(), getEndpointLocalName()));
210            }
211    
212            if (cls == null) {
213                ObjectHelper.notNull(answer.getEndpointName(), "Please provide endpoint/port name");
214                ObjectHelper.notNull(answer.getServiceName(), "Please provide service name");
215            }
216            return answer;
217        }
218    
219        void configure(Object beanInstance) {
220            // check the ApplicationContext states first , and call the refresh if necessary
221            if (((SpringCamelContext)getCamelContext()).getApplicationContext() instanceof ConfigurableApplicationContext) {
222                ConfigurableApplicationContext context = (ConfigurableApplicationContext)((SpringCamelContext)getCamelContext()).getApplicationContext();
223                if (!context.isActive()) {
224                    context.refresh();
225                }
226            }
227            configurer.configureBean(beanId, beanInstance);
228        }
229        
230        // Properties
231        // -------------------------------------------------------------------------
232        public String getBeanId() {
233            return beanId;
234        }
235        
236        // this property will be set by spring
237        public void setBeanId(String id) {        
238            this.beanId = id;
239        }
240        
241        public void setServiceNamespace(String serviceNamespace) {
242            this.serviceNamespace = serviceNamespace;
243        }
244    
245    
246        public String getServiceNamespace() {
247            return serviceNamespace;
248        }
249    
250    
251        public void setServiceLocalName(String serviceLocalName) {
252            this.serviceLocalName = serviceLocalName;
253        }
254    
255    
256        public String getServiceLocalName() {
257            return serviceLocalName;
258        }
259    
260        public String getEndpointLocalName() {
261            return endpointLocalName;
262        }
263    
264        public void setEndpointLocalName(String endpointLocalName) {
265            this.endpointLocalName = endpointLocalName;
266        }
267    
268    
269        public void setEndpointNamespace(String endpointNamespace) {
270            this.endpointNamespace = endpointNamespace;
271        }
272    
273    
274        public String getEndpointNamespace() {
275            return endpointNamespace;
276        }
277        
278        
279    }