/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you 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 net.jini.lease;

import java.rmi.MarshalledObject;
import java.rmi.RemoteException;
import net.jini.core.event.EventRegistration;
import net.jini.core.event.RemoteEventListener;
import net.jini.core.lease.Lease;

/**
 * A collection of leases being managed by a lease renewal service.
 * <p>
 * Clients of the renewal service organize the leases they wish to
 * have renewed into <em>lease renewal sets</em> (or <em>sets</em>,
 * for short). These sets are represented by objects implementing this
 * interface. The
 * <code>LeaseRenewalService.createLeaseRenewalSet</code> method is
 * provided to create sets. Sets are populated by methods on the sets
 * themselves. Two leases in the same set need not be granted by the
 * same service or have the same expiration time; in addition, they
 * can be added or removed from the set independently.
 * <p>
 * This interface is not a remote interface; each implementation of the
 * renewal service exports proxy objects that implement the
 * <code>LeaseRenewalSet</code> interface that use an
 * implementation-specific protocol to communicate with the actual
 * remote server. All of the proxy methods obey normal RMI remote
 * interface semantics except where explicitly noted. Two proxy objects
 * are equal if they are proxies for the same set created by the same
 * renewal service. Every method invocation (on both a
 * <code>LeaseRenewalService</code> and all the
 * <code>LeaseRenewalSet</code> instances created by that server) is
 * atomic with respect to other invocations.
 * <p>
 * A number of the methods in this class throw
 * <code>RemoteException</code>, each of these may throw the
 * <code>java.rmi.NoSuchObjectException</code> subclass. If a client
 * receives a <code>NoSuchObjectException</code> when calling a method
 * on a renewal set, the client can infer that the set has been
 * destroyed; however, it should not infer that the renewal service
 * has been destroyed.
 * <p>
 * The term <em>client lease</em> is used to refer to a lease that has
 * been placed into a renewal set. Client leases are distinct from the
 * leases that the renewal service grants on renewal sets it has
 * created.
 * <p>
 * Each client lease has two expiration related times associated with
 * it: the <em>desired expiration</em> time for the lease, and the
 * <em>actual expiration</em> time granted when the lease was created
 * or last renewed. The desired expiration represents when the client
 * would like the lease to expire. The actual expiration represents
 * when the lease is going to expire if it is not renewed. Both time
 * values are absolute times, not relative time durations. When a
 * client lease's desired expiration arrives, the lease will be
 * removed from the set without further client intervention.
 * <p>
 * Each client lease also has two other associated attributes: a
 * desired <em>renewal duration</em> and a <em>remaining desired
 * duration</em>. The desired renewal duration is specified by the
 * client (directly or indirectly) when the lease is added to the
 * set. This duration must normally be a positive number, however, it
 * may be <code>Lease.ANY</code> if the lease's desired expiration is
 * <code>Lease.FOREVER</code>. The remaining desired duration is
 * always the desired expiration less the current time.
 * <p>
 * Each time a client lease is renewed, the renewal service will ask
 * for an extension equal to the lease's renewal duration if the
 * renewal duration is:
 * <ul>
 *     <li> Lease.ANY, or 
 *     <li> less than the remaining desired duration, 
 * </ul>
 * 
 * otherwise, it will ask for an extension equal to the lease's
 * remaining desired duration.
 * <p>
 * If a client lease's actual expiration is later than its desired
 * expiration, the renewal service will not renew the lease; the lease
 * will remain in the set until its desired expiration is reached, the
 * set is destroyed, or it is removed by the client.
 * <p>
 * Each set is leased from the renewal service. If the lease on a set
 * expires or is cancelled, the renewal service will destroy the set
 * and take no further action with regard to the client leases in the
 * set. Each lease renewal set has associated with it an expiration
 * warning event that occurs at a client-specified time before the
 * lease on the set expires. Clients can register for warning events
 * using methods provided by the set. A registration for warning
 * events does not have its own lease, but instead is covered by the
 * same lease under which the set was granted.
 * <p>
 * The term <em>definite exception</em> is used to refer to an
 * exception that could be thrown by an operation on a client lease
 * (such as a remote method call) that would be indicative of a
 * permanent failure of the client lease. For purposes of this
 * document, all bad object exceptions, bad invocation exceptions, and
 * <code>LeaseException</code>s are considered to be definite
 * exceptions.
 * <p>
 * Each lease renewal set has associated with it a renewal failure
 * event that will occur in either of two cases: if any client lease
 * in the set reaches its actual expiration before its desired
 * expiration is reached, or if the renewal service attempts to renew
 * a client lease and gets a definite exception. Clients can register
 * for failure events using methods provided by the set. A
 * registration for failure event does not have its own lease, but
 * instead is covered by the same lease under which the set was
 * granted.
 * <p>
 * Once placed in a set, a client lease will stay there until one or
 * more of the following occurs:
 * <ul>
 *     <li> The lease on the set itself expires or is cancelled,
 *          causing destruction of the set
 *     <li> The client lease is removed by the client
 *     <li> The client lease's actual or desired expiration is reached
 *     <li> A renewal attempt on the client lease results in a
 *          definite exception
 * </ul>
 * <p>
 * Each client lease in a set will be renewed as long as it is in the
 * set. If a renewal call throws an indefinite exception, the renewal
 * service should retry the lease renewal until the lease would
 * otherwise be removed from the set. The renewal service will never
 * cancel a client lease. The preferred method of cancelling a client
 * lease is for the client to first remove the lease from the set and
 * then call cancel on it. It is also permissible for the client to
 * cancel the lease without first removing the lease from the set,
 * although this is likely to result in additional network traffic.
 * <p>
 * Client leases get returned to clients in a number of ways (via
 * <code>remove</code> and <code>getLeases</code> calls, as components
 * of events, etc.). In general, they should have their serial format
 * set to <code>Lease.DURATION</code> before being transferred to the
 * client's virtual machine. In some exceptional circumstances, this
 * may not be possible (for example, the client lease was recovered
 * from persistent storage and could not be deserialized in the
 * server's virtual machine). In these cases, it is acceptable to
 * transfer the lease to the client using the
 * <code>Lease.ABSOLUTE</code> serial format.
 * <p>
 * Whenever a client lease gets returned to a client, its actual
 * expiration should reflect either:
 * <ul>
 *     <li> The result of the last successful renewal call that the
 *          renewal service made or
 *     <li> The expiration time the lease originally had when it was
 *          added to the set, if the renewal service has not yet
 *          successfully renewed the lease
 * </ul>
 * 
 * 
 * @see LeaseRenewalService
 */
