You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@river.apache.org by pe...@apache.org on 2014/05/09 09:03:19 UTC

svn commit: r1593493 [21/24] - in /river/jtsk/skunk/qa_refactor/trunk: qa/ qa/src/com/sun/jini/test/impl/end2end/jssewrapper/ qa/src/com/sun/jini/test/impl/joinmanager/ qa/src/com/sun/jini/test/impl/mahalo/ qa/src/com/sun/jini/test/impl/outrigger/match...

Modified: river/jtsk/skunk/qa_refactor/trunk/src/net/jini/lease/LeaseRenewalManager.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/net/jini/lease/LeaseRenewalManager.java?rev=1593493&r1=1593492&r2=1593493&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/net/jini/lease/LeaseRenewalManager.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/net/jini/lease/LeaseRenewalManager.java Fri May  9 07:03:18 2014
@@ -1,1603 +1,1603 @@
-/*
- * 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 com.sun.jini.config.Config;
-import com.sun.jini.constants.ThrowableConstants;
-import com.sun.jini.logging.Levels;
-import com.sun.jini.logging.LogManager;
-import com.sun.jini.proxy.ConstrainableProxyUtil;
-import java.lang.reflect.Method;
-import java.rmi.RemoteException;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.SortedMap;
-import java.util.TreeMap;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.SynchronousQueue;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy;
-import java.util.concurrent.TimeUnit;
-import java.util.logging.Level;
-import java.util.logging.LogRecord;
-import java.util.logging.Logger;
-import net.jini.config.Configuration;
-import net.jini.config.ConfigurationException;
-import net.jini.core.constraint.RemoteMethodControl;
-import net.jini.core.lease.Lease;
-import net.jini.core.lease.LeaseException;
-import net.jini.core.lease.LeaseMap;
-import net.jini.core.lease.LeaseMapException;
-import net.jini.core.lease.UnknownLeaseException;
-import org.apache.river.impl.thread.NamedThreadFactory;
-
-/**
- * Provides for the systematic renewal and overall management of a set
- * of leases associated with one or more remote entities on behalf of a
- * local entity.
- * <p>
- * This class removes much of the administrative burden associated with
- * lease renewal. Clients of the renewal manager simply give their
- * leases to the manager and the manager renews each lease as necessary
- * to achieve a <em>desired expiration</em> time (which may be later
- * than the lease's current <em>actual expiration</em> time). Failures
- * encountered while renewing a lease can optionally be reflected to the
- * client via <code>LeaseRenewalEvent</code> instances.
- * <p>
- * Note that this class is not remote. Entities wishing to use this
- * class must create an instance of this class in their own virtual
- * machine to locally manage the leases granted to them. If the virtual
- * machine that the manager was created in exits or crashes, the renewal
- * manager will be destroyed.
- * <p>
- * The <code>LeaseRenewalManager</code> distinguishes between two time
- * values associated with lease expiration: the <em>desired
- * expiration</em> time for the lease, and the <em>actual
- * expiration</em> time granted when the lease is 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. The desired expiration
- * time can be retrieved using the renewal manager's
- * <code>getExpiration</code> method. The actual expiration time of a
- * lease object can be retrieved by invoking the lease's
- * <code>getExpiration</code> method.
- * <p>
- * Each lease in the managed set 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
- * (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 lease is renewed, the renewal manager will ask for an
- * extension equal to the lease's renewal duration if the renewal
- * duration is:
- * <ul>
- * <li> <code>Lease.ANY</code>, 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>
- * Once a lease is given to a lease renewal manager, the manager will
- * continue to renew the lease until one of the following occurs:
- * <ul>
- * <li> The lease's desired or actual expiration time is reached.
- * <li> An explicit removal of the lease from the set is requested via a
- *	<code>cancel</code>, <code>clear</code>, or <code>remove</code>
- *	call on the renewal manager.
- * <li> The renewal manager tries to renew the lease and gets a bad
- *	object exception, bad invocation exception, or
- *	<code>LeaseException</code>.
- * </ul>
- * <p>
- * The methods of this class are appropriately synchronized for
- * concurrent operation. Additionally, this class makes certain
- * guarantees with respect to concurrency. When this class makes a
- * remote call (for example, when requesting the renewal of a lease),
- * any invocations made on the methods of this class will not be
- * blocked. Similarly, this class makes a reentrancy guarantee with
- * respect to the listener objects registered with this class. Should
- * this class invoke a method on a registered listener (a local call),
- * calls from that method to any other method of this class are
- * guaranteed not to result in a deadlock condition.
- *
- * @author Sun Microsystems, Inc.
- * @see Lease
- * @see LeaseException
- * @see LeaseRenewalEvent 
- *
- * @com.sun.jini.impl <!-- Implementation Specifics -->
- *
- * The following implementation-specific items are discussed below:
- * <ul>
- * <li><a href="#configEntries">Configuring LeaseRenewalManager</a>
- * <li><a href="#logging">Logging</a>
- * <li><a href="#algorithm">The renewal algorithm</a>
- * </ul>
- *
- * <a name="configEntries">
- * <p><b><font size="+1">Configuring LeaseRenewalManager</font></b><p>
- * </a>
- *
- * This implementation of <code>LeaseRenewalManager</code> supports the
- * following configuration entries, with component
- * <code>net.jini.lease.LeaseRenewalManager</code>:
- *
- * <table summary="Describes the renewBatchTimeWindow configuration entry"
- *	  border="0" cellpadding="2">
- *   <tr valign="top">
- *     <th scope="col" summary="layout"> <font size="+1">&#X2022;</font>
- *     <th scope="col" align="left" colspan="2"> <font size="+1"><code>
- *	 renewBatchTimeWindow</code></font>
- *   <tr valign="top"> <td> &nbsp <th scope="row" align="right">
- *     Type: <td> <code>long</code>
- *   <tr valign="top"> <td> &nbsp <th scope="row" align="right">
- *     Default: <td> <code>5 * 60 * 1000 // 5 minutes</code>
- *   <tr valign="top"> <td> &nbsp <th scope="row" align="right">
- *     Description: <td> The maximum number of milliseconds earlier than
- *     a lease would typically be renewed to allow it to be renewed in
- *     order to permit batching its renewal with that of other
- *     leases. The value must not be negative. This entry is obtained
- *     in the constructor.
- * </table>
- * <table summary="Describes the roundTripTime configuration entry"
- *	  border="0" cellpadding="2">
- *   <tr valign="top">
- *     <th scope="col" summary="layout"> <font size="+1">&#X2022;</font>
- *     <th scope="col" align="left" colspan="2"> <font size="+1"><code>
- *	 roundTripTime</code></font>
- *   <tr valign="top"> <td> &nbsp <th scope="row" align="right">
- *     Type: <td> <code>long</code>
- *   <tr valign="top"> <td> &nbsp <th scope="row" align="right">
- *     Default: <td> <code>10 * 1000 // 10 seconds</code>
- *   <tr valign="top"> <td> &nbsp <th scope="row" align="right">
- *     Description: <td> The worst-case latency, expressed in milliseconds,
- *     to assume for a remote call to renew a lease. The value must be greater 
- *     than zero. Unrealistically low values for this entry may
- *     result in failure to renew a lease. Leases managed by this manager
- *     should have durations exceeding the <code>roundTripTime</code>.
- *     This entry is obtained in the constructor.
- * </table>
- * <table summary="Describes the executorService configuration entry"
- *	  border="0" cellpadding="2">
- *   <tr valign="top">
- *     <th scope="col" summary="layout"> <font size="+1">&#X2022;</font>
- *     <th scope="col" align="left" colspan="2"> <font size="+1"><code>
- *	 executorService</code></font>
- *   <tr valign="top"> <td> &nbsp <th scope="row" align="right">
- *     Type: <td> {@link ExecutorService}
- *   <tr valign="top"> <td> &nbsp <th scope="row" align="right">
- *     Default: <td> <code>new ThreadPoolExecutor(1,11,15,TimeUnit.SECONDS,
- *     new LinkedBlockingQueue())</code>
- *   <tr valign="top"> <td> &nbsp <th scope="row" align="right">
- *     Description: <td> The object used to manage queuing tasks
- *     involved with renewing leases and sending notifications. The
- *     value must not be <code>null</code>. The default value creates
- *     a maximum of 11 threads for performing operations, waits 15
- *     seconds before removing idle threads, and uses a load factor of
- *     1.0 when determining whether to create a new thread. Note that
- *     the implementation of the renewal algorithm includes an assumption
- *     that the <code>ExecutorService</code> uses a load factor of 1.0.
- * </table>
- * 
- * <a name="logging">
- * <p><b><font size="+1">Logging</font></b><p>
- * </a>
- *
- * This implementation uses the {@link Logger} named
- * <code>net.jini.lease.LeaseRenewalManager</code> to log information at
- * the following logging levels: <p>
- *
- * <table border="1" cellpadding="5"
- *	  summary="Describes logging performed by the
- *		   LeaseRenewalManager at different logging levels">
- *
- * <caption halign="center" valign="top"><b><code>
- *	    net.jini.lease.LeaseRenewalManager</code></b></caption>
- *
- * <tr> <th scope="col"> Level <th scope="col"> Description
- *
- * <tr> <td> {@link Levels#FAILED FAILED}
- *	<td> Lease renewal failure events, or leases that expire before
- *           reaching the desired expiration time
- *
- * <tr> <td> {@link Levels#HANDLED HANDLED}
- *	<td> Lease renewal attempts that produce indefinite exceptions
- *
- * <tr> <td> {@link Level#FINE FINE}
- *	<td> Adding and removing leases, lease renewal attempts, and desired
- *	     lease expiration events
- *
- * </table> <p>
- *
- * For a way of using the <code>FAILED</code> and <code>HANDLED</code> logging
- * levels in standard logging configuration files, see the {@link LogManager}
- * class.
- *
- * <a name="algorithm">
- * <p><b><font size="+1">The renewal algorithm</font></b><p>
- * </a>
- * The time at which a lease is scheduled for renewal is based on the
- * expiration time of the lease, possibly adjusted to account for the
- * latency of the remote renewal call. The configuration entry
- * <code>roundTripTime</code>, which defaults to ten seconds, represents
- * the total time to make the remote call. 
- * <p>
- * The following pseudocode was derived from the code which computes
- * the renewal time. In this code, <code>rtt</code> represents the
- * value of the <code>roundTripTime</code>:
- *
- * <pre>    
- *          endTime = lease.getExpiration();
- *          delta = endTime - now;
- *          if (delta <= rtt * 2) {
- *	        delta = rtt;
- *          } else if (delta <= rtt * 8) {
- *	        delta /= 2;
- *          } else if (delta <= 1000 * 60 * 60 * 24 * 7) {
- *	        delta /= 8;
- *          } else if (delta <= 1000 * 60 * 60 * 24 * 14) {
- *	        delta = 1000 * 60 * 60 * 24;
- *          } else {
- *	        delta = 1000 * 60 * 60 * 24 * 3;
- *          }
- *          renew = endTime - delta;
- *</pre>
- *
- * It is important to note that <code>delta</code> is never less than
- * <code>rtt</code> when the renewal time is computed. A lease which 
- * would expire within this time range will be scheduled for immediate
- * renewal. The use of very short lease durations (at or below <code>rtt</code>)
- * can cause the renewal manager to effectively ignore the lease duration
- * and repeatedly schedule the lease for immediate renewal.
- * <p>
- * If an attempt to renew a lease fails with an indefinite exception, a
- * renewal is rescheduled with an updated renewal time as computed by the
- * following pseudocode:
- *
- * <pre>
- *          delta = endTime - renew;
- *          if (delta > rtt) {
- *              if (delta <= rtt * 3) {
- *	            delta = rtt;
- *              } else if (delta <= 1000 * 60 * 60) {
- *	            delta /= 3;
- *              } else if (delta <= 1000 * 60 * 60 * 24) {
- *	            delta = 1000 * 60 * 30;
- *              } else if (delta <= 1000 * 60 * 60 * 24 * 7) {
- *	            delta = 1000 * 60 * 60 * 3;
- *              } else {
- *	            delta = 1000 * 60 * 60 * 8;
- *              }
- *              renew += delta;
- *          }
- * </pre>
- *
- * Client leases are maintained in a collection sorted by descending renewal
- * time. A renewal thread is spawned whenever the renewal time of the last lease
- * in the collection is reached. This renewal thread examines all of the leases
- * in the collection whose renewal time falls within
- * <code>renewBatchTimeWindow</code> milliseconds of the renewal time of the
- * last lease. If any of these leases can be batch renewed with the last lease (as
- * determined by calling the {@link Lease#canBatch canBatch} method of
- * the last lease) then a {@link LeaseMap} is created, all eligible leases
- * are added to it and the {@link LeaseMap#renewAll} method is called. Otherwise, the
- * last lease is renewed directly.
- * <p> 
- * The <code>ExecutorService</code> that manages the renewal threads has a bound on
- * the number of simultaneous threads it will support. The renewal time of
- * leases may be adjusted earlier in time to reduce the likelihood that the
- * renewal of a lease will be delayed due to exhaustion of the thread pool.
- * Actual renewal times are determined by starting with the lease with the
- * latest (farthest off) desired renewal time and working backwards.  When
- * computing the actual renewal time for a lease, the renewals of all leases
- * with later renewal times, which will be initiated during the round trip time
- * of the current lease's renewal, are considered.  If using the desired
- * renewal time for the current lease would result in more in-progress renewals
- * than the number of threads allowed, the renewal time of the current lease is
- * shifted earlier in time, such that the maximum number of threads is not
- * exceeded.
- * 
- */
-
-public class LeaseRenewalManager {
-
-    private static final String LRM = "net.jini.lease.LeaseRenewalManager";
-
-    private static final Logger logger = Logger.getLogger(LRM);
-
-    /* Method objects for manipulating method constraints */
-    private static final Method cancelMethod;
-    private static final Method cancelAllMethod;
-    private static final Method renewMethod;
-    private static final Method renewAllMethod;
-    static {
-	try {
-	    cancelMethod = Lease.class.getMethod(
-		"cancel", new Class[] { });
-	    cancelAllMethod = LeaseMap.class.getMethod(
-		"cancelAll", new Class[] { });
-	    renewMethod = Lease.class.getMethod(
-		"renew", new Class[] { long.class });
-	    renewAllMethod = LeaseMap.class.getMethod(
-		"renewAll", new Class[] { });
-	} catch (NoSuchMethodException e) {
-	    throw new NoSuchMethodError(e.getMessage());
-	}
-    }
-
-    /* Methods for comparing lease constraints. */
-    private static final Method[] leaseToLeaseMethods = {
-	cancelMethod, cancelMethod, renewMethod, renewMethod
-    };
-
-    /* Methods for converting lease constraints to lease map constraints. */
-    private static final Method[] leaseToLeaseMapMethods = {
-	cancelMethod, cancelAllMethod, renewMethod, renewAllMethod
-    };
-
-    /** Time window in which to look for batchable leases */
-    private long renewBatchTimeWindow = 1000 * 60 * 5;
-
-    /** Task manager for queuing and renewing leases 
-     *  NOTE: test failures occur with queue's that have capacity, 
-     *  no test failures occur with SynchronousQueue, for the time
-     *  being, until the cause is sorted out we may need to rely on 
-     *  a larger pool, if necessary.  TaskManager is likely to have 
-     *  lower throughput capacity that ExecutorService with a
-     *  SynchronousQueue although this hasn't been confirmed yet.
-     */
-    final ExecutorService leaseRenewalExecutor;
-
-    /**
-     * The worst-case renewal round-trip-time
-     */
-    private static long renewalRTT = 10 * 1000;
-
-    /** 
-     * Entries for leases that are not actively being renewed.
-     * Lease with the earliest renewal is last in the map.
-     */
-    private final SortedMap leases = new TreeMap();
-
-    /** Entries for leases that are actively being renewed */
-    private final List leaseInRenew = new ArrayList(1);
-    /** The queuer task */
-    private QueuerTask queuer = null;
-
-    /**
-     * Used to determine concurrency constraints when calculating actual
-     * renewals.  The list is stored in a field to avoid reallocating it.
-     */
-    private List calcList;
-
-    private final class RenewTask implements Runnable {
-	/** Entries of leases to renew (if multiple, all can be batched) */
-	private final List bList;
-
-	/** 
-	 * True if this task only holds leases that have reached their
-	 * actual or desired expiration
-	 */
-	private final boolean noRenewals;
-
-	/**
-	 * Create a collection of entries whose leases can be batch
-	 * renewed with the last lease in the map, or a list of entries
-	 * whose leases need to be removed.  Which is created depends on
-	 * the state of the last lease in the map.  Remove each entry
-	 * from the map, and add them to leaseInRenew.
-	 */
-	RenewTask(long now) {
-	    bList = new ArrayList(1);
-	    Entry e = (Entry) leases.lastKey();
-
-	    if (e.renewalsDone() || e.endTime <= now) {
-		noRenewals = true;
-		Map lMap = leases.tailMap(new Entry(now));
-		for (Iterator iter = lMap.values().iterator(); 
-		     iter.hasNext(); )
-		{
-		    Entry be = (Entry) iter.next();
-		    if (be.renewalsDone() || be.endTime <= now) {
-			iter.remove();
-			logExpiration(be);
-			/*
-			 * Only add to bList if we need to tell someone
-			 * about this lease's departure
-			 */
-			if (be.listener != null)
-			    bList.add(be);
-		    }
-		}
-	    } else {
-		noRenewals = false;
-		Map lMap = leases.tailMap(
-		    new Entry(e.renew + renewBatchTimeWindow));
-		for (Iterator iter = lMap.values().iterator(); 
-		     iter.hasNext(); )
-		{
-		    Entry be = (Entry) iter.next();
-		    if (be == e || be.canBatch(e)) {
-			iter.remove();
-			leaseInRenew.add(be);
-			bList.add(be);
-		    }
-		}
-	    }
-	}
-
-	public void run() {
-	    if (noRenewals) {
-		// Just notify
-		tell(bList);
-	    } else {
-		/*
-		 * Get rid of any leases that have expired and then do
-		 * renewals
-		 */
-		long now = System.currentTimeMillis();
-		List bad = processBadLeases(now);
-		if (!bList.isEmpty())
-		    renewAll(bList, now);
-		if (bad != null)
-		    tell(bad);
-	    }
-	}
-
-	/**
-	 * Find any expired leases, remove them from bList and
-	 * leaseInRenew, and return any with listeners.
-	 */
-	private List processBadLeases(long now) {
-	    List bad = null;
-	    synchronized (LeaseRenewalManager.this) {
-		for (Iterator iter = bList.iterator(); iter.hasNext(); ) {
-		    Entry e = (Entry) iter.next();
-		    if (e.endTime <= now) {
-			iter.remove();
-			logExpiration(e);
-			removeLeaseInRenew(e);
-			if (e.listener != null) {
-			    if (bad == null)
-				bad = new ArrayList(1);
-			    bad.add(e);
-			}
-		    }
-		}
-	    }
-	    return bad;
-	}
-    }
-
-    private static class Entry implements Comparable {
-	/*
-	 * Since the cnt only gets modified in the constructor, and the
-	 * constructor is always called from synchronized code, the cnt
-	 * does not need to be synchronized.
-	 */
-	private static long cnt = 0;
-
-	/** Unique id */
-	public final long id;
-	/** The lease */
-	public final Lease lease;
-	/** Desired expiration */
-	public long expiration;
-	/** Renew duration */
-	public long renewDuration;
-	/** The listener, or null */
-	public final LeaseListener listener;
-	/** Current actual expiration */
-	public long endTime;
-
-	/** 
-	 * The next time we have to do something with this lease.
-	 * Usually a renewal, but could be removing it from the managed
-	 * set because its desired expiration has been reached.
-	 */
-	public long renew;
-
-	/** Actual time to renew, given concurrency limitations */
-	public long actualRenew;
-	/** Renewal exception, or null */
-	public Throwable ex = null;
-
-	public Entry(Lease lease,
-		     long expiration,
-		     long renewDuration,
-		     LeaseListener listener)
-	{
-	    this.endTime = lease.getExpiration();
-	    this.lease = lease;
-	    this.expiration = expiration;
-	    this.renewDuration = renewDuration;
-	    this.listener = listener;
-	    id = cnt++;
-	}
-
-	/** Create a fake entry for tailMap */
-	public Entry(long renew) {
-	    this.renew = renew;
-	    id = Long.MAX_VALUE;
-	    lease = null;
-	    listener = null;
-	}
-
-	/**
-	 * If the renewDuration is ANY, return ANY, otherwise return the
-	 * minimum of the renewDuration and the time remaining until the
-	 * desired expiration.
-	 */
-	public long getRenewDuration(long now) {
-	    if (renewDuration == Lease.ANY)
-		return renewDuration;
-	    return Math.min(expiration - now, renewDuration);
-	}
-
-	/** Calculate the renew time for the lease entry */
-	public void calcRenew(long now) {
-	    endTime = lease.getExpiration();
-	    if (renewalsDone()) {
-		if (null == desiredExpirationListener()) {
-		    // Nothing urgent needs to be done with this lease
-		    renew = Long.MAX_VALUE;
-		} else {
-		    /*
-		     * Tell listener about dropping this lease in a
-		     * timely fashion
-		     */
-		    renew = expiration; 
-		}
-		return;
-	    }
-	    long delta = endTime - now;
-	    if (delta <= renewalRTT * 2) {
-		delta = renewalRTT;
-	    } else if (delta <= renewalRTT * 8) {
-		delta /= 2;
-	    } else if (delta <= 1000 * 60 * 60 * 24 * 7) {
-		delta /= 8;
-	    } else if (delta <= 1000 * 60 * 60 * 24 * 14) {
-		delta = 1000 * 60 * 60 * 24;
-	    } else {
-		delta = 1000 * 60 * 60 * 24 * 3;
-	    }
-	    renew = endTime - delta;
-	}
-
-	/** Calculate a new renew time due to an indefinite exception */
-	public void delayRenew() {
-	    long delta = endTime - renew;
-	    if (delta <= renewalRTT) {
-		return;
-	    } else if (delta <= renewalRTT * 3) {
-		 delta = renewalRTT;
-	    } else if (delta <= 1000 * 60 * 60) {
-		delta /= 3;
-	    } else if (delta <= 1000 * 60 * 60 * 24) {
-		delta = 1000 * 60 * 30;
-	    } else if (delta <= 1000 * 60 * 60 * 24 * 7) {
-		delta = 1000 * 60 * 60 * 3;
-	    } else {
-		delta = 1000 * 60 * 60 * 8;
-	    }
-	    renew += delta;
-	}
-
-	/** Sort by decreasing renew time, secondary sort by decreasing id */
-	public int compareTo(Object obj) {
-	    if (this == obj)
-		return 0;
-	    Entry e = (Entry) obj;
-	    if (renew < e.renew || (renew == e.renew && id < e.id))
-		return 1;
-	    return -1;
-	}
-
-	/**
-	 * Returns true if the renewal of this lease can be batched with
-	 * the (earlier) renewal of the given lease.  This method must
-	 * be called with an entry such that e.renew <= this.renew. <p>
-	 * 
-	 * First checks that both leases require renewal, have the same
-	 * client constraints, and can be batched.  Then enforces
-	 * additional requirements to avoid renewing the lease too much
-	 * more often than necessary. <p>
-	 *
-	 * One of the following must be true: <ul>
-	 *
-	 * <li> This lease has a renewal duration of Lease.ANY, meaning
-	 * it doesn't specify its renewal duration.
-	 *
-	 * <li> The amount of time from the other lease's renewal time
-	 * to this one's is less than half of the estimated time needed
-	 * to perform renewals (renewalRTT).  In this case, the renewal
-	 * times are so close together that the renewal duration
-	 * shouldn't be materially affected.
-	 *
-	 * <li> This lease's expiration time is no more than half its
-	 * renewal duration greater than the renewal time of the other
-	 * lease.  This case insures that this lease is not renewed
-	 * until at least half of it's renewal duration has
-	 * elapsed. </ul> <p>
-	 *
-	 * In addition, one of the following must be true: <ul>
-	 *
-	 * <li> The other lease has a renewal duration of Lease.ANY,
-	 * meaning we don't know how long its next renewal will be.
-	 *
-	 * <li> The other lease is not going to be renewed again before
-	 * this lease's renewal time, because either its next renewal
-	 * will last until after this lease's renewal time or it will
-	 * only be renewed once more. </ul>
-	 */
-	public boolean canBatch(Entry e) {
-	    return (!renewalsDone() &&
-		    !e.renewalsDone() &&
-		    sameConstraints(lease, e.lease) &&
-		    lease.canBatch(e.lease) &&
-		    (renewDuration == Lease.ANY ||
-		     renew - e.renew <= renewalRTT / 2 ||
-		     endTime - e.renew <= renewDuration / 2) &&
-		    (e.renewDuration == Lease.ANY ||
-		     e.renew > renew - e.renewDuration ||
-		     e.renew >= e.expiration - e.renewDuration));
-	}
-
-	/**
-	 * Returns true if the two leases both implement RemoteMethodControl
-	 * and have the same constraints for Lease methods, or both don't
-	 * implement RemoteMethodControl, else returns false.
-	 */
-	private static boolean sameConstraints(Lease l1, Lease l2) {
-	    if (!(l1 instanceof RemoteMethodControl)) {
-		return !(l2 instanceof RemoteMethodControl);
-	    } else if (!(l2 instanceof RemoteMethodControl)) {
-		return false;
-	    } else {
-		return ConstrainableProxyUtil.equivalentConstraints(
-		    ((RemoteMethodControl) l1).getConstraints(),
-		    ((RemoteMethodControl) l2).getConstraints(),
-		    leaseToLeaseMethods);
-	    }
-	}
-
-	/**
-	 * Return the DesiredExpirationListener associated with this
-	 * lease, or null if there is none.
-	 */
-	public DesiredExpirationListener desiredExpirationListener() {
-	    if (listener == null)
-		return null;
-
-	    if (listener instanceof DesiredExpirationListener) 
-		return (DesiredExpirationListener) listener;
-
-	    return null;
-	}
-
-	/**
-	 * Return true if the actual expiration is greater than or equal
-	 * to the desired expiration (e.g. we don't need to renew this
-	 * lease any more.
-	 */
-	public boolean renewalsDone() {
-	    return expiration <= endTime;
-	}
-    }
-
-    /**
-     * No-argument constructor that creates an instance of this class
-     * that initially manages no leases.
-     */
-    public LeaseRenewalManager() {
-        leaseRenewalExecutor = 
-            new ThreadPoolExecutor(
-                    1,  /* min threads */
-                    11, /* max threads */
-                    15,
-                    TimeUnit.SECONDS, 
-                    new SynchronousQueue<Runnable>(), /* Queue has no capacity */
-                    new NamedThreadFactory("LeaseRenewalManager",true),
-                    new CallerRunsPolicy()
-            );
-    }
-
-    /**
-     * Constructs an instance of this class that initially manages no leases
-     * and that uses <code>config</code> to control implementation-specific
-     * details of the behavior of the instance created.
-     *
-     * @param config supplies entries that control the configuration of this
-     *	      instance
-     * @throws ConfigurationException if a problem occurs when obtaining
-     *	       entries from the configuration
-     * @throws NullPointerException if the configuration is <code>null</code>
-     */
-    public LeaseRenewalManager(Configuration config)
-	throws ConfigurationException
-    {
-	if (config == null) {
-	    throw new NullPointerException("config is null");
-	}
-	renewBatchTimeWindow = Config.getLongEntry(
-	    config, LRM, "renewBatchTimeWindow",
-	    renewBatchTimeWindow, 0, Long.MAX_VALUE);
-	renewalRTT = Config.getLongEntry(
-	    config, LRM, "roundTripTime",
-	    renewalRTT, 1, Long.MAX_VALUE);
-	leaseRenewalExecutor = Config.getNonNullEntry(
-            config, 
-            LRM, 
-            "executorService", 
-            ExecutorService.class,
-            new ThreadPoolExecutor(
-                    1,  /* Min Threads */
-                    11, /* Max Threads */
-                    15,
-                    TimeUnit.SECONDS, 
-                    new SynchronousQueue<Runnable>(), /* No capacity */
-                    new NamedThreadFactory("LeaseRenewalManager",false),
-                    new CallerRunsPolicy()
-            ) 
-        );
-    }
-
-    /**
-     * Constructs an instance of this class that will initially manage a
-     * single lease. Employing this form of the constructor is
-     * equivalent to invoking the no-argument form of the constructor
-     * followed by an invocation of the three-argument form of the
-     * <code>renewUntil</code> method. See <code>renewUntil</code> for
-     * details on the arguments and what exceptions may be thrown by
-     * this constructor.
-     *
-     * @param lease reference to the initial lease to manage
-     * @param desiredExpiration the desired expiration for
-     *	      <code>lease</code>
-     * @param listener reference to the <code>LeaseListener</code>
-     *	      object that will receive notifications of any exceptional
-     *	      conditions that occur during renewal attempts. If
-     *	      <code>null</code> no notifications will be sent.
-     * @throws NullPointerException if <code>lease</code> is
-     *	       <code>null</code>
-     * @see LeaseListener
-     * @see #renewUntil 
-     */
-    public LeaseRenewalManager(Lease lease,
-			       long desiredExpiration,
-			       LeaseListener listener)
-    {
-        leaseRenewalExecutor = new ThreadPoolExecutor(
-                1,  /* Min Threads */
-                11, /* Max Threads */
-                15,
-                TimeUnit.SECONDS, 
-                new SynchronousQueue<Runnable>(), /* No Capacity */
-                new NamedThreadFactory("LeaseRenewalManager",true),
-                new CallerRunsPolicy()
-        );
-	renewUntil(lease, desiredExpiration, listener);
-    }
-
-    /**
-     * Include a lease in the managed set until a specified time. 
-     * <p>
-     * If <code>desiredExpiration</code> is <code>Lease.ANY</code>
-     * calling this method is equivalent the following call:
-     * <pre>
-     *     renewUntil(lease, Lease.FOREVER, Lease.ANY, listener)
-     * </pre>
-     * otherwise it is equivalent to this call:
-     * <pre>
-     *     renewUntil(lease, desiredExpiration, Lease.FOREVER, listener)
-     * </pre>
-     * <p>
-     * @param lease the <code>Lease</code> to be managed
-     * @param desiredExpiration when the client wants the lease to
-     *	      expire, in milliseconds since the beginning of the epoch
-     * @param listener reference to the <code>LeaseListener</code>
-     *	      object that will receive notifications of any exceptional
-     *	      conditions that occur during renewal attempts. If
-     *	      <code>null</code> no notifications will be sent.
-     * @throws NullPointerException if <code>lease</code> is
-     *	       <code>null</code>
-     * @see #renewUntil
-     */
-    public final void renewUntil(Lease lease,
-			   long desiredExpiration,
-			   LeaseListener listener)
-    {
-	if (desiredExpiration == Lease.ANY) {
-	    renewUntil(lease, Lease.FOREVER, Lease.ANY, listener);
-	} else {
-	    renewUntil(lease, desiredExpiration, Lease.FOREVER, listener);
-	}
-    }
-
-    /**
-     * Include a lease in the managed set until a specified time and
-     * with a specified renewal duration.
-     * <p>
-     * This method takes as arguments: a reference to the lease to
-     * manage, the desired expiration time of the lease, the renewal
-     * duration time for the lease, and a reference to the
-     * <code>LeaseListener</code> object that will receive notification
-     * of exceptional conditions when attempting to renew this
-     * lease. The <code>LeaseListener</code> argument may be
-     * <code>null</code>.
-     * <p>
-     * If the <code>lease</code> argument is <code>null</code>, a
-     * <code>NullPointerException</code> will be thrown. If the
-     * <code>desiredExpiration</code> argument is
-     * <code>Lease.FOREVER</code>, the <code>renewDuration</code>
-     * argument may be <code>Lease.ANY</code> or any positive value;
-     * otherwise, the <code>renewDuration</code> argument must be a
-     * positive value. If the <code>renewDuration</code> argument does
-     * not meet these requirements, an
-     * <code>IllegalArgumentException</code> will be thrown.
-     * <p>
-     * If the lease passed to this method is already in the set of
-     * managed leases, the listener object, the desired expiration, and
-     * the renewal duration associated with that lease will be replaced
-     * with the new listener, desired expiration, and renewal duration.
-     * <p>
-     * The lease will remain in the set until one of the following
-     * occurs:
-     * <ul>
-     * <li> The lease's desired or actual expiration time is reached.
-     * <li> An explicit removal of the lease from the set is requested
-     *	    via a <code>cancel</code>, <code>clear</code>, or
-     *	    <code>remove</code> call on the renewal manager.
-     * <li> The renewal manager tries to renew the lease and gets a bad
-     *	    object exception, bad invocation exception, or
-     *	    <code>LeaseException</code>.
-     * </ul>
-     * <p>
-     * This method will interpret the value of the
-     * <code>desiredExpiration</code> argument as the desired absolute
-     * system time after which the lease is no longer valid. This
-     * argument provides the ability to indicate an expiration time that
-     * extends beyond the actual expiration of the lease. If the value
-     * passed for this argument does indeed extend beyond the lease's
-     * actual expiration time, then the lease will be systematically
-     * renewed at appropriate times until one of the conditions listed
-     * above occurs. If the value is less than or equal to the actual
-     * expiration time, nothing will be done to modify the time when the
-     * lease actually expires. That is, the lease will not be renewed
-     * with an expiration time that is less than the actual expiration
-     * time of the lease at the time of the call.
-     * <p>
-     * If the <code>LeaseListener</code> argument is a
-     * non-<code>null</code> object reference, it will receive
-     * notification of exceptional conditions occurring upon a renewal
-     * attempt of the lease. In particular, exceptional conditions
-     * include the reception of a <code>LeaseException</code>, bad
-     * object exception, or bad invocation exception (collectively these
-     * are referred to as <em>definite exceptions</em>) during a renewal
-     * attempt or the lease's actual expiration being reached before its
-     * desired expiration.
-     * <p>
-     * If a definite exception occurs during a lease renewal request,
-     * the exception will be wrapped in an instance of the
-     * <code>LeaseRenewalEvent</code> class and sent to the listener.
-     * <p>
-     * If an indefinite exception occurs during a renewal request for
-     * the lease, renewal requests will continue to be made for that
-     * lease until: the lease is renewed successfully, a renewal attempt
-     * results in a definite exception, or the lease's actual expiration
-     * time has been exceeded. If the lease cannot be successfully
-     * renewed before its actual expiration is reached, the exception
-     * associated with the most recent renewal attempt will be wrapped
-     * in an instance of the <code>LeaseRenewalEvent</code> class and
-     * sent to the listener.
-     * <p>
-     * If the lease's actual expiration is reached before the lease's
-     * desired expiration time, and either 1) the last renewal attempt
-     * succeeded or 2) there have been no renewal attempts, a
-     * <code>LeaseRenewalEvent</code> containing a <code>null</code>
-     * exception will be sent to the listener.
-     *
-     * @param lease the <code>Lease</code> to be managed
-     * @param desiredExpiration when the client wants the lease to
-     *	      expire, in milliseconds since the beginning of the epoch
-     * @param renewDuration the renewal duration to associate with the
-     *	      lease, in milliseconds
-     * @param listener reference to the <code>LeaseListener</code>
-     *	      object that will receive notifications of any exceptional
-     *	      conditions that occur during renewal attempts. If
-     *	      <code>null</code>, no notifications will be sent.
-     * @throws NullPointerException if <code>lease</code> is
-     *	       <code>null</code>
-     * @throws IllegalArgumentException if <code>renewDuration</code> is
-     *	       invalid
-     * @see LeaseRenewalEvent
-     * @see LeaseException
-     */
-    public void renewUntil(Lease lease,
-			   long desiredExpiration,
-			   long renewDuration,
-			   LeaseListener listener)
-    {
-	validateDuration(renewDuration, desiredExpiration == Lease.FOREVER,
-			 "desiredExpiration");
-	addLease(lease, desiredExpiration, renewDuration, listener,
-		 System.currentTimeMillis());
-    }
-
-    /**
-     * Include a lease in the managed set for a specified duration.
-     * <p>
-     * Calling this method is equivalent the following call:
-     * <pre>
-     *     renewFor(lease, desiredDuration, Lease.FOREVER, listener)
-     * </pre>
-     *
-     * @param lease reference to the new lease to manage
-     * @param desiredDuration the desired duration (relative time) that
-     *	      the caller wants <code>lease</code> to be valid for, in
-     *	      milliseconds
-     * @param listener reference to the <code>LeaseListener</code>
-     *	      object that will receive notifications of any exceptional
-     *	      conditions that occur during renewal attempts. If
-     *	      <code>null</code>, no notifications will be sent.
-     * @throws NullPointerException if <code>lease</code> is
-     *	       <code>null</code>
-     * @see #renewFor 
-     */
-    public void renewFor(Lease lease, long desiredDuration, 
-			 LeaseListener listener) 
-    {
-	renewFor(lease, desiredDuration, Lease.FOREVER, listener);
-    }	 
-
-    /**
-     * Include a lease in the managed set for a specified duration and
-     * with specified renewal duration.
-     * <p>
-     * The semantics of this method are similar to those of the
-     * four-argument form of <code>renewUntil</code>, with
-     * <code>desiredDuration</code> + current time being used for the
-     * value of the <code>desiredExpiration</code> argument of
-     * <code>renewUntil</code>. The only exception to this is that, in
-     * the context of <code>renewFor</code>, the value of the
-     * <code>renewDuration</code> argument may only be
-     * <code>Lease.ANY</code> if the value of the
-     * <code>desiredDuration</code> argument is <em>exactly</em>
-     * <code>Lease.FOREVER.</code>
-     * <p>
-     * This method tests for arithmetic overflow in the desired
-     * expiration time computed from the value of
-     * <code>desiredDuration</code> argument
-     * (<code>desiredDuration</code> + current time). Should such
-     * overflow be present, a value of <code>Lease.FOREVER</code> is
-     * used to represent the lease's desired expiration time.
-     *
-     * @param lease reference to the new lease to manage
-     * @param desiredDuration the desired duration (relative time) that
-     *	      the caller wants <code>lease</code> to be valid for, in
-     *	      milliseconds
-     * @param renewDuration the renewal duration to associate with the
-     *	      lease, in milliseconds
-     * @param listener reference to the <code>LeaseListener</code>
-     *	      object that will receive notifications of any exceptional
-     *	      conditions that occur during renewal attempts. If
-     *	      <code>null</code>, no notifications will be sent.
-     * @throws NullPointerException if <code>lease</code> is
-     *	       <code>null</code>
-     * @throws IllegalArgumentException if <code>renewDuration</code> is
-     *	       invalid
-     * @see #renewUntil 
-     */
-    public void renewFor(Lease lease,
-			 long desiredDuration,
-			 long renewDuration,
-			 LeaseListener listener)
-    {
-	/*
-	 * Validate before calculating effective desiredExpiration, if
-	 * they want a renewDuration of Lease.ANY, desiredDuration has
-	 * to be exactly Lease.FOREVER
-	 */
-	validateDuration(renewDuration, desiredDuration == Lease.FOREVER,
-			 "desiredDuration");
-
-	long now = System.currentTimeMillis();
-	long desiredExpiration;
-	if (desiredDuration < Lease.FOREVER - now) { // check overflow.
-	    desiredExpiration = now + desiredDuration;
-	} else {
-	    desiredExpiration = Lease.FOREVER;
-	}
-	addLease(lease, desiredExpiration, renewDuration, listener, now);
-    }
-
-    /**
-     * Error checking function that ensures renewDuration is valid taking
-     * into account the whether or not the desired expiration/duration is
-     * Lease.FOREVER. Throws an appropriate IllegalArgumentException if
-     * an invalid renewDuration is passed.
-     *
-     * @param renewDuration renew duration the clients wants
-     * @param isForever should be true if client asked for a desired
-     *	      expiration/duration of exactly Lease.FOREVER
-     * @param name name of the desired expiration/duration field, used
-     *	      to construct exception
-     * @throws IllegalArgumentException if renewDuration is invalid
-     */
-    private void validateDuration(long renewDuration, boolean isForever, 
-				  String name) 
-    {
-	if (renewDuration <= 0 && 
-	    !(renewDuration == Lease.ANY && isForever))
-	{
-	    /*
-	     * A negative renew duration and is not lease.ANY with a
-	     * forever desired expiration
-	     */
-	    if (renewDuration == Lease.ANY) {
-		/*
-		 * Must have been Lease.ANY with a non-FOREVER desired
-		 * expiration
-		 */
-		throw new IllegalArgumentException("A renewDuration of " +
-		     "Lease.ANY can only be used with a " + name + " of " +
-		     "Lease.FOREVER");
-	    } 
-
-	    if (isForever) {
-		// Must have been a non-Lease.ANY, non-positive renewDuration
-		throw new IllegalArgumentException("When " + name + " is " +
-		    "Lease.FOREVER the only valid values for renewDuration " +
-		    "are a positive number, Lease.ANY, or Lease.FOREVER");
-	    }
-
-	    /*
-	     * Must be a non-positive renewDuration with a non-Forever 
-	     * desired expiration
-	     */
-	    throw new IllegalArgumentException("When the " + name +
-		" is not Lease.FOREVER the only valid values for " +
-		"renewDuration are a positive number or Lease.FOREVER");
-	}
-    }
-
-    private synchronized void addLease(Lease lease,
-				       long desiredExpiration,
-				       long renewDuration,
-				       LeaseListener listener,
-				       long now)
-    {	    
-	Entry e = findEntryDo(lease);
-	if (e != null && !removeLeaseInRenew(e))
-	    leases.remove(e);
-	insertEntry(new Entry(lease, desiredExpiration, renewDuration,
-			      listener),
-		    now);
-	calcActualRenews(now);
-	logger.log(Level.FINE, "Added lease {0}", lease);
-    }
-
-    /** Calculate the preferred renew time, and put in the map */
-    private void insertEntry(Entry e, long now) {
-	e.calcRenew(now);
-	leases.put(e, e);
-    }
-
-    /**
-     * Returns the current desired expiration time associated with a
-     * particular lease, (not the actual expiration that was granted
-     * when the lease was created or last renewed).
-     *
-     * @param lease the lease the caller wants the current desired
-     *	      expiration for
-     * @return a <code>long</code> value corresponding to the current
-     *	       desired expiration time associated with <code>lease</code>
-     * @throws UnknownLeaseException if the lease passed to this method
-     *	       is not in the set of managed leases
-     * @see UnknownLeaseException
-     * @see #setExpiration 
-     */
-    public synchronized long getExpiration(Lease lease)
-	throws UnknownLeaseException
-    {
-	return findEntry(lease).expiration;
-    }
-
-    /**
-     * Replaces the current desired expiration of a given lease from the
-     * managed set with a new desired expiration time.
-     * <p>
-     * Note that an invocation of this method with a lease that is
-     * currently a member of the managed set is equivalent to an
-     * invocation of the <code>renewUntil</code> method with the lease's
-     * current listener as that method's <code>listener</code>
-     * argument. Specifically, if the value of the
-     * <code>expiration</code> argument is less than or equal to the
-     * lease's current desired expiration, this method takes no action.
-     *
-     * @param lease the lease whose desired expiration time should be
-     *	      replaced
-     * @param expiration <code>long</code> value representing the new
-     *	      desired expiration time for the <code>lease</code>
-     *	      argument
-     * @throws UnknownLeaseException if the lease passed to this method
-     *	       is not in the set of managed leases
-     * @see #renewUntil
-     * @see UnknownLeaseException
-     * @see #getExpiration 
-     */
-    public synchronized void setExpiration(Lease lease, long expiration)
-	throws UnknownLeaseException
-    {
-	Entry e = findEntry(lease);
-	e.expiration = expiration;
-	if (expiration != Lease.FOREVER && e.renewDuration == Lease.ANY)
-	    e.renewDuration = Lease.FOREVER;
-	if (leaseInRenew.indexOf(e) < 0) {
-	    leases.remove(e);
-	    long now = System.currentTimeMillis();
-	    insertEntry(e, now);
-	    calcActualRenews(now);
-	}
-    }
-
-    /**
-     * Removes a given lease from the managed set, and cancels it.
-     * <p>
-     * Note that even if an exception is thrown as a result of the
-     * cancel operation, the lease will still have been removed from the
-     * set of leases managed by this class. Additionally, any exception
-     * thrown by the <code>cancel</code> method of the lease object
-     * itself may also be thrown by this method.
-     *
-     * @param lease the lease to remove and cancel
-     * @throws UnknownLeaseException if the lease passed to this method
-     *	       is not in the set of managed leases
-     * @throws RemoteException typically, this exception occurs when
-     *         there is a communication failure between the client and
-     *         the server. When this exception does occur, the lease may
-     *         or may not have been successfully cancelled, (but the
-     *         lease is guaranteed to have been removed from the managed
-     *         set).
-     * @see Lease#cancel
-     * @see UnknownLeaseException
-     */
-    public void cancel(Lease lease)
-	throws UnknownLeaseException, RemoteException
-    {
-	remove(lease);
-	lease.cancel();
-    }
-    
-    public void close(){
-        leaseRenewalExecutor.shutdown();
-    }
-
-    /**
-     * Removes a given lease from the managed set of leases; but does
-     * not cancel the given lease.
-     *
-     * @param lease the lease to remove from the managed set
-     * @throws UnknownLeaseException if the lease passed to this method
-     *         is not in the set of managed leases
-     * @see UnknownLeaseException
-     */
-    public synchronized void remove(Lease lease) throws UnknownLeaseException {
-	Entry e = findEntry(lease);
-	if (!removeLeaseInRenew(e))
-	    leases.remove(e);
-	calcActualRenews();
-	logger.log(Level.FINE, "Removed lease {0}", lease);
-    }
-
-    /**
-     * Removes all leases from the managed set of leases. This method
-     * does not request the cancellation of the removed leases.
-     */
-    public synchronized void clear() {
-	leases.clear();
-	leaseInRenew.clear();
-	calcActualRenews();
-	logger.log(Level.FINE, "Removed all leases");
-    }
-
-    /** Calculate the actual renew times, and poke/restart the queuer */
-    private void calcActualRenews() {
-	calcActualRenews(System.currentTimeMillis());
-    }
-
-    /** Calculate the actual renew times, and poke/restart the queuer */
-    private void calcActualRenews(long now) {
-	/*
-	 * Subtract one to account for the queuer thread, which should not be
-	 * counted.
-	 */
-	int maxThreads = leaseRenewalExecutor instanceof ThreadPoolExecutor ? 
-            ((ThreadPoolExecutor)leaseRenewalExecutor).getMaximumPoolSize() - 1 
-                : 10;
-	if (calcList == null) {
-	    calcList = new ArrayList(maxThreads);
-	}
-	for (Iterator iter = leases.values().iterator(); iter.hasNext(); ) {
-	    Entry e = (Entry) iter.next();
-
-	    // Start by assuming we can renew the lease when we want
-	    e.actualRenew = e.renew;
-
-	    if (e.renewalsDone()) {
-		/*
-		 * The lease's actual expiration is >= desired
-		 * expiration, drop the lease if the desired expiration
-		 * has been reached and we don't have to tell anyone
-		 * about it
-		 */
-		if (now >= e.expiration && 
-		    e.desiredExpirationListener() == null) 
-		{
-		    logExpiration(e);
-		    iter.remove();
-		}
-
-		/*
-		 * Even if we have to send an event we assume that it
-		 * won't consume a slot in our schedule
-		 */
-		continue; 
-	    }
-
-	    if (e.endTime <= now && e.listener == null) {
-		// Lease has expired and no listener, just remove it.
-		logExpiration(e);
-		iter.remove();
-		continue;
-	    }
-
-	    /*
-	     * Make sure there aren't too many lease renewal threads
-	     * operating at the same time.
-	     */
-	    if (!canBatch(e)) {
-		/*
-		 * Find all renewals that start before we expect ours to
-		 * be done.
-		 */
-		for (Iterator listIter = calcList.iterator();
-		     listIter.hasNext(); )
-		{
-		    if (e.renew >=
-			((Entry) listIter.next()).actualRenew - renewalRTT)
-		    {
-			/*
-			 * This renewal starts after we expect ours to
-			 * be done.
-			 */
-			break;
-		    }
-		    listIter.remove();
-		}
-		if (calcList.size() == maxThreads) {
-		    /*
-		     * Too many renewals.  Move our actual renewal time
-		     * earlier so we'll probably be done before the last
-		     * one needs to start.  Remove that one, since it
-		     * won't overlap any earlier renewals.
-		     */
-		    Entry e1 = (Entry) calcList.remove(0);
-		    e.actualRenew = e1.actualRenew - renewalRTT;
-		}
-		calcList.add(e);
-	    }
-	}
-	calcList.clear();
-	long newWakeup = wakeupTime();
-	if (queuer == null) {
-	    if (newWakeup < Long.MAX_VALUE) {
-		queuer = new QueuerTask(newWakeup);
-		leaseRenewalExecutor.execute(queuer);
-	    }
-	} else if (newWakeup < queuer.wakeup ||
-		   (newWakeup == Long.MAX_VALUE && leaseInRenew.isEmpty()))
-	{
-	    notifyAll();
-	}
-    }
-
-    /**
-     * Return true if e can be batched with another entry that expires
-     * between e.renew - renewBatchTimeWindow and e.renew.
-     */
-    private boolean canBatch(Entry e) {
-	Iterator iter = leases.tailMap(e).values().iterator();
-	iter.next(); // skip e itself
-	while (iter.hasNext()) {
-	    Entry be = (Entry) iter.next();
-	    if (e.renew - be.renew > renewBatchTimeWindow)
-		break;
-	    if (e.canBatch(be))
-		return true;
-	}
-	return false;
-    }
-
-    /**
-     * Find a lease entry, throw exception if not found or expired
-     * normally
-     */
-    private Entry findEntry(Lease lease) throws UnknownLeaseException {
-	Entry e = findEntryDo(lease);
-	if (e != null &&
-	    (e.renew < e.endTime || System.currentTimeMillis() < e.endTime))
-	{
-	    return e;
-	}
-	throw new UnknownLeaseException();
-    }
-
-    /** Find a lease entry, or null */
-    private Entry findEntryDo(Lease lease) {
-	Entry e = findLeaseFromIterator(leases.values().iterator(), lease);
-	if (e == null)
-	    e = findLeaseFromIterator(leaseInRenew.iterator(), lease);
-	return e;
-    }
-
-    /** Find a lease entry, or null */
-    private static Entry findLeaseFromIterator(Iterator iter, Lease lease) {
-	while (iter.hasNext()) {
-	    Entry e = (Entry) iter.next();
-	    if (e.lease.equals(lease))
-		return e;
-	}
-	return null;
-    }
-
-    /** Notify the listener for each lease */
-    private void tell(List bad) {
-	for (Iterator iter = bad.iterator(); iter.hasNext(); ) {
-	    Entry e = (Entry) iter.next();
-	    if (e.renewalsDone()) {
-		final DesiredExpirationListener del = 
-		    e.desiredExpirationListener();
-		if (del != null) {
-		    del.expirationReached(new LeaseRenewalEvent(this, e.lease,
-		        e.expiration, null));
-		}
-		continue; 
-	    }
-	    e.listener.notify(new LeaseRenewalEvent(this, e.lease,
-						    e.expiration, e.ex));
-	}
-    }
-
-    /**
-     * Logs a lease expiration, distinguishing between expected
-     * and premature expirations.
-     *
-     * @param e the <code>Entry</code> holding the lease
-     */
-    private void logExpiration(Entry e) {
-	if (e.renewalsDone()) {
-	    logger.log(Level.FINE,
-		       "Reached desired expiration for lease {0}",
-		       e.lease);
-	} else {
-	    logger.log(Levels.FAILED,
-		       "Lease {0} expired before reaching "
-		       + "desired expiration of " 
-		       + e.expiration);
-	}
-    }
-		
-    /**
-     * Logs a throw. Use this method to log a throw when the log message needs
-     * parameters.
-     *
-     * @param level the log level
-     * @param sourceMethod name of the method where throw occurred
-     * @param msg log message
-     * @param params log message parameters
-     * @param e exception thrown
-     */
-    private static void logThrow(Level level,
-				 String sourceMethod,
-				 String msg,
-				 Object[] params,
-				 Throwable e)
-    {
-	LogRecord r = new LogRecord(level, msg);
-	r.setLoggerName(logger.getName());
-	r.setSourceClassName(LeaseRenewalManager.class.getName());
-	r.setSourceMethodName(sourceMethod);
-	r.setParameters(params);
-	r.setThrown(e);
-	logger.log(r);
-    }
-
-    /** Renew all of the leases (if multiple, all can be batched) */
-    private void renewAll(List bList, long now) {
-        Map lmeMap = null;
-	Throwable t = null;
-	List bad = null;
-
-	try {
-	    if (bList.size() == 1) {
-		Entry e = (Entry) bList.get(0);
-		logger.log(Level.FINE, "Renewing lease {0}", e.lease);
-		e.lease.renew(e.getRenewDuration(now));
-	    } else {
-		LeaseMap batchLeaseMap = createBatchLeaseMap(bList, now);
-		logger.log(Level.FINE, "Renewing leases {0}", batchLeaseMap);
-		batchLeaseMap.renewAll();
-	    }
-	} catch (LeaseMapException ex) {
-	    lmeMap = ex.exceptionMap;
-	    bad = new ArrayList(lmeMap.size());
-	} catch (Throwable ex) {
-	    t = ex;
-	    bad = new ArrayList(bList.size());  // They may all be bad
-	}
-
-	/*
-	 * For each lease we tried to renew determine the associated
-	 * exception (if any), and then ether add the lease back to
-	 * leases (if the renewal was successful), schedule a retry and
-	 * add back to leases (if the renewal was indefinite), or drop
-	 * the lease (by not adding it back to leases) and notify any
-	 * interested listeners.  In any event remove lease from the
-	 * list of leases being renewed.
-	 */
-
-	now = System.currentTimeMillis();
-	synchronized (this) {
-	    for (Iterator iter = bList.iterator(); iter.hasNext(); ) {
-		Entry e = (Entry) iter.next();
-
-		if (!removeLeaseInRenew(e))
-		    continue;
-
-		// Update the entries exception field 
-		if (bad == null) {
-		    e.ex = null;
-		} else {
-		    e.ex = (t != null) ? t : (Throwable) lmeMap.get(e.lease);
-		}
-
-		if (e.ex == null) {
-		    // No problems just put back in list
-		    insertEntry(e, now);
-		    continue;
-		} 
-
-		/*
-		 * Some sort of problem.  If definite don't put back
-		 * into leases and setup to notify the appropriate
-		 * listener, if indefinite schedule for a retry and put
-		 * back into leases
-		 */
-		final int cat = ThrowableConstants.retryable(e.ex);
-		if (cat == ThrowableConstants.INDEFINITE) {
-		    e.delayRenew();
-		    leases.put(e, e);
-		    if (logger.isLoggable(Levels.HANDLED)) {
-			logThrow(
-			    Levels.HANDLED, "renewAll",
-			    "Indefinite exception while renewing lease {0}",
-			    new Object[] { e.lease }, e.ex);
-		    }
-		} else {
-		    if (logger.isLoggable(Levels.FAILED)) {
-			logThrow(Levels.FAILED, "renewAll",
-				 "Lease renewal failed for lease {0}",
-				 new Object[] { e.lease }, e.ex);
-		    }
-		    if (e.listener != null) { 
-			/*
-			 * Note: For us ThrowableConstants.UNCATEGORIZED ==
-			 * definite
-			 */
-			bad.add(e);
-		    }	
-		}	
-	    }
-	    calcActualRenews(now);
-	}
-
-	if (bad != null)
-	    tell(bad);	
-    }
-
-    /** Create a LeaseMap for batch renewal */
-    private static LeaseMap createBatchLeaseMap(List bList, long now) {
-	Iterator iter = bList.iterator();
-	Entry e = (Entry) iter.next();
-	LeaseMap batchLeaseMap =
-	    e.lease.createLeaseMap(e.getRenewDuration(now));
-	if (e.lease instanceof RemoteMethodControl &&
-	    batchLeaseMap instanceof RemoteMethodControl)
-	{
-	    batchLeaseMap = (LeaseMap)
-		((RemoteMethodControl) batchLeaseMap).setConstraints(
-		    ConstrainableProxyUtil.translateConstraints(
-			((RemoteMethodControl) e.lease).getConstraints(),
-			leaseToLeaseMapMethods));
-	}
-	while (iter.hasNext()) {
-	    e = (Entry) iter.next();
-	    batchLeaseMap.put(e.lease, Long.valueOf(e.getRenewDuration(now)));
-	}
-	return batchLeaseMap;
-    }
-
-    /** Remove from leaseInRenew, return true if removed */
-    private boolean removeLeaseInRenew(Entry e) {
-	int index = leaseInRenew.indexOf(e); // avoid iterator cons
-	if (index < 0)
-	    return false;
-	leaseInRenew.remove(index);
-	return true;
-    }
-
-    /** Return the soonest actual renewal time */
-    private long wakeupTime() {
-	if (leases.isEmpty())
-	    return Long.MAX_VALUE;
-	return ((Entry) leases.lastKey()).actualRenew;
-    }
-
-    private class QueuerTask implements Runnable {
-
-	/** When to next wake up and queue a new renew task */
-	private long wakeup;
-
-	QueuerTask(long wakeup) {
-	    this.wakeup = wakeup;
-	}
-
-
-        public void run() {
-	    synchronized (LeaseRenewalManager.this) {
-		try {
-		    while (true) {
-			wakeup = wakeupTime();
-			if (wakeup == Long.MAX_VALUE && leaseInRenew.isEmpty())
-			    break;
-			final long now = System.currentTimeMillis();
-			long delta = wakeup - now;
-			if (delta <= 0) {
-			    leaseRenewalExecutor.execute(new RenewTask(now));
-			} else {
-			    LeaseRenewalManager.this.wait(delta);
-			}
-		    }
-		} catch (InterruptedException ex) {
-		}
-		queuer = null;
-	    }
-	}
-    }
-}
+/*
+ * 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 com.sun.jini.config.Config;
+import com.sun.jini.constants.ThrowableConstants;
+import com.sun.jini.logging.Levels;
+import com.sun.jini.logging.LogManager;
+import com.sun.jini.proxy.ConstrainableProxyUtil;
+import java.lang.reflect.Method;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+import net.jini.config.Configuration;
+import net.jini.config.ConfigurationException;
+import net.jini.core.constraint.RemoteMethodControl;
+import net.jini.core.lease.Lease;
+import net.jini.core.lease.LeaseException;
+import net.jini.core.lease.LeaseMap;
+import net.jini.core.lease.LeaseMapException;
+import net.jini.core.lease.UnknownLeaseException;
+import org.apache.river.impl.thread.NamedThreadFactory;
+
+/**
+ * Provides for the systematic renewal and overall management of a set
+ * of leases associated with one or more remote entities on behalf of a
+ * local entity.
+ * <p>
+ * This class removes much of the administrative burden associated with
+ * lease renewal. Clients of the renewal manager simply give their
+ * leases to the manager and the manager renews each lease as necessary
+ * to achieve a <em>desired expiration</em> time (which may be later
+ * than the lease's current <em>actual expiration</em> time). Failures
+ * encountered while renewing a lease can optionally be reflected to the
+ * client via <code>LeaseRenewalEvent</code> instances.
+ * <p>
+ * Note that this class is not remote. Entities wishing to use this
+ * class must create an instance of this class in their own virtual
+ * machine to locally manage the leases granted to them. If the virtual
+ * machine that the manager was created in exits or crashes, the renewal
+ * manager will be destroyed.
+ * <p>
+ * The <code>LeaseRenewalManager</code> distinguishes between two time
+ * values associated with lease expiration: the <em>desired
+ * expiration</em> time for the lease, and the <em>actual
+ * expiration</em> time granted when the lease is 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. The desired expiration
+ * time can be retrieved using the renewal manager's
+ * <code>getExpiration</code> method. The actual expiration time of a
+ * lease object can be retrieved by invoking the lease's
+ * <code>getExpiration</code> method.
+ * <p>
+ * Each lease in the managed set 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
+ * (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 lease is renewed, the renewal manager will ask for an
+ * extension equal to the lease's renewal duration if the renewal
+ * duration is:
+ * <ul>
+ * <li> <code>Lease.ANY</code>, 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>
+ * Once a lease is given to a lease renewal manager, the manager will
+ * continue to renew the lease until one of the following occurs:
+ * <ul>
+ * <li> The lease's desired or actual expiration time is reached.
+ * <li> An explicit removal of the lease from the set is requested via a
+ *	<code>cancel</code>, <code>clear</code>, or <code>remove</code>
+ *	call on the renewal manager.
+ * <li> The renewal manager tries to renew the lease and gets a bad
+ *	object exception, bad invocation exception, or
+ *	<code>LeaseException</code>.
+ * </ul>
+ * <p>
+ * The methods of this class are appropriately synchronized for
+ * concurrent operation. Additionally, this class makes certain
+ * guarantees with respect to concurrency. When this class makes a
+ * remote call (for example, when requesting the renewal of a lease),
+ * any invocations made on the methods of this class will not be
+ * blocked. Similarly, this class makes a reentrancy guarantee with
+ * respect to the listener objects registered with this class. Should
+ * this class invoke a method on a registered listener (a local call),
+ * calls from that method to any other method of this class are
+ * guaranteed not to result in a deadlock condition.
+ *
+ * @author Sun Microsystems, Inc.
+ * @see Lease
+ * @see LeaseException
+ * @see LeaseRenewalEvent 
+ *
+ * @com.sun.jini.impl <!-- Implementation Specifics -->
+ *
+ * The following implementation-specific items are discussed below:
+ * <ul>
+ * <li><a href="#configEntries">Configuring LeaseRenewalManager</a>
+ * <li><a href="#logging">Logging</a>
+ * <li><a href="#algorithm">The renewal algorithm</a>
+ * </ul>
+ *
+ * <a name="configEntries">
+ * <p><b><font size="+1">Configuring LeaseRenewalManager</font></b><p>
+ * </a>
+ *
+ * This implementation of <code>LeaseRenewalManager</code> supports the
+ * following configuration entries, with component
+ * <code>net.jini.lease.LeaseRenewalManager</code>:
+ *
+ * <table summary="Describes the renewBatchTimeWindow configuration entry"
+ *	  border="0" cellpadding="2">
+ *   <tr valign="top">
+ *     <th scope="col" summary="layout"> <font size="+1">&#X2022;</font>
+ *     <th scope="col" align="left" colspan="2"> <font size="+1"><code>
+ *	 renewBatchTimeWindow</code></font>
+ *   <tr valign="top"> <td> &nbsp <th scope="row" align="right">
+ *     Type: <td> <code>long</code>
+ *   <tr valign="top"> <td> &nbsp <th scope="row" align="right">
+ *     Default: <td> <code>5 * 60 * 1000 // 5 minutes</code>
+ *   <tr valign="top"> <td> &nbsp <th scope="row" align="right">
+ *     Description: <td> The maximum number of milliseconds earlier than
+ *     a lease would typically be renewed to allow it to be renewed in
+ *     order to permit batching its renewal with that of other
+ *     leases. The value must not be negative. This entry is obtained
+ *     in the constructor.
+ * </table>
+ * <table summary="Describes the roundTripTime configuration entry"
+ *	  border="0" cellpadding="2">
+ *   <tr valign="top">
+ *     <th scope="col" summary="layout"> <font size="+1">&#X2022;</font>
+ *     <th scope="col" align="left" colspan="2"> <font size="+1"><code>
+ *	 roundTripTime</code></font>
+ *   <tr valign="top"> <td> &nbsp <th scope="row" align="right">
+ *     Type: <td> <code>long</code>
+ *   <tr valign="top"> <td> &nbsp <th scope="row" align="right">
+ *     Default: <td> <code>10 * 1000 // 10 seconds</code>
+ *   <tr valign="top"> <td> &nbsp <th scope="row" align="right">
+ *     Description: <td> The worst-case latency, expressed in milliseconds,
+ *     to assume for a remote call to renew a lease. The value must be greater 
+ *     than zero. Unrealistically low values for this entry may
+ *     result in failure to renew a lease. Leases managed by this manager
+ *     should have durations exceeding the <code>roundTripTime</code>.
+ *     This entry is obtained in the constructor.
+ * </table>
+ * <table summary="Describes the executorService configuration entry"
+ *	  border="0" cellpadding="2">
+ *   <tr valign="top">
+ *     <th scope="col" summary="layout"> <font size="+1">&#X2022;</font>
+ *     <th scope="col" align="left" colspan="2"> <font size="+1"><code>
+ *	 executorService</code></font>
+ *   <tr valign="top"> <td> &nbsp <th scope="row" align="right">
+ *     Type: <td> {@link ExecutorService}
+ *   <tr valign="top"> <td> &nbsp <th scope="row" align="right">
+ *     Default: <td> <code>new ThreadPoolExecutor(1,11,15,TimeUnit.SECONDS,
+ *     new LinkedBlockingQueue())</code>
+ *   <tr valign="top"> <td> &nbsp <th scope="row" align="right">
+ *     Description: <td> The object used to manage queuing tasks
+ *     involved with renewing leases and sending notifications. The
+ *     value must not be <code>null</code>. The default value creates
+ *     a maximum of 11 threads for performing operations, waits 15
+ *     seconds before removing idle threads, and uses a load factor of
+ *     1.0 when determining whether to create a new thread. Note that
+ *     the implementation of the renewal algorithm includes an assumption
+ *     that the <code>ExecutorService</code> uses a load factor of 1.0.
+ * </table>
+ * 
+ * <a name="logging">
+ * <p><b><font size="+1">Logging</font></b><p>
+ * </a>
+ *
+ * This implementation uses the {@link Logger} named
+ * <code>net.jini.lease.LeaseRenewalManager</code> to log information at
+ * the following logging levels: <p>
+ *
+ * <table border="1" cellpadding="5"
+ *	  summary="Describes logging performed by the
+ *		   LeaseRenewalManager at different logging levels">
+ *
+ * <caption halign="center" valign="top"><b><code>
+ *	    net.jini.lease.LeaseRenewalManager</code></b></caption>
+ *
+ * <tr> <th scope="col"> Level <th scope="col"> Description
+ *
+ * <tr> <td> {@link Levels#FAILED FAILED}
+ *	<td> Lease renewal failure events, or leases that expire before
+ *           reaching the desired expiration time
+ *
+ * <tr> <td> {@link Levels#HANDLED HANDLED}
+ *	<td> Lease renewal attempts that produce indefinite exceptions
+ *
+ * <tr> <td> {@link Level#FINE FINE}
+ *	<td> Adding and removing leases, lease renewal attempts, and desired
+ *	     lease expiration events
+ *
+ * </table> <p>
+ *
+ * For a way of using the <code>FAILED</code> and <code>HANDLED</code> logging
+ * levels in standard logging configuration files, see the {@link LogManager}
+ * class.
+ *
+ * <a name="algorithm">
+ * <p><b><font size="+1">The renewal algorithm</font></b><p>
+ * </a>
+ * The time at which a lease is scheduled for renewal is based on the
+ * expiration time of the lease, possibly adjusted to account for the
+ * latency of the remote renewal call. The configuration entry
+ * <code>roundTripTime</code>, which defaults to ten seconds, represents
+ * the total time to make the remote call. 
+ * <p>
+ * The following pseudocode was derived from the code which computes
+ * the renewal time. In this code, <code>rtt</code> represents the
+ * value of the <code>roundTripTime</code>:
+ *
+ * <pre>    
+ *          endTime = lease.getExpiration();
+ *          delta = endTime - now;
+ *          if (delta <= rtt * 2) {
+ *	        delta = rtt;
+ *          } else if (delta <= rtt * 8) {
+ *	        delta /= 2;
+ *          } else if (delta <= 1000 * 60 * 60 * 24 * 7) {
+ *	        delta /= 8;
+ *          } else if (delta <= 1000 * 60 * 60 * 24 * 14) {
+ *	        delta = 1000 * 60 * 60 * 24;
+ *          } else {
+ *	        delta = 1000 * 60 * 60 * 24 * 3;
+ *          }
+ *          renew = endTime - delta;
+ *</pre>
+ *
+ * It is important to note that <code>delta</code> is never less than
+ * <code>rtt</code> when the renewal time is computed. A lease which 
+ * would expire within this time range will be scheduled for immediate
+ * renewal. The use of very short lease durations (at or below <code>rtt</code>)
+ * can cause the renewal manager to effectively ignore the lease duration
+ * and repeatedly schedule the lease for immediate renewal.
+ * <p>
+ * If an attempt to renew a lease fails with an indefinite exception, a
+ * renewal is rescheduled with an updated renewal time as computed by the
+ * following pseudocode:
+ *
+ * <pre>
+ *          delta = endTime - renew;
+ *          if (delta > rtt) {
+ *              if (delta <= rtt * 3) {
+ *	            delta = rtt;
+ *              } else if (delta <= 1000 * 60 * 60) {
+ *	            delta /= 3;
+ *              } else if (delta <= 1000 * 60 * 60 * 24) {
+ *	            delta = 1000 * 60 * 30;
+ *              } else if (delta <= 1000 * 60 * 60 * 24 * 7) {
+ *	            delta = 1000 * 60 * 60 * 3;
+ *              } else {
+ *	            delta = 1000 * 60 * 60 * 8;
+ *              }
+ *              renew += delta;
+ *          }
+ * </pre>
+ *
+ * Client leases are maintained in a collection sorted by descending renewal
+ * time. A renewal thread is spawned whenever the renewal time of the last lease
+ * in the collection is reached. This renewal thread examines all of the leases
+ * in the collection whose renewal time falls within
+ * <code>renewBatchTimeWindow</code> milliseconds of the renewal time of the
+ * last lease. If any of these leases can be batch renewed with the last lease (as
+ * determined by calling the {@link Lease#canBatch canBatch} method of
+ * the last lease) then a {@link LeaseMap} is created, all eligible leases
+ * are added to it and the {@link LeaseMap#renewAll} method is called. Otherwise, the
+ * last lease is renewed directly.
+ * <p> 
+ * The <code>ExecutorService</code> that manages the renewal threads has a bound on
+ * the number of simultaneous threads it will support. The renewal time of
+ * leases may be adjusted earlier in time to reduce the likelihood that the
+ * renewal of a lease will be delayed due to exhaustion of the thread pool.
+ * Actual renewal times are determined by starting with the lease with the
+ * latest (farthest off) desired renewal time and working backwards.  When
+ * computing the actual renewal time for a lease, the renewals of all leases
+ * with later renewal times, which will be initiated during the round trip time
+ * of the current lease's renewal, are considered.  If using the desired
+ * renewal time for the current lease would result in more in-progress renewals
+ * than the number of threads allowed, the renewal time of the current lease is
+ * shifted earlier in time, such that the maximum number of threads is not
+ * exceeded.
+ * 
+ */
+
+public class LeaseRenewalManager {
+
+    private static final String LRM = "net.jini.lease.LeaseRenewalManager";
+
+    private static final Logger logger = Logger.getLogger(LRM);
+
+    /* Method objects for manipulating method constraints */
+    private static final Method cancelMethod;
+    private static final Method cancelAllMethod;
+    private static final Method renewMethod;
+    private static final Method renewAllMethod;
+    static {
+	try {
+	    cancelMethod = Lease.class.getMethod(
+		"cancel", new Class[] { });
+	    cancelAllMethod = LeaseMap.class.getMethod(
+		"cancelAll", new Class[] { });
+	    renewMethod = Lease.class.getMethod(
+		"renew", new Class[] { long.class });
+	    renewAllMethod = LeaseMap.class.getMethod(
+		"renewAll", new Class[] { });
+	} catch (NoSuchMethodException e) {
+	    throw new NoSuchMethodError(e.getMessage());
+	}
+    }
+
+    /* Methods for comparing lease constraints. */
+    private static final Method[] leaseToLeaseMethods = {
+	cancelMethod, cancelMethod, renewMethod, renewMethod
+    };
+
+    /* Methods for converting lease constraints to lease map constraints. */
+    private static final Method[] leaseToLeaseMapMethods = {
+	cancelMethod, cancelAllMethod, renewMethod, renewAllMethod
+    };
+
+    /** Time window in which to look for batchable leases */
+    private long renewBatchTimeWindow = 1000 * 60 * 5;
+
+    /** Task manager for queuing and renewing leases 
+     *  NOTE: test failures occur with queue's that have capacity, 
+     *  no test failures occur with SynchronousQueue, for the time
+     *  being, until the cause is sorted out we may need to rely on 
+     *  a larger pool, if necessary.  TaskManager is likely to have 
+     *  lower throughput capacity that ExecutorService with a
+     *  SynchronousQueue although this hasn't been confirmed yet.
+     */
+    final ExecutorService leaseRenewalExecutor;
+
+    /**
+     * The worst-case renewal round-trip-time
+     */
+    private static long renewalRTT = 10 * 1000;
+
+    /** 
+     * Entries for leases that are not actively being renewed.
+     * Lease with the earliest renewal is last in the map.
+     */
+    private final SortedMap leases = new TreeMap();
+
+    /** Entries for leases that are actively being renewed */
+    private final List leaseInRenew = new ArrayList(1);
+    /** The queuer task */
+    private QueuerTask queuer = null;
+
+    /**
+     * Used to determine concurrency constraints when calculating actual
+     * renewals.  The list is stored in a field to avoid reallocating it.
+     */
+    private List calcList;
+
+    private final class RenewTask implements Runnable {
+	/** Entries of leases to renew (if multiple, all can be batched) */
+	private final List bList;
+
+	/** 
+	 * True if this task only holds leases that have reached their
+	 * actual or desired expiration
+	 */
+	private final boolean noRenewals;
+
+	/**
+	 * Create a collection of entries whose leases can be batch
+	 * renewed with the last lease in the map, or a list of entries
+	 * whose leases need to be removed.  Which is created depends on
+	 * the state of the last lease in the map.  Remove each entry
+	 * from the map, and add them to leaseInRenew.
+	 */
+	RenewTask(long now) {
+	    bList = new ArrayList(1);
+	    Entry e = (Entry) leases.lastKey();
+
+	    if (e.renewalsDone() || e.endTime <= now) {
+		noRenewals = true;
+		Map lMap = leases.tailMap(new Entry(now));
+		for (Iterator iter = lMap.values().iterator(); 
+		     iter.hasNext(); )
+		{
+		    Entry be = (Entry) iter.next();
+		    if (be.renewalsDone() || be.endTime <= now) {
+			iter.remove();
+			logExpiration(be);
+			/*
+			 * Only add to bList if we need to tell someone
+			 * about this lease's departure
+			 */
+			if (be.listener != null)
+			    bList.add(be);
+		    }
+		}
+	    } else {
+		noRenewals = false;
+		Map lMap = leases.tailMap(
+		    new Entry(e.renew + renewBatchTimeWindow));
+		for (Iterator iter = lMap.values().iterator(); 
+		     iter.hasNext(); )
+		{
+		    Entry be = (Entry) iter.next();
+		    if (be == e || be.canBatch(e)) {
+			iter.remove();
+			leaseInRenew.add(be);
+			bList.add(be);
+		    }
+		}
+	    }
+	}
+
+	public void run() {
+	    if (noRenewals) {
+		// Just notify
+		tell(bList);
+	    } else {
+		/*
+		 * Get rid of any leases that have expired and then do
+		 * renewals
+		 */
+		long now = System.currentTimeMillis();
+		List bad = processBadLeases(now);
+		if (!bList.isEmpty())
+		    renewAll(bList, now);
+		if (bad != null)
+		    tell(bad);
+	    }
+	}
+
+	/**
+	 * Find any expired leases, remove them from bList and
+	 * leaseInRenew, and return any with listeners.
+	 */
+	private List processBadLeases(long now) {
+	    List bad = null;
+	    synchronized (LeaseRenewalManager.this) {
+		for (Iterator iter = bList.iterator(); iter.hasNext(); ) {
+		    Entry e = (Entry) iter.next();
+		    if (e.endTime <= now) {
+			iter.remove();
+			logExpiration(e);
+			removeLeaseInRenew(e);
+			if (e.listener != null) {
+			    if (bad == null)
+				bad = new ArrayList(1);
+			    bad.add(e);
+			}
+		    }
+		}
+	    }
+	    return bad;
+	}
+    }
+
+    private static class Entry implements Comparable {
+	/*
+	 * Since the cnt only gets modified in the constructor, and the
+	 * constructor is always called from synchronized code, the cnt
+	 * does not need to be synchronized.
+	 */
+	private static long cnt = 0;
+
+	/** Unique id */
+	public final long id;
+	/** The lease */
+	public final Lease lease;
+	/** Desired expiration */
+	public long expiration;
+	/** Renew duration */
+	public long renewDuration;
+	/** The listener, or null */
+	public final LeaseListener listener;
+	/** Current actual expiration */
+	public long endTime;
+
+	/** 
+	 * The next time we have to do something with this lease.
+	 * Usually a renewal, but could be removing it from the managed
+	 * set because its desired expiration has been reached.
+	 */
+	public long renew;
+
+	/** Actual time to renew, given concurrency limitations */
+	public long actualRenew;
+	/** Renewal exception, or null */
+	public Throwable ex = null;
+
+	public Entry(Lease lease,
+		     long expiration,
+		     long renewDuration,
+		     LeaseListener listener)
+	{
+	    this.endTime = lease.getExpiration();
+	    this.lease = lease;
+	    this.expiration = expiration;
+	    this.renewDuration = renewDuration;
+	    this.listener = listener;
+	    id = cnt++;
+	}
+
+	/** Create a fake entry for tailMap */
+	public Entry(long renew) {
+	    this.renew = renew;
+	    id = Long.MAX_VALUE;
+	    lease = null;
+	    listener = null;
+	}
+
+	/**
+	 * If the renewDuration is ANY, return ANY, otherwise return the
+	 * minimum of the renewDuration and the time remaining until the
+	 * desired expiration.
+	 */
+	public long getRenewDuration(long now) {
+	    if (renewDuration == Lease.ANY)
+		return renewDuration;
+	    return Math.min(expiration - now, renewDuration);
+	}
+
+	/** Calculate the renew time for the lease entry */
+	public void calcRenew(long now) {
+	    endTime = lease.getExpiration();
+	    if (renewalsDone()) {
+		if (null == desiredExpirationListener()) {
+		    // Nothing urgent needs to be done with this lease
+		    renew = Long.MAX_VALUE;
+		} else {
+		    /*
+		     * Tell listener about dropping this lease in a
+		     * timely fashion
+		     */
+		    renew = expiration; 
+		}
+		return;
+	    }
+	    long delta = endTime - now;
+	    if (delta <= renewalRTT * 2) {
+		delta = renewalRTT;
+	    } else if (delta <= renewalRTT * 8) {
+		delta /= 2;
+	    } else if (delta <= 1000 * 60 * 60 * 24 * 7) {
+		delta /= 8;
+	    } else if (delta <= 1000 * 60 * 60 * 24 * 14) {
+		delta = 1000 * 60 * 60 * 24;
+	    } else {
+		delta = 1000 * 60 * 60 * 24 * 3;
+	    }
+	    renew = endTime - delta;
+	}
+
+	/** Calculate a new renew time due to an indefinite exception */
+	public void delayRenew() {
+	    long delta = endTime - renew;
+	    if (delta <= renewalRTT) {
+		return;
+	    } else if (delta <= renewalRTT * 3) {
+		 delta = renewalRTT;
+	    } else if (delta <= 1000 * 60 * 60) {
+		delta /= 3;
+	    } else if (delta <= 1000 * 60 * 60 * 24) {
+		delta = 1000 * 60 * 30;
+	    } else if (delta <= 1000 * 60 * 60 * 24 * 7) {
+		delta = 1000 * 60 * 60 * 3;
+	    } else {
+		delta = 1000 * 60 * 60 * 8;
+	    }
+	    renew += delta;
+	}
+
+	/** Sort by decreasing renew time, secondary sort by decreasing id */
+	public int compareTo(Object obj) {
+	    if (this == obj)
+		return 0;
+	    Entry e = (Entry) obj;
+	    if (renew < e.renew || (renew == e.renew && id < e.id))
+		return 1;
+	    return -1;
+	}
+
+	/**
+	 * Returns true if the renewal of this lease can be batched with
+	 * the (earlier) renewal of the given lease.  This method must
+	 * be called with an entry such that e.renew <= this.renew. <p>
+	 * 
+	 * First checks that both leases require renewal, have the same
+	 * client constraints, and can be batched.  Then enforces
+	 * additional requirements to avoid renewing the lease too much
+	 * more often than necessary. <p>
+	 *
+	 * One of the following must be true: <ul>
+	 *
+	 * <li> This lease has a renewal duration of Lease.ANY, meaning
+	 * it doesn't specify its renewal duration.
+	 *
+	 * <li> The amount of time from the other lease's renewal time
+	 * to this one's is less than half of the estimated time needed
+	 * to perform renewals (renewalRTT).  In this case, the renewal
+	 * times are so close together that the renewal duration
+	 * shouldn't be materially affected.
+	 *
+	 * <li> This lease's expiration time is no more than half its
+	 * renewal duration greater than the renewal time of the other
+	 * lease.  This case insures that this lease is not renewed
+	 * until at least half of it's renewal duration has
+	 * elapsed. </ul> <p>
+	 *
+	 * In addition, one of the following must be true: <ul>
+	 *
+	 * <li> The other lease has a renewal duration of Lease.ANY,
+	 * meaning we don't know how long its next renewal will be.
+	 *
+	 * <li> The other lease is not going to be renewed again before
+	 * this lease's renewal time, because either its next renewal
+	 * will last until after this lease's renewal time or it will
+	 * only be renewed once more. </ul>
+	 */
+	public boolean canBatch(Entry e) {
+	    return (!renewalsDone() &&
+		    !e.renewalsDone() &&
+		    sameConstraints(lease, e.lease) &&
+		    lease.canBatch(e.lease) &&
+		    (renewDuration == Lease.ANY ||
+		     renew - e.renew <= renewalRTT / 2 ||
+		     endTime - e.renew <= renewDuration / 2) &&
+		    (e.renewDuration == Lease.ANY ||
+		     e.renew > renew - e.renewDuration ||
+		     e.renew >= e.expiration - e.renewDuration));
+	}
+
+	/**
+	 * Returns true if the two leases both implement RemoteMethodControl
+	 * and have the same constraints for Lease methods, or both don't
+	 * implement RemoteMethodControl, else returns false.
+	 */
+	private static boolean sameConstraints(Lease l1, Lease l2) {
+	    if (!(l1 instanceof RemoteMethodControl)) {
+		return !(l2 instanceof RemoteMethodControl);
+	    } else if (!(l2 instanceof RemoteMethodControl)) {
+		return false;
+	    } else {
+		return ConstrainableProxyUtil.equivalentConstraints(
+		    ((RemoteMethodControl) l1).getConstraints(),
+		    ((RemoteMethodControl) l2).getConstraints(),
+		    leaseToLeaseMethods);
+	    }
+	}
+
+	/**
+	 * Return the DesiredExpirationListener associated with this
+	 * lease, or null if there is none.
+	 */
+	public DesiredExpirationListener desiredExpirationListener() {
+	    if (listener == null)
+		return null;
+
+	    if (listener instanceof DesiredExpirationListener) 
+		return (DesiredExpirationListener) listener;
+
+	    return null;
+	}
+
+	/**
+	 * Return true if the actual expiration is greater than or equal
+	 * to the desired expiration (e.g. we don't need to renew this
+	 * lease any more.
+	 */
+	public boolean renewalsDone() {
+	    return expiration <= endTime;
+	}
+    }
+
+    /**
+     * No-argument constructor that creates an instance of this class
+     * that initially manages no leases.
+     */
+    public LeaseRenewalManager() {
+        leaseRenewalExecutor = 
+            new ThreadPoolExecutor(
+                    1,  /* min threads */
+                    11, /* max threads */
+                    15,
+                    TimeUnit.SECONDS, 
+                    new SynchronousQueue<Runnable>(), /* Queue has no capacity */
+                    new NamedThreadFactory("LeaseRenewalManager",false),
+                    new CallerRunsPolicy()
+            );
+    }
+
+    /**
+     * Constructs an instance of this class that initially manages no leases
+     * and that uses <code>config</code> to control implementation-specific
+     * details of the behavior of the instance created.
+     *
+     * @param config supplies entries that control the configuration of this
+     *	      instance
+     * @throws ConfigurationException if a problem occurs when obtaining
+     *	       entries from the configuration
+     * @throws NullPointerException if the configuration is <code>null</code>
+     */
+    public LeaseRenewalManager(Configuration config)
+	throws ConfigurationException
+    {
+	if (config == null) {
+	    throw new NullPointerException("config is null");
+	}
+	renewBatchTimeWindow = Config.getLongEntry(
+	    config, LRM, "renewBatchTimeWindow",
+	    renewBatchTimeWindow, 0, Long.MAX_VALUE);
+	renewalRTT = Config.getLongEntry(
+	    config, LRM, "roundTripTime",
+	    renewalRTT, 1, Long.MAX_VALUE);
+	leaseRenewalExecutor = Config.getNonNullEntry(
+            config, 
+            LRM, 
+            "executorService", 
+            ExecutorService.class,
+            new ThreadPoolExecutor(
+                    1,  /* Min Threads */
+                    11, /* Max Threads */

[... 844 lines stripped ...]