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" description="an endpoint using CXF's JAX-WS frontend"
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 * Returns the object implementing the endpoint's functionality. It is
095 * returned as a generic Java <code>Object</code> that can be cast to
096 * the proper type.
097 *
098 * @return the pojo
099 */
100 public Object getPojo() {
101 return pojo;
102 }
103
104 /**
105 * Specifies the object implementing the endpoint's functionality. This
106 * object should use the JAX-WS annotations.
107 *
108 * @param pojo a JAX-WS annotated object
109
110 * @org.apache.xbean.Property description="a bean configuring the JAX-WS annotated implementation for the endpoint"
111 */
112 public void setPojo(Object pojo) {
113 this.pojo = pojo;
114 }
115
116 /**
117 * Returns the list of interceptors used to process fault messages being
118 * sent back to the consumer.
119 *
120 * @return a list of <code>Interceptor</code> objects
121 * */
122 public List<Interceptor> getOutFaultInterceptors() {
123 return outFault;
124 }
125
126 /**
127 * Returns the list of interceptors used to process fault messages being
128 * recieved by the endpoint.
129 *
130 * @return a list of <code>Interceptor</code> objects
131 * */
132 public List<Interceptor> getInFaultInterceptors() {
133 return inFault;
134 }
135
136 /**
137 * Returns the list of interceptors used to process messages being
138 * recieved by the endpoint.
139 *
140 * @return a list of <code>Interceptor</code> objects
141 * */
142 public List<Interceptor> getInInterceptors() {
143 return in;
144 }
145
146 /**
147 * Returns the list of interceptors used to process responses being
148 * sent back to the consumer.
149 *
150 * @return a list of <code>Interceptor</code> objects
151 * */
152 public List<Interceptor> getOutInterceptors() {
153 return out;
154 }
155
156 /**
157 * Specifies a list of interceptors used to process requests recieved
158 * by the endpoint.
159 *
160 * @param interceptors a list of <code>Interceptor</code> objects
161 * @org.apache.xbean.Property description="a list of beans configuring interceptors that process incoming requests"
162 * */
163 public void setInInterceptors(List<Interceptor> interceptors) {
164 in = interceptors;
165 }
166
167 /**
168 * Specifies a list of interceptors used to process faults recieved by
169 * the endpoint.
170 *
171 * @param interceptors a list of <code>Interceptor</code> objects
172 * @org.apache.xbean.Property description="a list of beans configuring interceptors that process incoming faults"
173 * */
174 public void setInFaultInterceptors(List<Interceptor> interceptors) {
175 inFault = interceptors;
176 }
177
178 /**
179 * Specifies a list of interceptors used to process responses sent by
180 * the endpoint.
181 *
182 * @param interceptors a list of <code>Interceptor</code> objects
183 * @org.apache.xbean.Property description="a list of beans configuring interceptors that process response messages"
184 * */
185 public void setOutInterceptors(List<Interceptor> interceptors) {
186 out = interceptors;
187 }
188
189 /**
190 * Specifies a list of interceptors used to process faults sent by
191 * the endpoint.
192 *
193 * @param interceptors a list of <code>Interceptor</code> objects
194 * @org.apache.xbean.Property description="a list of beans configuring interceptors that process
195 * fault messages being returned to the consumer"
196 * */
197 public void setOutFaultInterceptors(List<Interceptor> interceptors) {
198 outFault = interceptors;
199 }
200
201 public Map getProperties() {
202 return properties;
203 }
204
205 public void setProperties(Map properties) {
206 this.properties = properties;
207 }
208
209
210 /*
211 * (non-Javadoc)
212 *
213 * @see org.apache.servicemix.common.Endpoint#validate()
214 */
215 @Override
216 public void validate() throws DeploymentException {
217 if (getPojo() == null) {
218 throw new DeploymentException("pojo must be set");
219 }
220 JaxWsServiceFactoryBean serviceFactory = new JaxWsServiceFactoryBean();
221 serviceFactory.setPopulateFromClass(true);
222 endpoint = new EndpointImpl(getBus(), getPojo(),
223 new JaxWsServerFactoryBean(serviceFactory));
224 if (isUseJBIWrapper()) {
225 endpoint.setBindingUri(org.apache.cxf.binding.jbi.JBIConstants.NS_JBI_BINDING);
226 }
227 endpoint.setInInterceptors(getInInterceptors());
228 endpoint.setInFaultInterceptors(getInFaultInterceptors());
229 endpoint.setOutInterceptors(getOutInterceptors());
230 endpoint.setOutFaultInterceptors(getOutFaultInterceptors());
231 if (isMtomEnabled()) {
232 endpoint.getInInterceptors().add(new AttachmentInInterceptor());
233 endpoint.getOutInterceptors().add(new AttachmentOutInterceptor());
234 }
235 if (isSchemaValidationEnabled()) {
236 if (endpoint.getProperties() == null) {
237 endpoint.setProperties(new HashMap<String, Object>());
238 }
239 endpoint.getProperties().put(org.apache.cxf.message.Message.SCHEMA_VALIDATION_ENABLED, true);
240 }
241 JaxWsImplementorInfo implInfo = new JaxWsImplementorInfo(getPojo()
242 .getClass());
243 setService(implInfo.getServiceName());
244 setInterfaceName(implInfo.getInterfaceName());
245 setEndpoint(implInfo.getEndpointName().getLocalPart());
246 super.validate();
247 }
248
249 /*
250 * (non-Javadoc)
251 *
252 * @see org.apache.servicemix.common.endpoints.ProviderEndpoint#process(javax.jbi.messaging.MessageExchange)
253 */
254 @Override
255 public void process(MessageExchange exchange) throws Exception {
256
257 QName opeName = exchange.getOperation();
258 EndpointInfo ei = endpoint.getServer().getEndpoint().getEndpointInfo();
259 if (opeName == null) {
260 // if interface only have one operation, may not specify the opeName in MessageExchange
261 if (ei.getBinding().getOperations().size() == 1) {
262 opeName = ei.getBinding().getOperations().iterator().next().getName();
263 exchange.setOperation(opeName);
264 } else {
265 throw new Fault(
266 new Exception("Operation not bound on this MessageExchange"));
267
268 }
269 }
270
271 JBITransportFactory jbiTransportFactory = (JBITransportFactory) getBus()
272 .getExtension(ConduitInitiatorManager.class)
273 .getConduitInitiator(CxfSeComponent.JBI_TRANSPORT_ID);
274
275 QName serviceName = exchange.getService();
276 if (serviceName == null) {
277 serviceName = getService();
278 exchange.setService(serviceName);
279 }
280 QName interfaceName = exchange.getInterfaceName();
281 if (interfaceName == null) {
282 interfaceName = getInterfaceName();
283 exchange.setInterfaceName(interfaceName);
284 }
285 JBIDestination jbiDestination = jbiTransportFactory
286 .getDestination(serviceName.toString()
287 + interfaceName.toString());
288 DeliveryChannel dc = getContext().getDeliveryChannel();
289 jbiTransportFactory.setDeliveryChannel(dc);
290
291 jbiDestination.setDeliveryChannel(dc);
292 if (exchange.getStatus() == ExchangeStatus.ACTIVE) {
293 jbiDestination.getJBIDispatcherUtil().dispatch(exchange);
294 }
295
296 }
297
298 /*
299 * (non-Javadoc)
300 *
301 * @see org.apache.servicemix.common.endpoints.ProviderEndpoint#start()
302 */
303 @Override
304 public void start() throws Exception {
305 super.start();
306 address = "jbi://" + ID_GENERATOR.generateSanitizedId();
307 try {
308 endpoint.publish(address);
309 } catch (Exception e) {
310 e.printStackTrace();
311 }
312
313 setService(endpoint.getServer().getEndpoint().getService().getName());
314 setEndpoint(endpoint.getServer().getEndpoint().getEndpointInfo()
315 .getName().getLocalPart());
316 try {
317 definition = new ServiceWSDLBuilder(getBus(), endpoint.getServer()
318 .getEndpoint().getService().getServiceInfos().iterator()
319 .next()).build();
320 description = WSDLFactory.newInstance().newWSDLWriter().getDocument(definition);
321 } catch (WSDLException e) {
322 throw new DeploymentException(e);
323 }
324 ReflectionUtils.doWithFields(getPojo().getClass(), new FieldCallback() {
325 public void doWith(Field field) throws IllegalArgumentException,
326 IllegalAccessException {
327 if (field.getAnnotation(WebServiceRef.class) != null) {
328 ServiceImpl s = new ServiceImpl(getBus(), null, null, field
329 .getType());
330 s.addPort(new QName("port"),
331 JBITransportFactory.TRANSPORT_ID, "jbi://"
332 + ID_GENERATOR.generateSanitizedId());
333 Object o = s.getPort(new QName("port"), field.getType());
334 field.setAccessible(true);
335 field.set(getPojo(), o);
336 }
337 }
338 });
339 ReflectionUtils.callLifecycleMethod(getPojo(), PostConstruct.class);
340 injectPojo();
341 }
342
343
344 /*
345 * (non-Javadoc)
346 *
347 * @see org.apache.servicemix.common.endpoints.ProviderEndpoint#stop()
348 */
349 @Override
350 public void stop() throws Exception {
351 endpoint.stop();
352 ReflectionUtils.callLifecycleMethod(getPojo(), PreDestroy.class);
353 JBIDispatcherUtil.clean();
354 JBITransportFactory jbiTransportFactory = (JBITransportFactory) getBus()
355 .getExtension(ConduitInitiatorManager.class)
356 .getConduitInitiator(CxfSeComponent.JBI_TRANSPORT_ID);
357 jbiTransportFactory.setDeliveryChannel(null);
358 jbiTransportFactory.removeDestination(getService().toString()
359 + getInterfaceName().toString());
360 super.stop();
361 }
362
363 protected Bus getBus() {
364 return ((CxfSeComponent) getServiceUnit().getComponent()).getBus();
365 }
366
367
368 @PostConstruct
369 protected void injectPojo() {
370 try {
371 ComponentContext context = getContext();
372 Method mth = pojo.getClass().getMethod("setContext", new Class[] {ComponentContext.class });
373 if (mth != null) {
374 mth.invoke(pojo, new Object[] {context});
375 }
376 } catch (Exception e) {
377 logger.debug("Unable to inject ComponentContext: " + e.getMessage());
378 }
379
380 }
381
382 /**
383 * Specifies if the endpoint can process messages with binary data.
384 *
385 * @param mtomEnabled a <code>boolean</code>
386 * @org.apache.xbean.Property description="Specifies if the service can consume MTOM formatted binary data.
387 * The default is <code>false</code>."
388 * */
389 public void setMtomEnabled(boolean mtomEnabled) {
390 this.mtomEnabled = mtomEnabled;
391 }
392
393 public boolean isMtomEnabled() {
394 return mtomEnabled;
395 }
396
397 public boolean isSchemaValidationEnabled() {
398 return schemaValidationEnabled;
399 }
400
401 public void setSchemaValidationEnabled(boolean schemaValidationEnabled) {
402 this.schemaValidationEnabled = schemaValidationEnabled;
403 }
404
405 /**
406 * Specifies if the endpoint expects messages that are encased in the
407 * JBI wrapper used for SOAP messages.
408 *
409 * @param mtomEnabled a <code>boolean</code>
410 * @org.apache.xbean.Property description="Specifies if the endpoint expects to receive the JBI wrapper in
411 * the message received from the NMR. The default is <code>true</code>."
412 * */
413 public void setUseJBIWrapper(boolean useJBIWrapper) {
414 this.useJBIWrapper = useJBIWrapper;
415 }
416
417 public boolean isUseJBIWrapper() {
418 return useJBIWrapper;
419 }
420 }