Skip to main content
summaryrefslogtreecommitdiffstats
blob: 18b07b12b2926c89d9328e289d218553b727fb80 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*******************************************************************************
 * Copyright (c) 2004, 2007 Boeing.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Boeing - initial API and implementation
 *******************************************************************************/
package org.eclipse.osee.framework.jini.lease;

import java.rmi.RemoteException;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import net.jini.core.lease.Lease;
import net.jini.core.lease.LeaseDeniedException;
import net.jini.core.lease.UnknownLeaseException;
import org.eclipse.osee.framework.jini.JiniPlugin;
import org.eclipse.osee.framework.logging.OseeLog;

/**
 * This class handles the renewal of leases. It is designed such that a lease will be renewed a set amount of time prior
 * to expiration, and handles retrying in cases where the renewal fails. Leases are renewed for the maximum amount of
 * time the lease will allow. Retries are be scheduled for half of the remaining lease time. For example, if the first
 * attempt to renew occurs with 2 minutes left, the first retry will occur with 1 minute, then 30 seconds, until
 * STOP_RETRY_TIME is reached.
 * 
 * @author David Diepenbrock
 */
public class OseeLeaseRenewer {

   private Timer timer;
   private final Map<OseeLease, Renewer> map;

   /**
    * The amount of time before a lease expires to first attempt renewal. This amount of time should be sufficiently
    * large to account for delays in communication (i.e. network delays), and allow for at least a few retries in the
    * event the service is not reachable. This time is specified in milliseconds.
    */
   private static final long RENEWAL_TIME = 2 * 60 * 1000; // 2 minutes
   /**
    * When less than this amount of time is remaining in a lease, failed renewal attempts will not be retried. This time
    * is specified in milliseconds.
    */
   private static final long STOP_RETRY_TIME = 250; // 250 ms

   public OseeLeaseRenewer() {
      // debug = new Debug(false, true, this.getClass().getName());
      map = new HashMap<OseeLease, Renewer>(4);
   }

   /**
    * Attempts to maintain a lease until cancelRenewal is called
    * 
    * @param lease
    */
   public synchronized void startRenewal(OseeLease lease) {
      if (timer == null) {
         timer = new Timer(true);
      }

      lease.resetStartTime();
      Renewer renewer = new Renewer(lease);
      map.put(lease, renewer);

      // Pick the larger duration - RENEWAL_TIME before the expiration, or half of the total lease
      // time.
      long duration = Math.max(lease.getDuration() / 2, lease.getDuration() - RENEWAL_TIME);
      timer.schedule(renewer, duration, duration);
   }

   /**
    * Prevents the lease from being renewed. This does not cancel the lease, only the renewal attempts.
    * 
    * @param lease
    */
   public synchronized void cancelRenewal(OseeLease lease) {
      Renewer renewer = map.remove(lease);
      if (renewer != null) {
         renewer.cancel();
      } else {
         OseeLog.log(JiniPlugin.class, Level.WARNING,
               this.getClass().getName() + ": Lease Cancel Attempt: Lease Not Found!");
      }

      if (map.isEmpty()) {
         timer.cancel();
         timer = null;
      }
   }

   private class Renewer extends TimerTask {

      private final OseeLease lease;

      public Renewer(OseeLease lease) {
         super();
         this.lease = lease;
      }

      @Override
      public void run() {
         try {
            // Obtain the longest lease allowed
            lease.renew(Lease.FOREVER);
         } catch (LeaseDeniedException ex) {
            OseeLog.log(JiniPlugin.class, Level.SEVERE, ex);
         } catch (UnknownLeaseException ex) {
            OseeLog.log(JiniPlugin.class, Level.SEVERE, ex);
         }
         /*
          * If there was a problem with the lease renewal, retry up until there is less than 250 ms
          * remaining in the lease, at which point we can give up hope. Assuming leases are renewed
          * with 2 minutes remaining & 250 ms for STOP_RETRY_TIME, this will provide 8 attempts.
          */
         catch (RemoteException ex) {
            long remainingTime = lease.getExpiration() - System.currentTimeMillis();
            if (remainingTime > STOP_RETRY_TIME) {
               timer.schedule(new Renewer(lease), remainingTime / 2);
            } else {
               // debug.report("Canceling Renewals Retries");
               cancelRenewal(lease);
               OseeLog.log(JiniPlugin.class, Level.SEVERE, "Unable to renew lease.", ex);
            }
         }
      }
   }
}

Back to the top