public interface LeaseRenewalSet {
    /**
     * The event id for all <code>RenewalFailureEvent</code> objects.
     *
     * @see RenewalFailureEvent
     */
    final static public long RENEWAL_FAILURE_EVENT_ID = 0;

    /**
     * The event id for all <code>ExpirationWarningEvent</code> objects.
     *
     * @see ExpirationWarningEvent
     */
    final static public long EXPIRATION_WARNING_EVENT_ID = 1;

    /**
     * Include a client lease in the set for a specified duration and
     * with a specified renewal duration.
     * <p>
     * The <code>leaseToRenew</code> argument specifies the lease to be
     * added to the set. An <code>IllegalArgumentException</code> must
     * be thrown if the lease was granted by the renewal service
     * itself. If <code>leaseToRenew</code> is <code>null</code>, a
     * <code>NullPointerException</code> must be thrown.
     * <p>
     * The <code>desiredDuration</code> argument is the number of
     * milliseconds the client would like the lease to remain in the
     * set. It is used to calculate the lease's initial desired
     * expiration by adding <code>desiredDuration</code> to the current
     * time (as viewed by the service). If this causes an overflow, a
     * desired expiration of <code>Long.MAX_VALUE</code> will be
     * used. Unlike a lease duration, the desired duration is
     * unilaterally specified by the client, not negotiated between the
     * client and the service. Note, a negative value for
     * <code>desiredDuration</code> (including <code>Lease.ANY</code>)
     * will result in a desired expiration that is in the past, causing
     * <code>leaseToRenew</code> to be dropped from the set; this action
     * will neither result in an exception or an event.
     * <p>
     * If the actual expiration time of <code>leaseToRenew</code> is
     * less than the current time (as viewed by the renewal service) and
     * the current time is less than the desired expiration time for
     * <code>leaseToRenew</code>, the method will return
     * normally. However, <code>leaseToRenew</code> will be dropped from
     * the set and a renewal failure event will be generated.
     * <p>
     * The <code>renewDuration</code> is the initial renewal duration to
     * associate with <code>leaseToRenew</code> (in milliseconds). If
     * <code>desiredDuration</code> is exactly
     * <code>Long.MAX_VALUE</code>, the <code>renewDuration</code> may
     * be any positive number or <code>Lease.ANY</code>; otherwise it
     * must be a positive number. If these requirements are not met, the
     * renewal service must throw an
     * <code>IllegalArgumentException</code>.
     * <p>
     * Calling this method with a lease that is equivalent to a client
     * lease already in the set will associate the existing client lease
     * in the set with the new desired duration and renew duration. The
     * client lease is not replaced because it is more likely that the
     * renewal service, rather than the client, has an up-to-date lease
     * expiration. The service is more likely to have an up-to-date
     * expiration because the client should not be renewing a lease that
     * it has passed to a lease renewal service unless the lease is
     * removed first. These semantics also allow <code>renewFor</code>
     * to be used in an idempotent fashion.
     *
     * @param leaseToRenew the lease to be added to the renewal set
     * @param desiredDuration the maximum length of time in milliseconds
     *	      the <code>leaseToRenew</code> should remain in the set, or
     *	      <code>Lease.FOREVER</code> which implies there is no
     *	      pre-specified time when the lease should be removed from
     *	      the set
     * @param renewDuration the lease duration to request when renewing
     *	      the lease, unless <code>renewDuration</code> is greater
     *	      than the remainder of the <code>desiredDuration</code>
     * @throws IllegalArgumentException if <code>desiredDuration</code>
     *	       is <code>Lease.FOREVER</code>, <code>renewDuration</code>
     *	       is not a positive value, <code>Lease.FOREVER</code>, or
     *	       <code>Lease.ANY</code>. If <code>desiredDuration</code>
     *	       is not <code>Lease.FOREVER</code>,
     *	       <code>IllegalArgumentException</code> will be thrown if
     *	       <code>renewDuration</code> is not a positive value or
     *	       <code>Lease.ANY</code>. <code>IllegalArgumentException</code>
     *	       will also be thrown if <code>leaseToRenew</code> 
     *	       was granted by this renewal service.
     * @throws NullPointerException if <code>leaseToRenew</code> is
     *	       <code>null</code>
     * @throws RemoteException if a communication-related exception
     *	       occurs
     */
    public void renewFor(Lease leaseToRenew, long desiredDuration,
			 long  renewDuration)
	throws RemoteException;

