/* * Copyright 2008-2010 Brian S O'Neill * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.cojen.dirmi; import java.lang.annotation.*; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; /** * Remote method timeout policy annotation, which can target a remote interface * or method. When annotated at the interface level, it defines default timeout * values for all methods. Any method can override the defaults with its own * annotation. The timeout annotation can be used with {@link TimeoutUnit} to * define the unit. If not specified, it defaults to milliseconds. * * <p>Timeouts only apply to the caller of a remote method. If the timeout has * elapsed without a response from the remote endpoint, the connection is * forcibly closed and a {@link RemoteTimeoutException} is thrown. When this * happens, no special action is automatically applied on the remote side to * interrupt any work in progress. The actual method implementation is * responsible for this. If it completes its work and returns after a timeout, * the response is discarded. * * <p>When a {@link RemoteTimeoutException} is thrown, it does not indicate * whether the remote endpoint actually received the request or not. Care must * be taken when attempting to retry a failed remote invocation, especially if * not idempotent. {@link Asynchronous} methods with callbacks can provide more * information regarding successful invocation, but timeouts on asynchronous * methods alone offer less utility. This is because the timeout on an * asynchronous method only applies to the sending of the request. It does not * wait for method completion. When using the {@link CallMode#ACKNOWLEDGED * acknowledged} calling mode, timeouts do at least wait for acknowledgement. * Consider returning a {@link Future} and call the {@code get} method which * accepts a timeout. * * <p>Method parameters may use the {@link TimeoutParam} annotation to specify * timeout values and units. When applied to a primitive numeric type (which * can be boxed), it specifies the timeout value. At most one parameter can be * a timeout value. When the annotation is applied to a parameter of type * {@link TimeUnit}, it specifies the timeout unit. Likewise, at most one * parameter can be a timeout unit. If no parameter is annotated as a timeout * unit but the parameter immediately following the timeout value is a {@code * TimeUnit}, it is automatically chosen as the timeout unit parameter. * * <p>Remote method implementations may make use of timeout parameters to * interrupt any work in progress, under the assumption that the caller has * given up after the timeout has elapsed. * * <p>Timeout parameters can have runtime values of null, in which case default * timeouts apply. These defaults are defined by any method and interface level * timeout annotations. If none, then the default timeout value is infinite and * the unit is milliseconds. In either case, the remote endpoint sees the * applied values instead of null. If the timeout value cannot be cast to the * parameter type without loss of magnitude, -1 (infinite) is passed instead. * * <pre> * // 10 second timeout for all methods by default. * <b>@Timeout(10)</b> * // If unit was not specified, milliseconds is assumed. * <b>@TimeoutUnit(TimeUnit.SECONDS)</b> * public interface MyRemote extends Remote { * // Default 10 second timeout applies. * String getItemName(String id) throws RemoteException; * * // Override with a 20 second timeout. * <b>@Timeout(20)</b> * String getItemDescription(String id) throws RemoteException; * * // Override with a 100 millisecond timeout. * <b>@Timeout(100)</b> * <b>@TimeoutUnit(TimeUnit.MILLISECONDS)</b> * String disableItem(String id) throws RemoteException; * * // A parameter is passed to define the timeout, overriding the default. * // The timeout unit is seconds, as defined by the interface level annotation. * void runReport(String param, <b>@TimeoutParam</b> int timeout) throws RemoteException; * * // A parameter and unit is passed to define the timeout. If runtime unit is * // is null, it defaults to minutes. * <b>@TimeoutUnit(TimeUnit.MINUTES)</b> * void runReport(String param, <b>@TimeoutParam</b> int timeout, TimeUnit unit) * throws RemoteException; * * // The timeout parameter is explicitly annotated, because of its non-standard * // argument position. If runtime unit is null, seconds is assumed because * // of interface level annotation. * void runReport(String param, <b>@TimeoutParam</b> TimeUnit unit, <b>@TimeoutParam</b> int timeout) * throws RemoteException; * } * </pre> * * @author Brian S O'Neill * @see TimeoutUnit * @see TimeoutParam */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) public @interface Timeout { /** * Specify the timeout duration. Any negative value indicates an infinite * timeout. */ long value(); }