001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036:
037: package com.sun.xml.ws.api.server;
038:
039: import com.sun.istack.NotNull;
040: import com.sun.istack.Nullable;
041: import com.sun.xml.ws.api.BindingID;
042: import com.sun.xml.ws.api.WSBinding;
043: import com.sun.xml.ws.api.message.Message;
044: import com.sun.xml.ws.api.message.Packet;
045: import com.sun.xml.ws.api.model.SEIModel;
046: import com.sun.xml.ws.api.model.wsdl.WSDLPort;
047: import com.sun.xml.ws.api.pipe.Codec;
048: import com.sun.xml.ws.api.pipe.Engine;
049: import com.sun.xml.ws.api.pipe.FiberContextSwitchInterceptor;
050: import com.sun.xml.ws.api.pipe.ServerTubeAssemblerContext;
051: import com.sun.xml.ws.api.pipe.Tube;
052: import com.sun.xml.ws.server.EndpointFactory;
053: import com.sun.xml.ws.util.xml.XmlUtil;
054: import org.xml.sax.EntityResolver;
055:
056: import javax.xml.namespace.QName;
057: import javax.xml.ws.Binding;
058: import javax.xml.ws.WebServiceContext;
059: import javax.xml.ws.WebServiceException;
060: import java.net.URL;
061: import java.util.Collection;
062: import java.util.Set;
063: import java.util.concurrent.Executor;
064:
065: /**
066: * Root object that hosts the {@link Packet} processing code
067: * at the server.
068: *
069: * <p>
070: * One instance of {@link WSEndpoint} is created for each deployed service
071: * endpoint. A hosted service usually handles multiple concurrent
072: * requests. To do this efficiently, an endpoint handles incoming
073: * {@link Packet} through {@link PipeHead}s, where many copies can be created
074: * for each endpoint.
075: *
076: * <p>
077: * Each {@link PipeHead} is thread-unsafe, and request needs to be
078: * serialized. A {@link PipeHead} represents a sizable resource
079: * (in particular a whole pipeline), so the caller is expected to
080: * reuse them and avoid excessive allocations as much as possible.
081: * Making {@link PipeHead}s thread-unsafe allow the JAX-WS RI internal to
082: * tie thread-local resources to {@link PipeHead}, and reduce the total
083: * resource management overhead.
084: *
085: * <p>
086: * To abbreviate this resource management (and for a few other reasons),
087: * JAX-WS RI provides {@link Adapter} class. If you are hosting a JAX-WS
088: * service, you'll most likely want to send requests to {@link WSEndpoint}
089: * through {@link Adapter}.
090: *
091: * <p>
092: * {@link WSEndpoint} is ready to handle {@link Packet}s as soon as
093: * it's created. No separate post-initialization step is necessary.
094: * However, to comply with the JAX-WS spec requirement, the caller
095: * is expected to call the {@link #dispose()} method to allow an
096: * orderly shut-down of a hosted service.
097: *
098: *
099: *
100: * <h3>Objects Exposed From Endpoint</h3>
101: * <p>
102: * {@link WSEndpoint} exposes a series of information that represents
103: * how an endpoint is configured to host a service. See the getXXX methods
104: * for more details.
105: *
106: *
107: *
108: * <h3>Implementation Notes</h3>
109: * <p>
110: * {@link WSEndpoint} owns a {@link WSWebServiceContext} implementation.
111: * But a bulk of the work is delegated to {@link WebServiceContextDelegate},
112: * which is passed in as a parameter to {@link PipeHead#process(Packet, WebServiceContextDelegate, TransportBackChannel)}.
113: *
114: * @author Kohsuke Kawaguchi
115: */
116: public abstract class WSEndpoint<T> {
117:
118: /**
119: * Gets the Endpoint's codec that is used to encode/decode {@link Message}s. This is a
120: * copy of the master codec and it shouldn't be shared across two requests running
121: * concurrently(unless it is stateless).
122: *
123: * @return codec to encode/decode
124: */
125: public abstract @NotNull
126: Codec createCodec();
127:
128: /**
129: * Gets the application endpoint's serviceName. It could be got from DD or annotations
130: *
131: * @return same as wsdl:service QName if WSDL exists or generated
132: */
133: public abstract @NotNull
134: QName getServiceName();
135:
136: /**
137: * Gets the application endpoint's portName. It could be got from DD or annotations
138: *
139: * @return same as wsdl:port QName if WSDL exists or generated
140: */
141: public abstract @NotNull
142: QName getPortName();
143:
144: /**
145: * Gets the application endpoint {@link Class} that eventually serves the request.
146: *
147: * <p>
148: * This is the same value given to the {@link #create} method.
149: */
150: public abstract @NotNull
151: Class<T> getImplementationClass();
152:
153: /**
154: * Represents the binding for which this {@link WSEndpoint}
155: * is created for.
156: *
157: * @return
158: * always same object.
159: */
160: public abstract @NotNull
161: WSBinding getBinding();
162:
163: /**
164: * Gets the {@link Container} object.
165: *
166: * <p>
167: * The components inside {@link WSEndpoint} uses this reference
168: * to communicate with the hosting environment.
169: *
170: * @return
171: * always same object. If no "real" {@link Container} instance
172: * is given, {@link Container#NONE} will be returned.
173: */
174: public abstract @NotNull
175: Container getContainer();
176:
177: /**
178: * Gets the port that this endpoint is serving.
179: *
180: * <p>
181: * A service is not required to have a WSDL, and when it doesn't,
182: * this method returns null. Otherwise it returns an object that
183: * describes the port that this {@link WSEndpoint} is serving.
184: *
185: * @return
186: * Possibly null, but always the same value.
187: */
188: public abstract @Nullable
189: WSDLPort getPort();
190:
191: /**
192: * Set this {@link Executor} to run asynchronous requests using this executor.
193: * This executor is set on {@link Engine} and must be set before
194: * calling {@link #schedule(Packet,CompletionCallback) } and
195: * {@link #schedule(Packet,CompletionCallback,FiberContextSwitchInterceptor)} methods.
196: *
197: * @param exec Executor to run async requests
198: */
199: public abstract void setExecutor(@NotNull
200: Executor exec);
201:
202: /**
203: * This method takes a {@link Packet} that represents
204: * a request, run it through a {@link Tube}line, eventually
205: * pass it to the user implementation code, which produces
206: * a reply, then run that through the tubeline again,
207: * and eventually return it as a return value through {@link CompletionCallback}.
208: *
209: * <p>
210: * This takes care of pooling of {@link Tube}lines and reuses
211: * tubeline for requests. Same instance of tubeline is not used concurrently
212: * for two requests.
213: *
214: * <p>
215: * If the transport is capable of asynchronous execution, use this
216: * instead of using {@link PipeHead#process}.
217: *
218: * <p>
219: * Before calling this method, set the executor using {@link #setExecutor}. The
220: * executor may used multiple times to run this request in a asynchronous fashion.
221: * The calling thread will be returned immediately, and the callback will be
222: * called in a different a thread.
223: *
224: * <p>
225: * {@link Packet#transportBackChannel} should have the correct value, so that
226: * one-way message processing happens correctly. {@link Packet#webServiceContextDelegate}
227: * should have the correct value, so that some {@link WebServiceContext} methods correctly.
228: *
229: * @see {@link Packet#transportBackChannel}
230: * @see {@link Packet#webServiceContextDelegate}
231: *
232: * @param request web service request
233: * @param callback callback to get response packet
234: */
235: public final void schedule(@NotNull
236: Packet request, @NotNull
237: CompletionCallback callback) {
238: schedule(request, callback, null);
239: }
240:
241: /**
242: * Schedule invocation of web service asynchronously.
243: *
244: * @see {@link #schedule(Packet, CompletionCallback)}
245: *
246: * @param request web service request
247: * @param callback callback to get response packet(exception if there is one)
248: * @param interceptor caller's interceptor to impose a context of execution
249: */
250: public abstract void schedule(@NotNull
251: Packet request, @NotNull
252: CompletionCallback callback, @Nullable
253: FiberContextSwitchInterceptor interceptor);
254:
255: /**
256: * Callback to notify that jax-ws runtime has finished execution of a request
257: * submitted via schedule().
258: */
259: public interface CompletionCallback {
260: /**
261: * Indicates that the jax-ws runtime has finished execution of a request
262: * submitted via schedule().
263: *
264: * <p>
265: * Since the JAX-WS RI runs asynchronously,
266: * this method maybe invoked by a different thread
267: * than any of the threads that started it or run a part of tubeline.
268: *
269: * @param response {@link Packet}
270: */
271: void onCompletion(@NotNull
272: Packet response);
273: }
274:
275: /**
276: * Creates a new {@link PipeHead} to process
277: * incoming requests.
278: *
279: * <p>
280: * This is not a cheap operation. The caller is expected
281: * to reuse the returned {@link PipeHead}. See
282: * {@link WSEndpoint class javadoc} for details.
283: *
284: * @return
285: * A newly created {@link PipeHead} that's ready to serve.
286: */
287: public abstract @NotNull
288: PipeHead createPipeHead();
289:
290: /**
291: * Represents a resource local to a thread.
292: *
293: * See {@link WSEndpoint} class javadoc for more discussion about
294: * this.
295: */
296: public interface PipeHead {
297: /**
298: * Processes a request and produces a reply.
299: *
300: * <p>
301: * This method takes a {@link Packet} that represents
302: * a request, run it through a {@link Tube}line, eventually
303: * pass it to the user implementation code, which produces
304: * a reply, then run that through the pipeline again,
305: * and eventually return it as a return value.
306: *
307: * @param request
308: * Unconsumed {@link Packet} that represents
309: * a request.
310: * @param wscd
311: * {@link WebServiceContextDelegate} to be set to {@link Packet}.
312: * (we didn't have to take this and instead just ask the caller to
313: * set to {@link Packet#webServiceContextDelegate}, but that felt
314: * too error prone.)
315: * @param tbc
316: * {@link TransportBackChannel} to be set to {@link Packet}.
317: * See the {@code wscd} parameter javadoc for why this is a parameter.
318: * Can be null.
319: * @return
320: * Unconsumed {@link Packet} that represents
321: * a reply to the request.
322: *
323: * @throws WebServiceException
324: * This method <b>does not</b> throw a {@link WebServiceException}.
325: * The {@link WSEndpoint} must always produce a fault {@link Message}
326: * for it.
327: *
328: * @throws RuntimeException
329: * A {@link RuntimeException} thrown from this method, including
330: * {@link WebServiceException}, must be treated as a bug in the
331: * code (including JAX-WS and all the pipe implementations), not
332: * an operator error by the user.
333: *
334: * <p>
335: * Therefore, it should be recorded by the caller in a way that
336: * allows developers to fix a bug.
337: */
338: @NotNull
339: Packet process(@NotNull
340: Packet request, @Nullable
341: WebServiceContextDelegate wscd, @Nullable
342: TransportBackChannel tbc);
343: }
344:
345: /**
346: * Indicates that the {@link WSEndpoint} is about to be turned off,
347: * and will no longer serve any packet anymore.
348: *
349: * <p>
350: * This method needs to be invoked for the JAX-WS RI to correctly
351: * implement some of the spec semantics (TODO: pointer.)
352: * It's the responsibility of the code that hosts a {@link WSEndpoint}
353: * to invoke this method.
354: *
355: * <p>
356: * Once this method is called, the behavior is undefed for
357: * all in-progress {@link PipeHead#process} methods (by other threads)
358: * and future {@link PipeHead#process} method invocations.
359: */
360: public abstract void dispose();
361:
362: /**
363: * Gets the description of the service.
364: *
365: * <p>
366: * A description is a set of WSDL/schema and other documents that together
367: * describes a service.
368: * A service is not required to have a description, and when it doesn't,
369: * this method returns null.
370: *
371: * @return
372: * Possibly null, but always the same value.
373: */
374: public abstract @Nullable
375: ServiceDefinition getServiceDefinition();
376:
377: /**
378: * Gets the list of {@link EndpointComponent} that are associated
379: * with this endpoint.
380: *
381: * <p>
382: * Components (such as codec, tube, handler, etc) who wish to provide
383: * some service to other components in the endpoint can iterate the
384: * registry and call its {@link EndpointComponent#getSPI(Class)} to
385: * establish a private contract between components.
386: * <p>
387: * Components who wish to subscribe to such a service can add itself
388: * to this set.
389: *
390: * @return
391: * always return the same set.
392: */
393: public abstract @NotNull
394: Set<EndpointComponent> getComponentRegistry();
395:
396: /**
397: * Gets the {@link com.sun.xml.ws.api.model.SEIModel} that represents the relationship
398: * between WSDL and Java SEI.
399: *
400: * <p>
401: * This method returns a non-null value if and only if this
402: * endpoint is ultimately serving an application through an SEI.
403: *
404: * @return
405: * maybe null. See above for more discussion.
406: * Always the same value.
407: */
408: public abstract @Nullable
409: SEIModel getSEIModel();
410:
411: /**
412: * Creates an endpoint from deployment or programmatic configuration
413: *
414: * <p>
415: * This method works like the following:
416: * <ol>
417: * <li>{@link ServiceDefinition} is modeleed from the given SEI type.
418: * <li>{@link Invoker} that always serves <tt>implementationObject</tt> will be used.
419: * </ol>
420: * @param implType
421: * Endpoint class(not SEI). Enpoint class must have @WebService or @WebServiceProvider
422: * annotation.
423: * @param processHandlerAnnotation
424: * Flag to control processing of @HandlerChain on Impl class
425: * if true, processes @HandlerChain on Impl
426: * if false, DD might have set HandlerChain no need to parse.
427: * @param invoker
428: * Pass an object to invoke the actual endpoint object. If it is null, a default
429: * invoker is created using {@link InstanceResolver#createDefault}. Appservers
430: * could create its own invoker to do additional functions like transactions,
431: * invoking the endpoint through proxy etc.
432: * @param serviceName
433: * Optional service name(may be from DD) to override the one given by the
434: * implementation class. If it is null, it will be derived from annotations.
435: * @param portName
436: * Optional port name(may be from DD) to override the one given by the
437: * implementation class. If it is null, it will be derived from annotations.
438: * @param container
439: * Allows technologies that are built on top of JAX-WS(such as WSIT) needs to
440: * negotiate private contracts between them and the container
441: * @param binding
442: * JAX-WS implementation of {@link Binding}. This object can be created by
443: * {@link BindingID#createBinding()}. Usually the binding can be got from
444: * DD, {@link javax.xml.ws.BindingType}.
445: *
446: *
447: * TODO: DD has a configuration for MTOM threshold.
448: * Maybe we need something more generic so that other technologies
449: * like Tango can get information from DD.
450: *
451: * TODO: does it really make sense for this to take EntityResolver?
452: * Given that all metadata has to be given as a list anyway.
453: *
454: * @param primaryWsdl
455: * The {@link ServiceDefinition#getPrimary() primary} WSDL.
456: * If null, it'll be generated based on the SEI (if this is an SEI)
457: * or no WSDL is associated (if it's a provider.)
458: * TODO: shouldn't the implementation find this from the metadata list?
459: * @param metadata
460: * Other documents that become {@link SDDocument}s. Can be null.
461: * @param resolver
462: * Optional resolver used to de-reference resources referenced from
463: * WSDL. Must be null if the {@code url} is null.
464: * @param isTransportSynchronous
465: * If the caller knows that the returned {@link WSEndpoint} is going to be
466: * used by a synchronous-only transport, then it may pass in <tt>true</tt>
467: * to allow the callee to perform an optimization based on that knowledge
468: * (since often synchronous version is cheaper than an asynchronous version.)
469: * This value is visible from {@link ServerTubeAssemblerContext#isSynchronous()}.
470: *
471: * @return newly constructed {@link WSEndpoint}.
472: * @throws WebServiceException
473: * if the endpoint set up fails.
474: */
475: public static <T> WSEndpoint<T> create(@NotNull
476: Class<T> implType, boolean processHandlerAnnotation, @Nullable
477: Invoker invoker, @Nullable
478: QName serviceName, @Nullable
479: QName portName, @Nullable
480: Container container, @Nullable
481: WSBinding binding, @Nullable
482: SDDocumentSource primaryWsdl, @Nullable
483: Collection<? extends SDDocumentSource> metadata, @Nullable
484: EntityResolver resolver, boolean isTransportSynchronous) {
485: return EndpointFactory.createEndpoint(implType,
486: processHandlerAnnotation, invoker, serviceName,
487: portName, container, binding, primaryWsdl, metadata,
488: resolver, isTransportSynchronous);
489: }
490:
491: /**
492: * Deprecated version that assumes <tt>isTransportSynchronous==false</tt>
493: */
494: @Deprecated
495: public static <T> WSEndpoint<T> create(@NotNull
496: Class<T> implType, boolean processHandlerAnnotation, @Nullable
497: Invoker invoker, @Nullable
498: QName serviceName, @Nullable
499: QName portName, @Nullable
500: Container container, @Nullable
501: WSBinding binding, @Nullable
502: SDDocumentSource primaryWsdl, @Nullable
503: Collection<? extends SDDocumentSource> metadata, @Nullable
504: EntityResolver resolver) {
505: return create(implType, processHandlerAnnotation, invoker,
506: serviceName, portName, container, binding, primaryWsdl,
507: metadata, resolver, false);
508: }
509:
510: /**
511: * The same as
512: * {@link #create(Class, boolean, Invoker, QName, QName, Container, WSBinding, SDDocumentSource, Collection, EntityResolver)}
513: * except that this version takes an url of the <tt>jax-ws-catalog.xml</tt>.
514: *
515: * @param catalogUrl
516: * if not null, an {@link EntityResolver} is created from it and used.
517: * otherwise no resolution will be performed.
518: */
519: public static <T> WSEndpoint<T> create(@NotNull
520: Class<T> implType, boolean processHandlerAnnotation, @Nullable
521: Invoker invoker, @Nullable
522: QName serviceName, @Nullable
523: QName portName, @Nullable
524: Container container, @Nullable
525: WSBinding binding, @Nullable
526: SDDocumentSource primaryWsdl, @Nullable
527: Collection<? extends SDDocumentSource> metadata, @Nullable
528: URL catalogUrl) {
529: return create(implType, processHandlerAnnotation, invoker,
530: serviceName, portName, container, binding, primaryWsdl,
531: metadata, XmlUtil.createEntityResolver(catalogUrl),
532: false);
533: }
534:
535: /**
536: * Gives the wsdl:service default name computed from the endpoint implementaiton class
537: */
538: public static @NotNull
539: QName getDefaultServiceName(Class endpointClass) {
540: return EndpointFactory.getDefaultServiceName(endpointClass);
541: }
542:
543: /**
544: * Gives the wsdl:service/wsdl:port default name computed from the endpoint implementaiton class
545: */
546: public static @NotNull
547: QName getDefaultPortName(@NotNull
548: QName serviceName, Class endpointClass) {
549: return EndpointFactory.getDefaultPortName(serviceName,
550: endpointClass);
551: }
552:
553: }
|