    /**
     * Include a client lease in the set for a specified duration.
     * <p>
     * Calling this method is equivalent to making the following call 
     * on this set:
     *
     * <pre>
     *     renewFor(leaseToRenew, desiredDuration, Lease.FOREVER)
     * </pre>
     *
     * @param leaseToRenew the lease to be added to the renewal set
     * @param desiredDuration the maximum length of time in milliseconds
     *	      the <code>leaseToRenew</code> should remain in the set, or
     *	      <code>Lease.FOREVER</code> which implies there is no
     *	      pre-specified time when the lease should be removed from
     *	      the set
     * @throws IllegalArgumentException if <code>leaseToRenew</code> 
     *	       was granted by this renewal service
     * @throws NullPointerException if <code>leaseToRenew</code> is
     *	       <code>null</code>
     * @throws RemoteException if a communication-related exception
     *	       occurs
     */
    public void renewFor(Lease leaseToRenew, long desiredDuration)
	throws RemoteException;

    /**
     * Removes the specified lease from set. If the lease is currently
     * in the set it will be returned, otherwise <code>null</code> will
     * be returned. <code>leaseToRemove</code> will not be 
     * canceled by this call.
     *
     * @param leaseToRemove lease to be removed from the set
     * @return the removed lease if it was in the set or
     *	       <code>null</code> if it was not
     * @throws NullPointerException if <code>leaseToRemove</code> is
     *	       <code>null</code>
     * @throws RemoteException if a communication-related exception
     *	       occurs
     */
    public Lease remove(Lease leaseToRemove) 
	throws RemoteException;
    
    /**
     * Returns all the leases currently in the set. 
     *
     * @return the leases in the set. Return a zero length array if
     *	       there are not leases currently in the set.
     * @throws LeaseUnmarshalException if one or more of the leases can
     *	       not be unmarshalled. The throwing of a
     *	       <code>LeaseUnmarshalException</code> represents a,
     *	       possibly transient, failure in the ability to unmarshal
     *	       one or more client leases in the set, it does not
     *	       necessarily imply anything about the state of the renewal
     *	       service or the set themselves.
     * @throws RemoteException if a communication-related exception
     *	       occurs
     */
    public Lease[] getLeases() throws LeaseUnmarshalException, RemoteException;

