001: package org.objectweb.celtix.bus.jaxws;
002:
003: import java.io.IOException;
004: import java.lang.reflect.Method;
005: import java.util.Iterator;
006: import java.util.List;
007: import java.util.Map;
008: import java.util.concurrent.ConcurrentHashMap;
009: import java.util.concurrent.Executor;
010: import java.util.logging.Level;
011: import java.util.logging.Logger;
012:
013: import javax.jws.soap.SOAPBinding.Style;
014: import javax.wsdl.BindingInput;
015: import javax.wsdl.BindingOperation;
016: import javax.wsdl.Definition;
017: import javax.wsdl.Port;
018: import javax.wsdl.WSDLException;
019: import javax.wsdl.extensions.ExtensibilityElement;
020: import javax.wsdl.extensions.soap.SOAPBody;
021: import javax.xml.bind.JAXBContext;
022: import javax.xml.bind.JAXBException;
023: import javax.xml.namespace.QName;
024: import javax.xml.transform.Source;
025: import javax.xml.validation.Schema;
026: import javax.xml.ws.Binding;
027: import javax.xml.ws.BindingType;
028: import javax.xml.ws.Endpoint;
029: import javax.xml.ws.Provider;
030: import javax.xml.ws.ServiceMode;
031: import javax.xml.ws.WebServiceException;
032: import javax.xml.ws.WebServicePermission;
033: import javax.xml.ws.WebServiceProvider;
034: import javax.xml.ws.handler.Handler;
035: import javax.xml.ws.soap.SOAPBinding;
036:
037: import org.objectweb.celtix.Bus;
038: import org.objectweb.celtix.BusException;
039: import org.objectweb.celtix.bindings.BindingFactory;
040: import org.objectweb.celtix.bindings.DataBindingCallback;
041: import org.objectweb.celtix.bindings.ServerBinding;
042: import org.objectweb.celtix.bindings.ServerBindingEndpointCallback;
043: import org.objectweb.celtix.bindings.ServerDataBindingCallback;
044: import org.objectweb.celtix.bus.handlers.AnnotationHandlerChainBuilder;
045: import org.objectweb.celtix.bus.jaxws.configuration.types.HandlerChainType;
046: import org.objectweb.celtix.common.i18n.Message;
047: import org.objectweb.celtix.common.injection.ResourceInjector;
048: import org.objectweb.celtix.common.logging.LogUtils;
049: import org.objectweb.celtix.configuration.Configuration;
050: import org.objectweb.celtix.configuration.ConfigurationBuilder;
051: import org.objectweb.celtix.configuration.ConfigurationBuilderFactory;
052: import org.objectweb.celtix.context.ObjectMessageContext;
053: import org.objectweb.celtix.endpoints.ContextInspector;
054: import org.objectweb.celtix.ws.addressing.EndpointReferenceType;
055: import org.objectweb.celtix.wsdl.EndpointReferenceUtils;
056:
057: public class EndpointImpl extends javax.xml.ws.Endpoint implements
058: ServerBindingEndpointCallback {
059:
060: public static final String ENDPOINT_CONFIGURATION_URI = "http://celtix.objectweb.org/bus/jaxws/endpoint-config";
061:
062: private static final Logger LOG = LogUtils
063: .getL7dLogger(EndpointImpl.class);
064:
065: protected EndpointReferenceType reference;
066:
067: protected boolean published;
068:
069: protected final Bus bus;
070: protected final Object implementor;
071: protected Class<?> implementorClass;
072: protected final String bindingURI;
073:
074: protected Configuration configuration;
075: protected List<Source> metadata;
076: protected Executor executor;
077: protected JAXBContext context;
078: protected Schema schema;
079: protected Map<String, Object> properties;
080: protected ServerBinding serverBinding;
081:
082: protected boolean doInit;
083: protected boolean initialised;
084:
085: //Implemetor (SEI) specific members
086: protected List<Class<?>> seiClass;
087:
088: //Implementor (Provider) specific members
089: protected ServiceMode serviceMode;
090: protected WebServiceProvider wsProvider;
091: protected Class<?> dataClass;
092:
093: protected Map<QName, ServerDataBindingCallback> callbackMap = new ConcurrentHashMap<QName, ServerDataBindingCallback>();
094:
095: public EndpointImpl(Bus b, Object impl, String bindingId) {
096: this (b, impl, bindingId, EndpointReferenceUtils
097: .getEndpointReference(b.getWSDLManager(), impl));
098: }
099:
100: public EndpointImpl(Bus b, Object impl, String bindingId,
101: EndpointReferenceType ref) {
102: this (b, impl, impl.getClass(), bindingId, ref);
103: }
104:
105: public EndpointImpl(Bus b, Object obj, Class<?> implClass,
106: String bindingId, EndpointReferenceType ref) {
107:
108: bus = b;
109: implementor = obj;
110: implementorClass = implClass;
111: reference = ref;
112: bindingURI = bindingId;
113:
114: if (Provider.class.isAssignableFrom(implementorClass)) {
115: //Provider Implementor
116: wsProvider = implementorClass
117: .getAnnotation(WebServiceProvider.class);
118: if (wsProvider == null) {
119: throw new WebServiceException(
120: "Provider based implementor must carry a WebServiceProvider annotation");
121: }
122: serviceMode = implementorClass
123: .getAnnotation(ServiceMode.class);
124: } else {
125: //SEI Implementor
126: try {
127: context = JAXBEncoderDecoder
128: .createJAXBContextForClass(implementorClass);
129: } catch (JAXBException ex1) {
130: ex1.printStackTrace();
131: context = null;
132: }
133: }
134:
135: if (bus != null) {
136: //NOTE EndpointRegistry need to check the Registry instrumentation is created
137: bus.getEndpointRegistry().registerEndpoint(this );
138: }
139:
140: doInit = true;
141: }
142:
143: private synchronized void init() {
144: if (doInit) {
145: try {
146: injectResources();
147: initProperties();
148: initMetaData();
149:
150: configuration = createConfiguration();
151: if (null != configuration) {
152: serverBinding = createServerBinding(bindingURI);
153: configureHandlers();
154: configureSystemHandlers();
155: configureSchemaValidation();
156: }
157:
158: initOpMap();
159: } catch (Exception ex) {
160: if (ex instanceof WebServiceException) {
161: throw (WebServiceException) ex;
162: }
163: throw new WebServiceException(
164: "Creation of Endpoint failed", ex);
165: }
166: }
167: doInit = false;
168: }
169:
170: private void initOpMap() throws WSDLException {
171: Definition def = EndpointReferenceUtils.getWSDLDefinition(bus
172: .getWSDLManager(), reference);
173: if (def == null) {
174: return;
175: }
176: Port port = EndpointReferenceUtils.getPort(
177: bus.getWSDLManager(), reference);
178: List ops = port.getBinding().getBindingOperations();
179: Iterator opIt = ops.iterator();
180: while (opIt.hasNext()) {
181: BindingOperation op = (BindingOperation) opIt.next();
182: BindingInput bindingInput = op.getBindingInput();
183: List elements = bindingInput.getExtensibilityElements();
184: QName qn = new QName(def.getTargetNamespace(), op.getName());
185: for (Iterator i = elements.iterator(); i.hasNext();) {
186: Object element = i.next();
187: if (SOAPBody.class.isInstance(element)) {
188: SOAPBody body = (SOAPBody) element;
189: if (body.getNamespaceURI() != null) {
190: qn = new QName(body.getNamespaceURI(), op
191: .getName());
192: }
193: }
194: }
195:
196: ServerDataBindingCallback cb = getDataBindingCallback(qn,
197: null, DataBindingCallback.Mode.PARTS);
198: callbackMap.put(qn, cb);
199: if (!"".equals(cb.getRequestWrapperQName().getLocalPart())) {
200: callbackMap.put(cb.getRequestWrapperQName(), cb);
201: }
202: }
203: }
204:
205: private void initProperties() {
206: if (null != properties) {
207: QName serviceName = (QName) properties
208: .get(Endpoint.WSDL_SERVICE);
209: QName portName = (QName) properties.get(Endpoint.WSDL_PORT);
210: if (null != serviceName && null != portName) {
211: EndpointReferenceUtils.setServiceAndPortName(reference,
212: serviceName, portName.getLocalPart());
213: }
214: }
215: }
216:
217: private void initMetaData() {
218: if (null != metadata) {
219: EndpointReferenceUtils.setMetadata(reference, metadata);
220: }
221: }
222:
223: /*
224: * (non-Javadoc)
225: *
226: * @see javax.xml.ws.Endpoint#getBinding()
227: */
228: public Binding getBinding() {
229: //Initialise the Endpoint so HandlerChain is set up on Binding.
230: if (doInit) {
231: init();
232: }
233: return serverBinding.getBinding();
234: }
235:
236: /*
237: * (non-Javadoc)
238: *
239: * @see javax.xml.ws.Endpoint#getImplementor()
240: */
241: public Object getImplementor() {
242: return implementor;
243: }
244:
245: public void releaseImplementor(Object impl) {
246: //no-op for normal cases
247: }
248:
249: /**
250: * @return Returns the Implementor Class.
251: */
252: public Class getImplementorClass() {
253: return implementorClass;
254: }
255:
256: /*
257: * (non-Javadoc) Not sure if this is meant to return the effective metadata -
258: * or the default metadata previously assigned with
259: * javax.xml.ws.Endpoint#setHandlerChain()
260: *
261: * @see javax.xml.ws.Endpoint#getMetadata()
262: */
263: public List<Source> getMetadata() {
264: return metadata;
265: }
266:
267: /**
268: * documented but not yet implemented in RI
269: */
270:
271: public Executor getExecutor() {
272: return executor;
273: }
274:
275: /*
276: * (non-Javadoc)
277: *
278: * @see javax.xml.ws.Endpoint#isPublished()
279: */
280: public boolean isPublished() {
281: return published;
282: }
283:
284: /*
285: * (non-Javadoc)
286: *
287: * @see javax.xml.ws.Endpoint#publish(java.lang.Object)
288: */
289: public void publish(Object serverContext) {
290: if (doInit) {
291: init();
292: initialised = true;
293: }
294: if (isPublished()) {
295: LOG.warning("ENDPOINT_ALREADY_PUBLISHED_MSG");
296: }
297: // apply all changes to configuration and metadata and (re-)activate
298: try {
299: String address = getAddressFromContext(serverContext);
300: if (!isContextBindingCompatible(address)) {
301: throw new IllegalArgumentException(new BusException(
302: new Message("BINDING_INCOMPATIBLE_CONTEXT_EXC",
303: LOG)));
304: }
305: publish(address);
306: } catch (Exception ex) {
307: throw new WebServiceException(ex);
308: }
309: }
310:
311: /*
312: * (non-Javadoc)
313: *
314: * @see javax.xml.ws.Endpoint#publish(java.lang.String)
315: */
316: public void publish(String address) {
317:
318: SecurityManager security = System.getSecurityManager();
319: if (security != null) {
320: security.checkPermission(new WebServicePermission(
321: "endpointPublish"));
322: }
323: if (doInit && !initialised) {
324: init();
325: }
326: if (isPublished()) {
327: LOG.warning("ENDPOINT_ALREADY_PUBLISHED_MSG");
328: }
329: doPublish(address);
330: }
331:
332: /*
333: * (non-Javadoc)
334: *
335: * @see javax.xml.ws.Endpoint#setMetadata(java.util.List)
336: */
337: public void setMetadata(List<Source> m) {
338: if (isPublished()) {
339: throw new IllegalStateException(
340: "Endpoint has already been published");
341: }
342: metadata = m;
343: doInit = true;
344: }
345:
346: /**
347: * documented but not yet implemented in RI
348: */
349: public void setExecutor(Executor ex) {
350: executor = ex;
351: }
352:
353: /*
354: * (non-Javadoc)
355: *
356: * @see javax.xml.ws.Endpoint#stop()
357: */
358: public void stop() {
359: if (!isPublished()) {
360: LOG.warning("ENDPOINT_INACTIVE_MSG");
361: }
362: try {
363: serverBinding.deactivate();
364: } catch (IOException ex) {
365: throw new WebServiceException(ex);
366: }
367: published = false;
368: }
369:
370: public Bus getBus() {
371: return bus;
372: }
373:
374: public ServerBinding getServerBinding() {
375: if (doInit) {
376: init();
377: }
378:
379: return serverBinding;
380: }
381:
382: public EndpointReferenceType getEndpointReferenceType() {
383: return reference;
384: }
385:
386: private String getBindingIdFromWSDL() {
387: Port port = null;
388: try {
389: port = EndpointReferenceUtils.getPort(bus.getWSDLManager(),
390: reference);
391: } catch (WSDLException we) {
392: return null;
393: }
394: return ((ExtensibilityElement) port.getExtensibilityElements()
395: .get(0)).getElementType().getNamespaceURI();
396: }
397:
398: ServerBinding createServerBinding(String bindingId)
399: throws BusException, WSDLException, IOException {
400: if (null == bindingId) {
401: BindingType bType = implementorClass
402: .getAnnotation(BindingType.class);
403: if (bType != null) {
404: bindingId = bType.value();
405: }
406: }
407:
408: String bindingIdFromWSDL = null;
409: if (bindingId == null) {
410: bindingIdFromWSDL = getBindingIdFromWSDL();
411: }
412:
413: if (null == bindingId && null != bindingIdFromWSDL) {
414: bindingId = bindingIdFromWSDL;
415: }
416:
417: if (null == bindingId) {
418: // Use SOAP1.1/HTTP Binding as default. JAX-WS Spec 5.2.1
419: bindingId = SOAPBinding.SOAP11HTTP_BINDING;
420: }
421:
422: BindingFactory factory = bus.getBindingManager()
423: .getBindingFactory(bindingId);
424: if (null == factory) {
425: throw new BusException(new Message(
426: "BINDING_FACTORY_MISSING_EXC", LOG, bindingId));
427: }
428: ServerBinding bindingImpl = factory.createServerBinding(
429: reference, this );
430: assert null != bindingImpl;
431: return bindingImpl;
432:
433: }
434:
435: String getAddressFromContext(Object ctx) throws Exception {
436: List<String> strs = configuration
437: .getStringList("serverContextInspectors");
438: Iterator iter = strs.iterator();
439: String address = null;
440: while (iter.hasNext()) {
441: String className = (String) iter.next();
442:
443: try {
444: LOG.log(Level.FINE, "loading context inspector",
445: className);
446:
447: Class<? extends ContextInspector> inspectorClass = Class
448: .forName(className, true,
449: getContextInspectorClassLoader())
450: .asSubclass(ContextInspector.class);
451:
452: ContextInspector inspector = inspectorClass
453: .newInstance();
454: address = inspector.getAddress(ctx);
455: if (address != null) {
456: return address;
457: }
458: } catch (ClassNotFoundException e) {
459: throw new WebServiceException(new Message(
460: "CONTEXT_INSPECTOR_INSTANTIATION_EXC", LOG)
461: .toString(), e);
462: } catch (InstantiationException e) {
463: throw new WebServiceException(new Message(
464: "CONTEXT_INSPECTOR_INSTANTIATION_EXC", LOG)
465: .toString(), e);
466: } catch (IllegalAccessException e) {
467: throw new WebServiceException(new Message(
468: "CONTEXT_INSPECTOR_INSTANTIATION_EXC", LOG)
469: .toString(), e);
470: }
471: }
472: return address;
473: }
474:
475: protected boolean isContextBindingCompatible(String address) {
476: return serverBinding.isBindingCompatible(address);
477: }
478:
479: void doPublish(String address) {
480:
481: EndpointReferenceUtils.setAddress(reference, address);
482: try {
483: serverBinding.activate();
484: published = true;
485: } catch (WSDLException ex) {
486: LOG.log(Level.SEVERE,
487: "SERVER_BINDING_ACTIVATION_FAILURE_MSG", ex);
488: throw new WebServiceException(ex);
489: } catch (IOException ex) {
490: LOG.log(Level.SEVERE,
491: "SERVER_BINDING_ACTIVATION_FAILURE_MSG", ex);
492: throw new WebServiceException(ex);
493: }
494: }
495:
496: public Map<String, Object> getProperties() {
497: return properties;
498: }
499:
500: public void setProperties(Map<String, Object> arg0) {
501: properties = arg0;
502: doInit = true;
503: }
504:
505: /**
506: * inject resources into servant. The resources are injected
507: * according to @Resource annotations. See JSR 250 for more
508: * information.
509: */
510: protected void injectResources(Object instance) {
511: if (instance != null) {
512: ResourceInjector injector = new ResourceInjector(bus
513: .getResourceManager());
514: injector.inject(instance);
515: }
516: }
517:
518: /**
519: * inject resources into servant. The resources are injected
520: * according to @Resource annotations. See JSR 250 for more
521: * information.
522: */
523: protected void injectResources() {
524: injectResources(implementor);
525: }
526:
527: /**
528: * Obtain handler chain from configuration first. If none is specified,
529: * default to the chain configured in the code, i.e. in annotations.
530: *
531: */
532: private void configureHandlers() {
533:
534: LOG.fine("loading handler chain for endpoint");
535: AnnotationHandlerChainBuilder builder = new AnnotationHandlerChainBuilder();
536: HandlerChainType hc = (HandlerChainType) configuration
537: .getObject("handlerChain");
538: List<Handler> chain = builder
539: .buildHandlerChainFromConfiguration(hc);
540: if (null == chain || chain.size() == 0) {
541: chain = builder.buildHandlerChainFor(implementorClass);
542: }
543: serverBinding.getBinding().setHandlerChain(chain);
544: }
545:
546: private void configureSystemHandlers() {
547: serverBinding.configureSystemHandlers(configuration);
548: }
549:
550: private void configureSchemaValidation() {
551: Boolean enableSchemaValidation = configuration.getObject(
552: Boolean.class, "enableSchemaValidation");
553:
554: if (enableSchemaValidation != null
555: && enableSchemaValidation.booleanValue()) {
556: LOG.fine("endpoint schema validation enabled");
557: schema = EndpointReferenceUtils.getSchema(bus
558: .getWSDLManager(), reference);
559: }
560: }
561:
562: public DataBindingCallback getFaultDataBindingCallback(
563: ObjectMessageContext objContext) {
564: return new JAXBDataBindingCallback(null,
565: DataBindingCallback.Mode.PARTS, context, schema, this );
566: }
567:
568: @SuppressWarnings("unchecked")
569: public ServerDataBindingCallback getDataBindingCallback(
570: QName operationName, ObjectMessageContext objContext,
571: DataBindingCallback.Mode mode) {
572: if (mode == DataBindingCallback.Mode.PARTS) {
573: ServerDataBindingCallback cb = callbackMap
574: .get(operationName);
575: if (null == cb) {
576: cb = new JAXBDataBindingCallback(
577: getMethod(operationName),
578: DataBindingCallback.Mode.PARTS, context,
579: schema, this );
580: }
581:
582: return cb;
583: }
584:
585: if (dataClass == null) {
586: dataClass = EndpointUtils.getProviderParameterType(this );
587: }
588:
589: return new ServerDynamicDataBindingCallback(dataClass, mode,
590: (Provider<?>) implementor);
591: }
592:
593: public Method getMethod(QName operationName) {
594:
595: if (wsProvider == null) {
596: return EndpointUtils.getMethod(this , operationName);
597: }
598:
599: Method invokeMethod = null;
600: if (operationName.getLocalPart().equals("invoke")) {
601:
602: try {
603: if (dataClass == null) {
604: dataClass = EndpointUtils
605: .getProviderParameterType(this );
606: }
607: invokeMethod = implementorClass.getMethod("invoke",
608: dataClass);
609: } catch (NoSuchMethodException ex) {
610: //TODO
611: }
612: }
613: return invokeMethod;
614: }
615:
616: public DataBindingCallback.Mode getServiceMode() {
617: DataBindingCallback.Mode mode = DataBindingCallback.Mode.PARTS;
618:
619: if (wsProvider != null) {
620: mode = serviceMode != null ? DataBindingCallback.Mode
621: .fromServiceMode(serviceMode.value())
622: : DataBindingCallback.Mode.PAYLOAD;
623: }
624: return mode;
625: }
626:
627: public WebServiceProvider getWebServiceProvider() {
628: return wsProvider;
629: }
630:
631: public synchronized List<Class<?>> getWebServiceAnnotatedClass() {
632: if (null == seiClass) {
633: seiClass = EndpointUtils
634: .getWebServiceAnnotatedClass(implementorClass);
635: }
636: return seiClass;
637: }
638:
639: private Configuration createConfiguration() {
640:
641: Configuration busCfg = bus.getConfiguration();
642: if (null == busCfg) {
643: return null;
644: }
645:
646: Configuration cfg = null;
647: String id = EndpointReferenceUtils.getServiceName(reference)
648: .toString();
649: ConfigurationBuilder cb = ConfigurationBuilderFactory
650: .getBuilder(null);
651: cfg = cb.getConfiguration(ENDPOINT_CONFIGURATION_URI, id,
652: busCfg);
653: if (null == cfg) {
654: cfg = cb.buildConfiguration(ENDPOINT_CONFIGURATION_URI, id,
655: busCfg);
656: }
657: return cfg;
658: }
659:
660: private ClassLoader getContextInspectorClassLoader() {
661: return getClass().getClassLoader();
662: }
663:
664: void start() {
665: if (published) {
666: return;
667: } else {
668: try {
669: serverBinding.activate();
670: published = true;
671: } catch (IOException e) {
672: //e.printStackTrace();
673: } catch (WSDLException e) {
674: //e.printStackTrace();
675: }
676: }
677: }
678:
679: public Map<QName, ? extends DataBindingCallback> getOperations() {
680: return callbackMap;
681: }
682:
683: public Style getStyle() {
684: javax.jws.soap.SOAPBinding bind = implementorClass
685: .getAnnotation(javax.jws.soap.SOAPBinding.class);
686: if (bind != null) {
687: return bind.style();
688: }
689: return javax.jws.soap.SOAPBinding.Style.DOCUMENT;
690: }
691:
692: }
|