/* * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.xml.internal.ws.developer; import com.sun.istack.internal.NotNull; import com.sun.istack.internal.Nullable; import com.sun.xml.internal.ws.api.message.Packet; import com.sun.xml.internal.ws.api.pipe.Tube; import com.sun.xml.internal.ws.api.server.AsyncProvider; import com.sun.xml.internal.ws.api.server.AsyncProviderCallback; import javax.annotation.Resource; import javax.jws.WebMethod; import javax.jws.WebService; import javax.xml.ws.EndpointReference; import javax.xml.ws.WebServiceContext; import javax.xml.ws.WebServiceException; import javax.xml.ws.wsaddressing.W3CEndpointReference; /** * Stateful web service support in the JAX-WS RI. * * <h2>Usage</h2> * <p> * Application service implementation classes (or providers) who'd like * to use the stateful web service support must declare {@link Stateful} * annotation on a class. It should also have a <b>public static</b> method/field * that takes {@link StatefulWebServiceManager}. * * <pre> * @{@link Stateful} @{@link WebService} * class BankAccount { * protected final int id; * private int balance; * * BankAccount(int id) { this.id = id; } * @{@link WebMethod} * public synchronized void deposit(int amount) { balance+=amount; } * * // either via a public static field * <font color=red> * public static {@link StatefulWebServiceManager}<BankAccount> manager; * </font> * // ... or via a public static method (the method name could be anything) * <font color=red> * public static void setManager({@link StatefulWebServiceManager}<BankAccount> manager) { * ... * } * </font> * } * </pre> * * <p> * After your service is deployed but before you receive a first request, * the resource injection occurs on the field or the method. * * <p> * A stateful web service class does not need to have a default constructor. * In fact, most of the time you want to define a constructor that takes * some arguments, so that each instance carries certain state (as illustrated * in the above example.) * * <p> * Each instance of a stateful web service class is identified by an unique * {@link EndpointReference}. Your application creates an instance of * a class, then you'll have the JAX-WS RI assign this unique EPR for the * instance as follows: * * <pre> * @{@link WebService} * class Bank { // this is ordinary stateless service * @{@link WebMethod} * public synchronized W3CEndpointReference login(int accountId, int pin) { * if(!checkPin(pin)) * throw new AuthenticationFailedException("invalid pin"); * BankAccount acc = new BankAccount(accountId); * return BankAccount.manager.{@link #export export}(acc); * } * } * </pre> * * <p> * Typically you then pass this EPR to remote systems. When they send * messages to this EPR, the JAX-WS RI makes sure that the particular exported * instance associated with that EPR will receive a service invocation. * * <h2>Things To Consider</h2> * <p> * When you no longer need to tie an instance to the EPR, * use {@link #unexport(Object)} so that the object can be GC-ed * (or else you'll leak memory.) You may choose to do so explicitly, * or you can rely on the time out by using {@link #setTimeout(long, Callback)}. * * <p> * {@link StatefulWebServiceManager} is thread-safe. It can be safely * invoked from multiple threads concurrently. * * @author Kohsuke Kawaguchi * @see StatefulFeature * @since 2.1 */ public interface StatefulWebServiceManager<T> { /** * Exports an object. * * <p> * This method works like {@link #export(Object)} except that * you can obtain the EPR in your choice of addressing version, * by passing in the suitable <tt>epr</tt> parameter. * * @param epr * Either {@link W3CEndpointReference} or {@link MemberSubmissionEndpointReference}. * If other types are specified, this method throws an {@link WebServiceException}. * @return * {@link EndpointReference}-subclass that identifies this exported * object. */ @NotNull <EPR extends EndpointReference> EPR export(Class<EPR> epr, T o); /** * Exports an object. * * <p> * This method works like {@link #export(Object)} except that * you can obtain the EPR in your choice of addressing version, * by passing in the suitable <tt>epr</tt> parameter. * * @param epr * Either {@link W3CEndpointReference} or {@link MemberSubmissionEndpointReference}. * If other types are specified, this method throws an {@link WebServiceException}. * @param o * The object to be exported, whose identity be referenced by the returned EPR. * @param recipe * The additional data to be put into EPR. Can be null. * @return * {@link EndpointReference}-subclass that identifies this exported * object. * @since 2.1.1 */ @NotNull <EPR extends EndpointReference> EPR export(Class<EPR> epr, T o, @Nullable EPRRecipe recipe ); /** * Exports an object. * * <p> * JAX-WS RI assigns an unique EPR to the exported object, * and from now on, messages that are sent to this EPR will * be routed to the given object. * * <p> * The object will be locked in memory, so be sure to * {@link #unexport(Object) unexport} it when it's no longer needed. * * <p> * Notice that the obtained EPR contains the address of the service, * which depends on the currently processed request. So invoking * this method multiple times with the same object may return * different EPRs, if such multiple invocations are done while * servicing different requests. (Of course all such EPRs point * to the same object, so messages sent to those EPRs will be * served by the same instance.) * * @return * {@link W3CEndpointReference} that identifies this exported * object. Always non-null. */ @NotNull W3CEndpointReference export(T o); /** * Exports an object (for {@link AsyncProvider asynchronous web services}.) * * <p> * This method works like {@link #export(Class,Object)} but it * takes an extra {@link WebServiceContext} that represents the request currently * being processed by the caller (the JAX-WS RI remembers this when the service * processing is synchronous, and that's why this parameter is only needed for * asynchronous web services.) * * <h3>Why {@link WebServiceContext} is needed?</h3> * <p> * The obtained EPR contains address, such as host name. The server does not * know what its own host name is (or there are more than one of them), * so this value is determined by what the current client thinks the server name is. * This is why we need to take {@link WebServiceContext}. Pass in the * object given to {@link AsyncProvider#invoke(Object, AsyncProviderCallback,WebServiceContext)}. */ @NotNull <EPR extends EndpointReference> EPR export(Class<EPR> eprType, @NotNull WebServiceContext context, T o); /** * Exports an object. * * <p> * <b>This method is not meant for application code.</b> * This is for {@link Tube}s that wish to use stateful web service support. * * @param currentRequest * The request that we are currently processing. This is used to infer the address in EPR. * @see #export(Class, WebServiceContext, Object) */ @NotNull <EPR extends EndpointReference> EPR export(Class<EPR> eprType, @NotNull Packet currentRequest, T o); /** * The same as {@link #export(Class, Packet, Object)} except * that it takes {@link EPRRecipe}. * * @param recipe * See {@link #export(Class, Object, EPRRecipe)}. */ @NotNull <EPR extends EndpointReference> EPR export(Class<EPR> eprType, @NotNull Packet currentRequest, T o, EPRRecipe recipe); /** * Exports an object. * * @deprecated * This method is provided as a temporary workaround, and we'll eventually try to remove it. * * @param endpointAddress * The endpoint address URL. Normally, this information is determined by other inputs, * like {@link Packet} or {@link WebServiceContext}. */ @NotNull <EPR extends EndpointReference> EPR export(Class<EPR> eprType, String endpointAddress, T o); /** * Unexports the given instance. * * <p> * JAX-WS will release a strong reference to unexported objects, * and they will never receive further requests (requests targeted * for those unexported objects will be served by the fallback object.) * * @param o * if null, this method will be no-op. */ void unexport(@Nullable T o); /** * Checks if the given EPR represents an object that has been exported from this manager. * * <p> * This method can be used to have two endpoints in the same application communicate * locally. * * @return null if the EPR is not exported from this manager. */ @Nullable T resolve(@NotNull EndpointReference epr); /** * Sets the "fallback" instance. * * <p> * When the incoming request does not have the necessary header to * distinguish instances of <tt>T</tt>, or when the header is present * but its value does not correspond with any of the active exported * instances known to the JAX-WS, then the JAX-WS RI will try to * route the request to the fallback instance. * * <p> * This provides the application an opportunity to perform application * specific error recovery. * * <p> * If no fallback instance is provided, then the JAX-WS RI will * send back the fault. By default, no fallback instance is set. * * <p> * This method can be invoked any time, but most often you'd like to * use one instance at the get-go. The following code example * illustrates how to do this: * * <pre> * @{@link WebService} * class BankAccount { * ... continuting from the example in class javadoc ... * * @{@link Resource} static void setManager({@link StatefulWebServiceManager} manager) { * manager.setFallbackInstance(new BankAccount(0) { * @{@link Override} * void deposit(int amount) { * putToAuditRecord(id); * if(thisLooksBad()) callPolice(); * throw new {@link WebServiceException}("No such bank account exists"); * } * }); * } * } * </pre> * * @param o * Can be null. */ void setFallbackInstance(T o); /** * Configures timeout for exported instances. * * <p> * When configured, the JAX-WS RI will internally use a timer * so that exported objects that have not received any request * for the given amount of minutes will be automatically unexported. * * <p> * At some point after the time out has occurred for an instance, * the JAX-WS RI will invoke the {@link Callback} to notify the application * that the time out has reached. Application then has a choice of * either let the object go unexported, or {@link #touch(Object) touch} * let the object live for another round of timer interval. * * <p> * If no callback is set, the expired object will automatically unexported. * * <p> * When you call this method multiple times, its effect on existing * instances are unspecified, although deterministic. * * @param milliseconds * The time out interval. Specify 0 to cancel the timeout timer. * Note that this only guarantees that time out does not occur * at least until this amount of time has elapsed. It does not * guarantee that the time out will always happen right after * the timeout is reached. * @param callback * application may choose to install a callback to control the * timeout behavior. */ void setTimeout(long milliseconds, @Nullable Callback<T> callback); /** * Resets the time out timer for the given instance. * * <p> * If the object is null, not exported, or already unexported, this * method will be no-op. */ void touch(T o); /** * Used by {@link StatefulWebServiceManager#setTimeout(long, Callback)} * to determine what to do when the time out is reached. */ interface Callback<T> { /** * Application has a chance to decide if the object should be unexported, * or kept alive. * * <p> * The application should either unexport the object, or touch the object * from within this callback. * If no action is taken, the object will remain exported until it is * manually unexported. * * @param timedOutObject * The object that reached the time out. * @param manager * The manager instance that you exported the object to. */ void onTimeout(@NotNull T timedOutObject, @NotNull StatefulWebServiceManager<T> manager); } }