Source for gnu.java.rmi.dgc.LeaseRenewingTask

   1: /* LeaseRenewingTask.java -- The task to renew the lease.
   2:    Copyright (C) 2006 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package gnu.java.rmi.dgc;
  40: 
  41: import gnu.java.rmi.server.UnicastRef;
  42: 
  43: import java.lang.ref.WeakReference;
  44: import java.rmi.dgc.Lease;
  45: import java.util.Iterator;
  46: import java.util.LinkedList;
  47: import java.util.Timer;
  48: import java.util.TimerTask;
  49: import java.util.WeakHashMap;
  50: 
  51: /**
  52:  * The task to renew the lease to some object reference. The UnicastRef
  53:  * being renewed is stored as a weak reference. So the presence of the
  54:  * sheduled task does not prevent it from being garbage collected. If the
  55:  * reference has not been garbage collected, the task is resheduled after
  56:  * the lease is renewed.
  57:  *
  58:  *  @author Audrius Meskauskas (Audriusa@Bioinformatics.org)
  59:  */
  60: public class LeaseRenewingTask
  61: {
  62:   /**
  63:    * The sheduled timer task to call the renew() method.
  64:    */
  65:   class LeaseTimerTask extends TimerTask
  66:   {
  67:     public void run()
  68:     {
  69:       renew();
  70:     }
  71:   }
  72: 
  73:   /**
  74:    * The default requested lease duration time (one minute by default).
  75:    */
  76:   public static long REQUEST_LEASE_DURATION =  60000;
  77: 
  78:   /**
  79:    * The reference to the UnicastRef that must renew its lease until not
  80:    * garbage collected. The different members of this list may point to the
  81:    * different instances of the UnicastRef's, but these references are
  82:    * pointing to the same remote object (they .equals() returns
  83:    * true when comparing with each other). Using LinkedList to make
  84:    * frequent deletions from the middle easy.
  85:    */
  86:   LinkedList ref = new LinkedList();
  87: 
  88:   /**
  89:    * The granted (or supposed) lease.
  90:    */
  91:   Lease lease = new Lease(null, REQUEST_LEASE_DURATION);
  92: 
  93:   /**
  94:    * The timer, shared by all lease renewing tasks. The same instance is also
  95:    * used for the reference protector discarding in DGCImpl.
  96:    */
  97:   static Timer timer = new Timer(true);
  98: 
  99:   /**
 100:    * Maps the UnicastRef to its renewing task.
 101:    */
 102:   static WeakHashMap existingTasks = new WeakHashMap();
 103: 
 104:   /**
 105:    * Creates the lease renewing task that renews the lease of the given
 106:    * UnicastRef until it is not collected. This constructor requests the lease
 107:    * value from the server and schedules the lease renewal action.
 108:    *
 109:    * @param renewIt the reference that must be renewed.
 110:    */
 111:   public LeaseRenewingTask(UnicastRef renewIt)
 112:   {
 113:     lease = notifyDGC(renewIt);
 114:     if (lease != null)
 115:       {
 116:         schedule(lease);
 117:         ref.add(new WeakReference(renewIt));
 118:       }
 119:   }
 120: 
 121:   /**
 122:    * Schedule periodic leases for the given UnicastRef reference.
 123:    *
 124:    * @param renewIt the reference, for that the leases must be scheduled.
 125:    */
 126:   public static void scheduleLeases(UnicastRef renewIt)
 127:   {
 128:     // No need to schedule leases for null.
 129:     if (renewIt == null)
 130:       return;
 131:     try {
 132:     synchronized (existingTasks)
 133:       {
 134:         // Check maybe the task for refreshing this remote object already
 135:         // exists.
 136:         LeaseRenewingTask task = (LeaseRenewingTask) existingTasks.get(renewIt);
 137: 
 138:         if (task != null)
 139:           {
 140:             // Extend the reference list only. The scheduling must be
 141:             // alredy done with the previous lease.
 142:             synchronized (task.ref)
 143:               {
 144:                 task.ref.add(new WeakReference(renewIt));
 145:               }
 146:           }
 147:         else
 148:           existingTasks.put(renewIt, new LeaseRenewingTask(renewIt));
 149:       }
 150:     }
 151:     catch (Exception ex)
 152:     {
 153:       InternalError ierr = new InternalError("Lease for "+renewIt);
 154:       ierr.initCause(ex);
 155:       throw ierr;
 156:     }
 157:   }
 158: 
 159:   /**
 160:    * Shedule the renewing call, taking into consideration that the following
 161:    * lease was granted.
 162:    *
 163:    * @param lease the lease that was granted.
 164:    */
 165:   public void schedule(Lease lease)
 166:   {
 167:     long value = lease.getValue();
 168: 
 169:     // Shedule a 10 % earlier because some time is needed for the message
 170:     // to reach the server.
 171:     long reduced = (value * 90)/100;
 172:     if (reduced == 0)
 173:       reduced = value;
 174: 
 175:     timer.schedule(new LeaseTimerTask(), reduced);
 176:   }
 177: 
 178:   /**
 179:    * Renew the lease.
 180:    */
 181:   public void renew()
 182:   {
 183:     Object renewIt = null;
 184:     // Iterate throw the list of associated references. If all are
 185:     // discarded, there is no need to renew.
 186:     synchronized (ref)
 187:     {
 188:       Iterator iter = ref.iterator();
 189:       WeakReference w;
 190:       while (iter.hasNext() && renewIt == null)
 191:         {
 192:           w = (WeakReference) iter.next();
 193:           renewIt = w.get();
 194:           if (renewIt == null)
 195:             // Discard the weak reference if its target has been garbage
 196:             // collected.
 197:             iter.remove();
 198:         }
 199:     }
 200: 
 201:     if (renewIt!=null)
 202:       {
 203:         Lease lease = notifyDGC( (UnicastRef) renewIt);
 204: 
 205:         // Schedule the next renewing session.
 206:         if (lease!=null)
 207:           schedule(lease);
 208:       }
 209:       {
 210:         // All references collected - discard this entry.
 211:       }
 212:   }
 213: 
 214:   /**
 215:    * Notify DGC that we still hold this reference.
 216:    *
 217:    * @param renewIt the reference we still have (must not be null).
 218:    */
 219:   public Lease notifyDGC(UnicastRef renewIt)
 220:   {
 221:     try
 222:       {
 223:         return renewIt.notifyDGC(lease);
 224:       }
 225:     catch (Exception e)
 226:       {
 227:         // Failed to notify.
 228:         // TODO Take some relevant action in the case if we failed
 229:         // to notify the remote object owner.
 230:         return null;
 231:       }
 232:   }
 233: 
 234: }