001: /*
002: * $Id: CxfMessageReceiver.java 11405 2008-03-18 00:13:00Z dirk.olmes $
003: * --------------------------------------------------------------------------------------
004: * Copyright (c) MuleSource, Inc. All rights reserved. http://www.mulesource.com
005: *
006: * The software in this package is published under the terms of the CPAL v1.0
007: * license, a copy of which has been included with this distribution in the
008: * LICENSE.txt file.
009: */
010:
011: package org.mule.transport.cxf;
012:
013: import org.mule.api.MuleException;
014: import org.mule.api.component.JavaComponent;
015: import org.mule.api.endpoint.InboundEndpoint;
016: import org.mule.api.lifecycle.Callable;
017: import org.mule.api.lifecycle.CreateException;
018: import org.mule.api.lifecycle.Disposable;
019: import org.mule.api.lifecycle.Initialisable;
020: import org.mule.api.lifecycle.InitialisationException;
021: import org.mule.api.service.Service;
022: import org.mule.api.service.ServiceAware;
023: import org.mule.api.transport.Connector;
024: import org.mule.transport.AbstractMessageReceiver;
025: import org.mule.transport.cxf.i18n.CxfMessages;
026: import org.mule.transport.cxf.support.MuleHeadersInInterceptor;
027: import org.mule.transport.cxf.support.ProviderService;
028: import org.mule.util.ClassUtils;
029: import org.mule.util.StringUtils;
030:
031: import java.util.ArrayList;
032: import java.util.List;
033: import java.util.Map;
034:
035: import javax.xml.namespace.QName;
036:
037: import org.apache.commons.lang.BooleanUtils;
038: import org.apache.cxf.Bus;
039: import org.apache.cxf.aegis.databinding.AegisDatabinding;
040: import org.apache.cxf.common.classloader.ClassLoaderUtils;
041: import org.apache.cxf.configuration.Configurer;
042: import org.apache.cxf.databinding.DataBinding;
043: import org.apache.cxf.endpoint.Server;
044: import org.apache.cxf.feature.AbstractFeature;
045: import org.apache.cxf.frontend.ServerFactoryBean;
046: import org.apache.cxf.interceptor.Interceptor;
047: import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
048: import org.apache.cxf.service.factory.AbstractServiceConfiguration;
049: import org.apache.cxf.service.factory.ReflectionServiceFactoryBean;
050:
051: /**
052: * Create a CXF service. All messages for the service will be sent to the Mule bus a
053: * la the MuleInvoker.
054: */
055: public class CxfMessageReceiver extends AbstractMessageReceiver {
056:
057: protected CxfConnector connector;
058: private Server server;
059: private boolean bridge;
060:
061: public CxfMessageReceiver(Connector Connector, Service service,
062: InboundEndpoint Endpoint) throws CreateException {
063: super (Connector, service, Endpoint);
064: connector = (CxfConnector) Connector;
065: }
066:
067: @SuppressWarnings("unchecked")
068: @Override
069: protected void doInitialise() throws InitialisationException {
070: try {
071:
072: Map endpointProps = getEndpoint().getProperties();
073: String wsdlUrl = (String) endpointProps
074: .get(CxfConstants.WSDL_LOCATION);
075: String databinding = (String) endpointProps
076: .get(CxfConstants.DATA_BINDING);
077: String bindingId = (String) endpointProps
078: .get(CxfConstants.BINDING_ID);
079: String frontend = (String) endpointProps
080: .get(CxfConstants.FRONTEND);
081: String bridge = (String) endpointProps
082: .get(CxfConstants.BRIDGE);
083: String serviceClassName = (String) endpointProps
084: .get(CxfConstants.SERVICE_CLASS);
085: List<AbstractFeature> features = (List<AbstractFeature>) endpointProps
086: .get(CxfConstants.FEATURES);
087:
088: Class<?> svcCls = null;
089: Class<?> targetCls = getTargetClass();
090: if (!StringUtils.isEmpty(serviceClassName)) {
091: svcCls = ClassUtils.loadClass(serviceClassName,
092: getClass());
093: } else {
094: svcCls = targetCls;
095: }
096:
097: if (BooleanUtils.toBoolean(bridge)) {
098: svcCls = ProviderService.class;
099: frontend = "jaxws";
100: }
101:
102: if (StringUtils.isEmpty(frontend)) {
103: frontend = connector.getDefaultFrontend();
104: }
105:
106: ServerFactoryBean sfb = null;
107: if (CxfConstants.SIMPLE_FRONTEND.equals(frontend)) {
108: sfb = new ServerFactoryBean();
109: sfb.setDataBinding(new AegisDatabinding());
110: } else if (CxfConstants.JAX_WS_FRONTEND.equals(frontend)) {
111: sfb = new JaxWsServerFactoryBean();
112: } else {
113: throw new CreateException(CxfMessages
114: .invalidFrontend(frontend), this );
115: }
116:
117: if (!(service.getComponent() instanceof JavaComponent)) {
118: throw new InitialisationException(CxfMessages
119: .javaComponentRequiredForInboundEndpoint(),
120: this );
121: } else {
122: sfb.setServiceBean(((JavaComponent) service
123: .getComponent()).getObjectFactory()
124: .getInstance());
125: }
126:
127: // The binding - i.e. SOAP, XML, HTTP Binding, etc
128: if (bindingId != null) {
129: sfb.setBindingId(bindingId);
130: }
131:
132: if (features != null) {
133: sfb.setFeatures(features);
134: }
135:
136: sfb.setInInterceptors((List<Interceptor>) endpointProps
137: .get("inInterceptors"));
138: sfb
139: .setInFaultInterceptors((List<Interceptor>) endpointProps
140: .get("inFaultInterceptors"));
141: sfb.setOutInterceptors((List<Interceptor>) endpointProps
142: .get("outInterceptors"));
143: sfb
144: .setOutFaultInterceptors((List<Interceptor>) endpointProps
145: .get("outFaultInterceptors"));
146:
147: if (sfb.getInInterceptors() == null) {
148: sfb.setInInterceptors(new ArrayList<Interceptor>());
149: }
150:
151: sfb.getInInterceptors().add(new MuleHeadersInInterceptor());
152:
153: // Aegis, JAXB, other?
154: if (databinding != null) {
155: Class<?> c = ClassLoaderUtils.loadClass(databinding,
156: getClass());
157: sfb.setDataBinding((DataBinding) c.newInstance());
158: }
159:
160: sfb.setServiceClass(svcCls);
161: sfb.setAddress(getAddressWithoutQuery());
162:
163: if (wsdlUrl != null) {
164: sfb.setWsdlURL(wsdlUrl);
165: }
166:
167: ReflectionServiceFactoryBean svcFac = sfb
168: .getServiceFactory();
169:
170: addIgnoredMethods(svcFac, Callable.class.getName());
171: addIgnoredMethods(svcFac, Initialisable.class.getName());
172: addIgnoredMethods(svcFac, Disposable.class.getName());
173: addIgnoredMethods(svcFac, ServiceAware.class.getName());
174:
175: String name = (String) endpointProps.get(CxfConstants.NAME);
176: // check if there is the namespace property on the service
177: String namespace = (String) endpointProps
178: .get(CxfConstants.NAMESPACE);
179:
180: // HACK because CXF expects a QName for the service
181: initServiceName(svcCls, name, namespace, svcFac);
182:
183: boolean sync = endpoint.isSynchronous();
184: // default to synchronous if using http
185: if (endpoint.getEndpointURI().getScheme()
186: .startsWith("http")
187: || endpoint.getEndpointURI().getScheme()
188: .startsWith("servlet")) {
189: sync = true;
190: }
191:
192: sfb.setInvoker(new MuleInvoker(this , targetCls, sync));
193: sfb.setStart(false);
194:
195: Bus bus = connector.getCxfBus();
196: sfb.setBus(bus);
197:
198: Configurer configurer = bus.getExtension(Configurer.class);
199: if (null != configurer) {
200: configurer.configureBean(sfb.getServiceFactory()
201: .getEndpointName().toString(), sfb);
202: }
203:
204: server = sfb.create();
205: } catch (MuleException e) {
206: throw new InitialisationException(e, this );
207: } catch (ClassNotFoundException e) {
208: // will be thrown in the case that the ClassUtils.loadClass() does
209: // not find the class to load
210: throw new InitialisationException(e, this );
211: } catch (Exception e) {
212: throw new InitialisationException(e, this );
213: }
214: }
215:
216: private String getAddressWithoutQuery() {
217: String a = getEndpointURI().getAddress();
218: int idx = a.lastIndexOf('?');
219: if (idx > -1) {
220: a = a.substring(0, idx);
221: }
222: return a;
223: }
224:
225: /**
226: * Gross hack to support getting the service namespace from CXF if one wasn't
227: * supplied.
228: */
229: private void initServiceName(Class<?> exposedInterface,
230: String name, String namespace,
231: ReflectionServiceFactoryBean svcFac) {
232: svcFac.setServiceClass(exposedInterface);
233: for (AbstractServiceConfiguration c : svcFac
234: .getServiceConfigurations()) {
235: c.setServiceFactory(svcFac);
236: }
237:
238: if (name != null && namespace == null) {
239: namespace = svcFac.getServiceQName().getNamespaceURI();
240: } else if (name == null && namespace != null) {
241: name = svcFac.getServiceQName().getLocalPart();
242: }
243:
244: if (name != null) {
245: svcFac.setServiceName(new QName(namespace, name));
246: }
247: }
248:
249: public void addIgnoredMethods(ReflectionServiceFactoryBean svcFac,
250: String className) {
251: try {
252: Class<?> c = ClassUtils.loadClass(className, getClass());
253: for (int i = 0; i < c.getMethods().length; i++) {
254: svcFac.getIgnoredMethods().add(c.getMethods()[i]);
255: }
256: } catch (ClassNotFoundException e) {
257: // can be ignored.
258: }
259: }
260:
261: private Class<?> getTargetClass() throws MuleException,
262: ClassNotFoundException {
263: try {
264: return ((JavaComponent) service.getComponent())
265: .getObjectType();
266: } catch (Exception e) {
267: throw new CreateException(e, this );
268: }
269: }
270:
271: protected void doDispose() {
272: // template method
273: }
274:
275: public void doConnect() throws Exception {
276: // Start the CXF Server
277: server.start();
278: connector.registerReceiverWithMuleService(this , endpoint
279: .getEndpointURI());
280: }
281:
282: public void doDisconnect() throws Exception {
283: server.stop();
284: }
285:
286: public void doStart() throws MuleException {
287: // nothing to do
288: }
289:
290: public void doStop() throws MuleException {
291: // nothing to do
292: }
293:
294: public Server getServer() {
295: return server;
296: }
297:
298: public boolean isBridge() {
299: return bridge;
300: }
301:
302: }
|