    /**
     * Register for the expiration warning event associated with this
     * set.
     * <p>
     * This method allows the client to register for notification of
     * the approaching expiration of the set's lease. The
     * <code>listener</code> argument specifies what listener should
     * be notified when the lease is about to expire. The
     * <code>minWarning</code> argument specifies a minimum number of
     * milliseconds before lease expiration that the first event
     * delivery attempt should be made by the service. The service may
     * also make subsequent delivery attempts if the first and any
     * subsequent attempts have been indeterminate. The
     * <code>minWarning</code> argument must be zero or a positive
     * number; if it is not, an <code>IllegalArgumentException</code>
     * must be thrown. If the current expiration of the set's lease is
     * less than <code>minWarning</code> milliseconds away, the event
     * will occur immediately (though it will take time to propagate
     * to the listener).
     * <p>
     * The <code>handback</code> argument to this method specifies an
     * object that will be part of the expiration warning event
     * notification. This mechanism is detailed in the Jini
     * Distributed Event Specification.
     * <p>
     * This method returns the event registration for this event. The
     * <code>Lease</code> object associated with the registration will
     * be equivalent (in the sense of <code>equals</code>) to the
     * <code>Lease</code> on the renewal set. Because the event
     * registration shares a lease with the set, clients that want to
     * just remove their expiration warning registration without
     * destroying the set should use the
     * <code>clearExpirationWarningListener</code> method instead of
     * cancelling the registration's lease. The registration's event
     * ID will be
     * <code>LeaseRenewalSet.EXPIRATION_WARNING_EVENT_ID</code>. The
     * source of the registration will be the set. The method must
     * throw a <code>NullPointerException</code> if the
     * <code>listener</code> argument is <code>null</code>. If an
     * event handler has already been specified for this event the
     * current registration is replaced with the new one. Because both
     * registrations are for the same kind of event, the events sent
     * to the new registration must be in the same sequence as the
     * events sent to the old registration.
     *
     * @param listener the listener to be notified when this event
     *	      occurs
     * @param minWarning how long before the lease on the set expires
     *	      should the event be sent
     * @param handback an object to be handed back to the listener when
     *	      the warning event occurs
     * @return an <code>EventRegistration</code> describing the event
     *	       registration
     * @throws IllegalArgumentException if <code>minWarning</code> is
     *	       negative
     * @throws NullPointerException if <code>listener</code> is
     *	       <code>null</code>
     * @throws RemoteException if a communication-related exception
     *	       occurs
     */
    public EventRegistration setExpirationWarningListener(
	                         RemoteEventListener listener, 
				 long                minWarning, 
				 MarshalledObject    handback)
	throws RemoteException;

    /**
     * Remove the listener currently registered for expiration warning
     * events. It is safe to call this method even if no listener is
     * currently registered.
     *
     * @throws RemoteException if a communication-related exception
     *	       occurs
     */
    public void clearExpirationWarningListener()
	throws RemoteException;

    /**
     * Register for the renewal failure event associated with this set.
     * <p>    
     * This method allows the client to register for the event
     * associated with the failure to renew a client lease in the
     * set. These events are generated when a client lease expires
     * while it is still in the set, or when the service attempts to
     * renew a client lease and gets a definite exception. The
     * listener argument specifies the listener to be notified if a
     * client lease could not be renewed.
     * <p>
     * The <code>handback</code> argument specifies an object that
     * will be part of the renewal failure event notification. This
     * mechanism is detailed in the Jini Distributed Event
     * Specification.
     * <p>
     * This method returns the event registration for this event. The
     * <code>Lease</code> object associated with the registration will
     * be equivalent (in the sense of <code>equals</code>) to the
     * <code>Lease</code> on the renewal set. Because the event
     * registration shares a lease with the set, clients that want to
     * just remove their expiration warning registration without
     * destroying the set should use the
     * <code>clearRenewalFailureListener</code> method, instead of
     * cancelling the registration's lease. The registration's event
     * ID will be
     * <code>LeaseRenewalSet.RENEWAL_FAILURE_EVENT_ID</code>. The
     * source of the registration will be the set. The method must
     * throw <code>NullPointerException</code> if the
     * <code>listener</code> argument is <code>null</code>. If an
     * event handler has already been specified for this event the
     * current registration is replaced with the new one. The returned
     * event registration must have the same event ID as the replaced
     * registration. Because both registrations are for the same kind
     * of event, the events sent to the new registration must be in
     * the same sequence as the events sent to the old registration.
     *
     * @param listener the listener to be notified when this event
     *	      occurs
     * @param handback an object to be handed back to the listener when
     *	      the warning event occurs
     * @return an <code>EventRegistration</code> describing the event
     *	      registration
     * @throws NullPointerException if <code>listener</code> is
     *	       <code>null</code>
     * @throws RemoteException if a communication-related exception
     *	       occurs
     */
    public EventRegistration setRenewalFailureListener(
				 RemoteEventListener listener, 
				 MarshalledObject    handback)
	throws RemoteException;

    /**
     * Remove the listener currently registered for renewal failure
     * events. It is safe to call this method even if no listener is
     * currently registered.
     *
     * @throws RemoteException if a communication-related exception
     *	       occurs
     */
    public void clearRenewalFailureListener()
	throws RemoteException;

    /**
     * Returns the lease that controls the lifetime of this set. Can
     * be used to extend or end the sets lifetime. Note that this method
     * does not make a remote call.
     *
     * @return the lease that controls the lifetime of this set
     */
    public Lease getRenewalSetLease();
}
