001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */package org.apache.cxf.jaxws;
019:
020: import java.net.MalformedURLException;
021: import java.net.URL;
022: import java.util.Collection;
023: import java.util.HashMap;
024: import java.util.HashSet;
025: import java.util.Iterator;
026: import java.util.List;
027: import java.util.Map;
028: import java.util.ResourceBundle;
029: import java.util.concurrent.Executor;
030: import java.util.logging.Level;
031: import java.util.logging.Logger;
032:
033: import javax.jws.WebService;
034: import javax.xml.bind.JAXBContext;
035: import javax.xml.namespace.QName;
036: import javax.xml.ws.Dispatch;
037: import javax.xml.ws.Service.Mode;
038: import javax.xml.ws.WebServiceException;
039: import javax.xml.ws.handler.Handler;
040: import javax.xml.ws.handler.HandlerResolver;
041: import javax.xml.ws.spi.ServiceDelegate;
042:
043: import org.apache.cxf.Bus;
044: import org.apache.cxf.BusException;
045: import org.apache.cxf.binding.BindingFactoryManager;
046: import org.apache.cxf.common.i18n.Message;
047: import org.apache.cxf.common.logging.LogUtils;
048: import org.apache.cxf.configuration.Configurer;
049: import org.apache.cxf.databinding.DataBinding;
050: import org.apache.cxf.databinding.source.SourceDataBinding;
051: import org.apache.cxf.endpoint.Endpoint;
052: import org.apache.cxf.endpoint.EndpointException;
053: import org.apache.cxf.jaxb.JAXBDataBinding;
054: import org.apache.cxf.jaxws.binding.soap.JaxWsSoapBindingConfiguration;
055: import org.apache.cxf.jaxws.handler.HandlerResolverImpl;
056: import org.apache.cxf.jaxws.handler.PortInfoImpl;
057: import org.apache.cxf.jaxws.support.BindingID;
058: import org.apache.cxf.jaxws.support.DummyImpl;
059: import org.apache.cxf.jaxws.support.JaxWsClientEndpointImpl;
060: import org.apache.cxf.jaxws.support.JaxWsEndpointImpl;
061: import org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean;
062: import org.apache.cxf.service.Service;
063: import org.apache.cxf.service.factory.AbstractServiceFactoryBean;
064: import org.apache.cxf.service.factory.ReflectionServiceFactoryBean;
065: import org.apache.cxf.service.factory.ServiceConstructionException;
066: import org.apache.cxf.service.model.BindingInfo;
067: import org.apache.cxf.service.model.EndpointInfo;
068: import org.apache.cxf.service.model.ServiceInfo;
069: import org.apache.cxf.service.model.ServiceModelUtil;
070: import org.apache.cxf.tools.util.URIParserUtil;
071: import org.apache.cxf.transport.DestinationFactory;
072: import org.apache.cxf.transport.DestinationFactoryManager;
073: import org.apache.cxf.workqueue.OneShotAsyncExecutor;
074: import org.apache.cxf.ws.addressing.EndpointReferenceType;
075: import org.apache.cxf.wsdl.EndpointReferenceUtils;
076: import org.apache.cxf.wsdl11.WSDLServiceFactory;
077:
078: public class ServiceImpl extends ServiceDelegate {
079:
080: private static final Logger LOG = LogUtils
081: .getL7dLogger(ServiceImpl.class);
082: private static final ResourceBundle BUNDLE = LOG
083: .getResourceBundle();
084:
085: private Bus bus;
086: private String wsdlURL;
087:
088: private HandlerResolver handlerResolver;
089: private final Collection<QName> ports = new HashSet<QName>();
090: private Map<QName, PortInfoImpl> portInfos = new HashMap<QName, PortInfoImpl>();
091: private Executor executor;
092: private QName serviceName;
093: private Class<?> clazz;
094:
095: public ServiceImpl(Bus b, URL url, QName name, Class<?> cls) {
096: bus = b;
097: wsdlURL = url == null ? null : url.toString();
098: this .serviceName = name;
099: clazz = cls;
100:
101: handlerResolver = new HandlerResolverImpl(bus, name, clazz);
102: if (url != null) {
103: try {
104: initializePorts();
105: } catch (ServiceConstructionException e) {
106: throw new WebServiceException(e);
107: }
108: }
109: }
110:
111: private void initializePorts() {
112: WSDLServiceFactory sf = new WSDLServiceFactory(bus, wsdlURL,
113: serviceName);
114: Service service = sf.create();
115: for (ServiceInfo si : service.getServiceInfos()) {
116: for (EndpointInfo ei : si.getEndpoints()) {
117: this .ports.add(ei.getName());
118: String bindingID = BindingID.getJaxwsBindingID(ei
119: .getTransportId());
120: addPort(ei.getName(), bindingID, ei.getAddress());
121: }
122: }
123: }
124:
125: public final void addPort(QName portName, String bindingId,
126: String address) {
127: PortInfoImpl portInfo = new PortInfoImpl(bindingId, portName,
128: serviceName);
129: portInfo.setAddress(address);
130: portInfos.put(portName, portInfo);
131: }
132:
133: private Endpoint getJaxwsEndpoint(QName portName,
134: AbstractServiceFactoryBean sf) {
135: Service service = sf.getService();
136: EndpointInfo ei = null;
137: if (portName == null) {
138: ei = service.getServiceInfos().get(0).getEndpoints()
139: .iterator().next();
140: } else {
141: ei = service.getEndpointInfo(portName);
142: if (ei == null) {
143: PortInfoImpl portInfo = getPortInfo(portName);
144: if (null != portInfo) {
145: try {
146: ei = createEndpointInfo(sf, portName, portInfo);
147: } catch (BusException e) {
148: throw new WebServiceException(e);
149: }
150: }
151: }
152: }
153:
154: if (ei == null) {
155: Message msg = new Message("INVALID_PORT", BUNDLE, portName);
156: throw new WebServiceException(msg.toString());
157: }
158:
159: try {
160: return new JaxWsClientEndpointImpl(bus, service, ei, this );
161: } catch (EndpointException e) {
162: throw new WebServiceException(e);
163: }
164: }
165:
166: private AbstractServiceFactoryBean createDispatchService(
167: DataBinding db) {
168: AbstractServiceFactoryBean serviceFactory;
169:
170: Service dispatchService = null;
171:
172: if (null != wsdlURL) {
173: WSDLServiceFactory sf = new WSDLServiceFactory(bus,
174: wsdlURL, serviceName);
175: dispatchService = sf.create();
176: dispatchService.setDataBinding(db);
177: serviceFactory = sf;
178: } else {
179: ReflectionServiceFactoryBean sf = new JaxWsServiceFactoryBean();
180: sf.setBus(bus);
181: sf.setServiceName(serviceName);
182: // maybe we can find another way to create service which have no SEI
183: sf.setServiceClass(DummyImpl.class);
184: sf.setDataBinding(db);
185: dispatchService = sf.create();
186: serviceFactory = sf;
187: }
188: configureObject(dispatchService);
189: return serviceFactory;
190: }
191:
192: public <T> Dispatch<T> createDispatch(QName portName,
193: Class<T> type, Mode mode) {
194: AbstractServiceFactoryBean sf = null;
195: try {
196: sf = createDispatchService(new SourceDataBinding());
197: } catch (ServiceConstructionException e) {
198: throw new WebServiceException(e);
199: }
200: Endpoint endpoint = getJaxwsEndpoint(portName, sf);
201: Dispatch<T> disp = new DispatchImpl<T>(bus, mode, type,
202: getExecutor(), endpoint);
203:
204: configureObject(disp);
205:
206: return disp;
207: }
208:
209: public Dispatch<Object> createDispatch(QName portName,
210: JAXBContext context, Mode mode) {
211: AbstractServiceFactoryBean sf = null;
212: try {
213: sf = createDispatchService(new JAXBDataBinding(context));
214: } catch (ServiceConstructionException e) {
215: throw new WebServiceException(e);
216: }
217: Endpoint endpoint = getJaxwsEndpoint(portName, sf);
218: Dispatch<Object> disp = new DispatchImpl<Object>(bus, mode,
219: context, Object.class, getExecutor(), endpoint);
220:
221: configureObject(disp);
222:
223: return disp;
224: }
225:
226: public Executor getExecutor() {
227: return executor;
228: }
229:
230: public HandlerResolver getHandlerResolver() {
231: return handlerResolver;
232: }
233:
234: public <T> T getPort(Class<T> type) {
235: try {
236: return createPort(null, null, type);
237: } catch (ServiceConstructionException e) {
238: throw new WebServiceException(e);
239: }
240: }
241:
242: public <T> T getPort(QName portName, Class<T> type) {
243: if (portName == null) {
244: throw new WebServiceException(BUNDLE
245: .getString("PORT_NAME_NULL_EXC"));
246: }
247:
248: if (!ports.contains(portName)
249: && !portInfos.containsKey(portName)) {
250: throw new WebServiceException(new Message("INVALID_PORT",
251: BUNDLE, portName).toString());
252: }
253:
254: try {
255: return createPort(portName, null, type);
256: } catch (ServiceConstructionException e) {
257: throw new WebServiceException(e);
258: }
259: }
260:
261: public <T> T getPort(EndpointReferenceType endpointReference,
262: Class<T> type) {
263: endpointReference = EndpointReferenceUtils.resolve(
264: endpointReference, bus);
265: QName serviceQName = EndpointReferenceUtils
266: .getServiceName(endpointReference);
267: String portName = EndpointReferenceUtils
268: .getPortName(endpointReference);
269:
270: QName portQName = null;
271: if (portName != null && serviceQName != null) {
272: portQName = new QName(serviceQName.getNamespaceURI(),
273: portName);
274: }
275:
276: return createPort(portQName, endpointReference, type);
277: }
278:
279: public Iterator<QName> getPorts() {
280: return ports.iterator();
281: }
282:
283: public QName getServiceName() {
284: return serviceName;
285: }
286:
287: public URL getWSDLDocumentLocation() {
288: try {
289: return new URL(wsdlURL);
290: } catch (MalformedURLException e) {
291: throw new WebServiceException(e);
292: }
293: }
294:
295: public void setExecutor(Executor e) {
296: this .executor = e;
297: }
298:
299: public void setHandlerResolver(HandlerResolver hr) {
300: handlerResolver = hr;
301: }
302:
303: public Bus getBus() {
304: return bus;
305: }
306:
307: protected <T> T createPort(QName portName,
308: EndpointReferenceType epr, Class<T> serviceEndpointInterface) {
309: LOG.log(Level.FINE, "creating port for portName", portName);
310: LOG.log(Level.FINE, "endpoint reference:", epr);
311: LOG.log(Level.FINE, "endpoint interface:",
312: serviceEndpointInterface);
313:
314: JaxWsProxyFactoryBean proxyFac = new JaxWsProxyFactoryBean();
315: JaxWsClientFactoryBean clientFac = (JaxWsClientFactoryBean) proxyFac
316: .getClientFactoryBean();
317: ReflectionServiceFactoryBean serviceFactory = proxyFac
318: .getServiceFactory();
319:
320: proxyFac.setBus(bus);
321: proxyFac.setServiceClass(serviceEndpointInterface);
322: proxyFac.setServiceName(serviceName);
323:
324: if (wsdlURL != null) {
325: proxyFac.setWsdlURL(wsdlURL);
326: }
327:
328: if (portName == null) {
329: QName portTypeName = getPortTypeName(serviceEndpointInterface);
330:
331: Service service = serviceFactory.getService();
332: if (service == null) {
333: serviceFactory
334: .setServiceClass(serviceEndpointInterface);
335: serviceFactory.setBus(getBus());
336: service = serviceFactory.create();
337: }
338:
339: EndpointInfo ei = ServiceModelUtil.findBestEndpointInfo(
340: portTypeName, service.getServiceInfos());
341: if (ei != null) {
342: portName = ei.getName();
343: } else {
344: portName = serviceFactory.getEndpointName();
345: }
346: }
347:
348: serviceFactory.setEndpointName(portName);
349:
350: if (epr != null) {
351: clientFac.setEndpointReference(epr);
352: }
353: PortInfoImpl portInfo = portInfos.get(portName);
354: if (portInfo != null) {
355: clientFac.setBindingId(portInfo.getBindingID());
356: clientFac.setAddress(portInfo.getAddress());
357: }
358: configureObject(portName.toString()
359: + ".jaxws-client.proxyFactory", proxyFac);
360:
361: Object obj = proxyFac.create();
362:
363: // Configure the Service
364: Service service = serviceFactory.getService();
365: service.setExecutor(new Executor() {
366: public void execute(Runnable command) {
367: Executor ex = getExecutor();
368: if (ex == null) {
369: ex = OneShotAsyncExecutor.getInstance();
370: }
371: ex.execute(command);
372: }
373: });
374: configureObject(service);
375:
376: // Configure the JaxWsEndpoitnImpl
377: JaxWsEndpointImpl jaxwsEndpoint = (JaxWsEndpointImpl) clientFac
378: .getClient().getEndpoint();
379: configureObject(jaxwsEndpoint);
380:
381: List<Handler> hc = jaxwsEndpoint.getJaxwsBinding()
382: .getHandlerChain();
383:
384: hc.addAll(handlerResolver.getHandlerChain(portInfos
385: .get(portName)));
386:
387: LOG.log(Level.FINE, "created proxy", obj);
388:
389: ports.add(portName);
390: return serviceEndpointInterface.cast(obj);
391: }
392:
393: private EndpointInfo createEndpointInfo(
394: AbstractServiceFactoryBean serviceFactory, QName portName,
395: PortInfoImpl portInfo) throws BusException {
396: EndpointInfo ei = null;
397: String address = portInfo.getAddress();
398:
399: DestinationFactoryManager dfm = bus
400: .getExtension(DestinationFactoryManager.class);
401: DestinationFactory df = dfm
402: .getDestinationFactoryForUri(portInfo.getAddress());
403:
404: String transportId = df.getTransportIds().get(0);
405: String bindingID = BindingID.getBindingID(portInfo
406: .getBindingID());
407:
408: Object config = null;
409: if (serviceFactory instanceof JaxWsServiceFactoryBean) {
410: config = new JaxWsSoapBindingConfiguration(
411: (JaxWsServiceFactoryBean) serviceFactory);
412: }
413: BindingInfo bindingInfo = bus.getExtension(
414: BindingFactoryManager.class).getBindingFactory(
415: bindingID).createBindingInfo(
416: serviceFactory.getService(), bindingID, config);
417:
418: Service service = serviceFactory.getService();
419: service.getServiceInfos().get(0).addBinding(bindingInfo);
420:
421: ei = new EndpointInfo(service.getServiceInfos().get(0),
422: transportId);
423: ei.setName(portName);
424: ei.setAddress(address);
425: ei.setBinding(bindingInfo);
426:
427: service.getServiceInfos().get(0).addEndpoint(ei);
428: return ei;
429: }
430:
431: private void configureObject(Object instance) {
432: configureObject(null, instance);
433: }
434:
435: private void configureObject(String name, Object instance) {
436: Configurer configurer = bus.getExtension(Configurer.class);
437: if (null != configurer) {
438: configurer.configureBean(name, instance);
439: }
440: }
441:
442: private PortInfoImpl getPortInfo(QName portName) {
443: // TODO if the portName null ?
444: return portInfos.get(portName);
445: }
446:
447: private QName getPortTypeName(Class<?> serviceEndpointInterface) {
448: Class<?> seiClass = serviceEndpointInterface;
449: if (!serviceEndpointInterface
450: .isAnnotationPresent(WebService.class)) {
451: Message msg = new Message("SEI_NO_WEBSERVICE_ANNOTATION",
452: BUNDLE, serviceEndpointInterface.getCanonicalName());
453: throw new WebServiceException(msg.toString());
454: }
455:
456: if (!serviceEndpointInterface.isInterface()) {
457: WebService webService = serviceEndpointInterface
458: .getAnnotation(WebService.class);
459: String epi = webService.endpointInterface();
460: if (epi.length() > 0) {
461: try {
462: seiClass = Thread.currentThread()
463: .getContextClassLoader().loadClass(epi);
464: } catch (ClassNotFoundException e) {
465: Message msg = new Message("COULD_NOT_LOAD_CLASS",
466: BUNDLE, seiClass.getCanonicalName());
467: throw new WebServiceException(msg.toString());
468: }
469: if (!seiClass
470: .isAnnotationPresent(javax.jws.WebService.class)) {
471: Message msg = new Message(
472: "SEI_NO_WEBSERVICE_ANNOTATION", BUNDLE,
473: seiClass.getCanonicalName());
474: throw new WebServiceException(msg.toString());
475: }
476: }
477: }
478:
479: WebService webService = seiClass
480: .getAnnotation(WebService.class);
481: String name = webService.name();
482: if (name.length() == 0) {
483: name = seiClass.getSimpleName();
484: }
485:
486: String tns = webService.targetNamespace();
487: if (tns.length() == 0) {
488: tns = URIParserUtil.getNamespace(seiClass.getPackage()
489: .getName());
490: }
491:
492: return new QName(tns, name);
493: }
494:
495: // TODO JAX-WS 2.1
496: /*
497: public <T> Dispatch<T> createDispatch(QName portName,
498: Class<T> type,
499: Mode mode,
500: WebServiceFeature... features) {
501: // TODO
502: throw new UnsupportedOperationException();
503: }
504:
505: public <T> Dispatch<T> createDispatch(EndpointReference endpointReference,
506: Class<T> type,
507: Mode mode,
508: WebServiceFeature... features) {
509: // TODO
510: throw new UnsupportedOperationException();
511: }
512:
513: public Dispatch<Object> createDispatch(QName portName,
514: JAXBContext context,
515: Mode mode,
516: WebServiceFeature... features) {
517: // TODO
518: throw new UnsupportedOperationException();
519: }
520:
521: public Dispatch<Object> createDispatch(EndpointReference endpointReference,
522: JAXBContext context,
523: Mode mode,
524: WebServiceFeature... features) {
525: // TODO
526: throw new UnsupportedOperationException();
527: }
528:
529: public <T> T getPort(Class<T> serviceEndpointInterface,
530: WebServiceFeature... features) {
531: // TODO
532: throw new UnsupportedOperationException();
533: }
534:
535: public <T> T getPort(QName portName,
536: Class<T> serviceEndpointInterface,
537: WebServiceFeature... features) {
538: // TODO
539: throw new UnsupportedOperationException();
540: }
541:
542: public <T> T getPort(EndpointReference endpointReference,
543: Class<T> serviceEndpointInterface,
544: WebServiceFeature... features) {
545: // TODO
546: throw new UnsupportedOperationException();
547: }
548: */
549: }
|