~ubuntu-branches/ubuntu/raring/libjboss-remoting-java/raring

« back to all changes in this revision

Viewing changes to src/main/org/jboss/remoting/LeasePinger.java

  • Committer: Package Import Robot
  • Author(s): Torsten Werner
  • Date: 2011-09-09 14:01:03 UTC
  • mfrom: (1.1.6 upstream)
  • Revision ID: package-import@ubuntu.com-20110909140103-hqokx61534tas9rg
Tags: 2.5.3.SP1-1
* Newer but not newest upstream release. Do not build samples.
* Change debian/watch to upstream's svn repo.
* Add patch to fix compile error caused by tomcat update.
  (Closes: #628303)
* Switch to source format 3.0.
* Switch to debhelper level 7.
* Remove useless Depends.
* Update Standards-Version: 3.9.2.
* Update README.source.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package org.jboss.remoting;
 
2
 
 
3
import org.jboss.logging.Logger;
 
4
import org.jboss.remoting.transport.ClientInvoker;
 
5
import java.util.HashMap;
 
6
import java.util.Iterator;
 
7
import java.util.Map;
 
8
import java.util.Timer;
 
9
import java.util.TimerTask;
 
10
 
 
11
import java.util.concurrent.ConcurrentHashMap;
 
12
 
 
13
/**
 
14
 * Internal agent class to ping the remote server to keep lease alive.
 
15
 *
 
16
 * @author <a href="mailto:telrod@e2technologies.net">Tom Elrod</a>
 
17
 * @author <a href="mailto:ovidiu@ejboss.org">Ovidiu Feodorov</a>
 
18
 */
 
19
public class LeasePinger
 
20
{
 
21
   // Constants ------------------------------------------------------------------------------------
 
22
 
 
23
   private static final Logger log = Logger.getLogger(LeasePinger.class);
 
24
 
 
25
   public static final long DEFAULT_LEASE_PERIOD = 5000;
 
26
   public static final int DEFAULT_DISCONNECT_TIMEOUT = -1;
 
27
   public static final String LEASE_PINGER_TIMEOUT = "leasePingerTimeout";
 
28
 
 
29
   static final String LEASE_PINGER_ID = "leasePingerId";
 
30
   static final String TIME_STAMP = "timeStamp";
 
31
   
 
32
   // Static ---------------------------------------------------------------------------------------
 
33
 
 
34
   private static boolean trace = log.isTraceEnabled();
 
35
 
 
36
   private static Timer timer = new Timer(true);
 
37
 
 
38
   // Attributes -----------------------------------------------------------------------------------
 
39
 
 
40
   private long defaultPingPeriod = -1;
 
41
 
 
42
   private ClientInvoker invoker = null;
 
43
   private String invokerSessionID = null;
 
44
 
 
45
   private Map clientSessionIds = new ConcurrentHashMap();
 
46
   private Map clients = new ConcurrentHashMap();
 
47
   private TimerTask timerTask = null;
 
48
 
 
49
   private long pingPeriod = -1;
 
50
   private int disconnectTimeout = DEFAULT_DISCONNECT_TIMEOUT;
 
51
   private int leasePingerTimeout = -1;
 
52
   
 
53
   // The following variables exist for testing purposes.
 
54
   private boolean pingInvoked;
 
55
   private boolean pingSucceeded;
 
56
   
 
57
   private String leasePingerId;
 
58
   private boolean useClientConnectionIdentity;
 
59
 
 
60
   // Constructors ---------------------------------------------------------------------------------
 
61
 
 
62
   public LeasePinger(ClientInvoker invoker, String invokerSessionID, long defaultLeasePeriod)
 
63
   {
 
64
      this(invoker, invokerSessionID, defaultLeasePeriod, null);
 
65
   }
 
66
   
 
67
   public LeasePinger(ClientInvoker invoker, String invokerSessionID, long defaultLeasePeriod, Map config)
 
68
   {
 
69
      this.invoker = invoker;
 
70
      this.invokerSessionID = invokerSessionID;
 
71
      this.pingPeriod = defaultLeasePeriod;
 
72
      this.defaultPingPeriod = defaultLeasePeriod;
 
73
      
 
74
      if (config != null)
 
75
      {
 
76
         Object o = config.get(LEASE_PINGER_TIMEOUT);
 
77
         if (o != null)
 
78
         {
 
79
            if (o instanceof String)
 
80
            {
 
81
               try
 
82
               {
 
83
                  leasePingerTimeout = Integer.valueOf((String) o).intValue();
 
84
               }
 
85
               catch (NumberFormatException  e)
 
86
               {
 
87
                  log.warn("leasePingerTimeout parameter must represent an int: " + o);
 
88
               }
 
89
            }
 
90
            else
 
91
            {
 
92
               log.warn("leasePingerTimeout parameter must be a String representing an int");
 
93
            }
 
94
         }
 
95
      }
 
96
   }
 
97
 
 
98
   // Public ---------------------------------------------------------------------------------------
 
99
 
 
100
   public void startPing()
 
101
   {
 
102
      if(trace) { log.trace(this + " starting lease timer with ping period of " + pingPeriod); }
 
103
 
 
104
      timerTask = new LeaseTimerTask(this);
 
105
 
 
106
      try
 
107
      {
 
108
         timer.schedule(timerTask, pingPeriod, pingPeriod);
 
109
      }
 
110
      catch (IllegalStateException e)
 
111
      {
 
112
         log.debug("Unable to schedule TimerTask on existing Timer", e);
 
113
         timer = new Timer(true);
 
114
         timer.schedule(timerTask, pingPeriod, pingPeriod);
 
115
      }
 
116
   }
 
117
 
 
118
   public void stopPing()
 
119
   {
 
120
      if(trace) { log.trace(this + " stopping lease timer"); }
 
121
 
 
122
      if (timerTask != null)
 
123
      {
 
124
         timerTask.cancel();
 
125
         timerTask = null;
 
126
         
 
127
         if (useClientConnectionIdentity)
 
128
         {
 
129
            Iterator it = clients.values().iterator();
 
130
            while (it.hasNext())
 
131
            {
 
132
               Client client = (Client) it.next();
 
133
               if (trace) log.trace(this + " calling " + client + ".notifyAndDisconnect()");
 
134
               client.notifyListeners();
 
135
               it.remove();
 
136
            }
 
137
         }
 
138
         
 
139
         try
 
140
         {
 
141
            // sending request map with no ClientHolders will indicate to server
 
142
            // that is full disconnect (for client invoker)
 
143
            HashMap metadata = null;
 
144
            
 
145
            // If disconnectTimeout == 0, skip network i/o.
 
146
            if (trace) log.trace(this + ": disconnectTimeout: " + disconnectTimeout);
 
147
            if (disconnectTimeout != 0)
 
148
            {
 
149
               if (disconnectTimeout > 0)
 
150
               {
 
151
                  metadata = new HashMap(1);
 
152
                  metadata.put(ServerInvoker.TIMEOUT, Integer.toString(disconnectTimeout));
 
153
               }
 
154
               InvocationRequest ir =
 
155
                  new InvocationRequest(invokerSessionID, null, "$DISCONNECT$", metadata, null, null);
 
156
               invoker.invoke(ir);
 
157
            }
 
158
         }
 
159
         catch (Throwable throwable)
 
160
         {
 
161
            RuntimeException e = new RuntimeException("Error tearing down lease with server.");
 
162
            e.initCause(throwable);
 
163
            throw e;
 
164
         }
 
165
         
 
166
         if (trace) 
 
167
         {
 
168
            log.trace(this + " shut down");
 
169
            if (!clientSessionIds.isEmpty())
 
170
            {
 
171
               log.trace(this + " " + clientSessionIds.size() + " remaining clients:");
 
172
               Iterator it = clientSessionIds.keySet().iterator();
 
173
               while (it.hasNext())
 
174
               {
 
175
                  log.trace(this + ": " + it.next());
 
176
               }
 
177
               clientSessionIds.clear();
 
178
            }
 
179
            else
 
180
            {
 
181
               log.trace(this + " No remaining clients");
 
182
            }
 
183
         }
 
184
      }
 
185
   }
 
186
 
 
187
   public void addClient(String sessionID, Map configuration, long leasePeriod)
 
188
   {
 
189
      if (leasePeriod <= 0)
 
190
      {
 
191
         leasePeriod = defaultPingPeriod;
 
192
      }
 
193
 
 
194
      if(trace) { log.trace(this + " adding new client with session ID " + sessionID + " and lease period " + leasePeriod); }
 
195
 
 
196
      if (useClientConnectionIdentity)
 
197
      {
 
198
         Client client = (Client) configuration.remove(Client.CLIENT);
 
199
         if (client != null)
 
200
         {
 
201
            clients.put(sessionID, client);
 
202
         }
 
203
      }
 
204
      
 
205
      ClientHolder newClient = new ClientHolder(sessionID, configuration, leasePeriod);
 
206
      clientSessionIds.put(sessionID, newClient);
 
207
 
 
208
      try
 
209
      {
 
210
         sendClientPing();
 
211
      }
 
212
      catch (Throwable t)
 
213
      {
 
214
         log.debug(this + " failed to ping to server", t);
 
215
         log.warn(this + " failed to ping to server: " + t.getMessage());
 
216
         throw new RuntimeException(t);
 
217
      }
 
218
      // if new client lease period is less than the current ping period, need to refresh to new one
 
219
      if (leasePeriod < pingPeriod)
 
220
      {
 
221
         pingPeriod = leasePeriod;
 
222
 
 
223
         // don't want to call stopPing() as that will send disconnect for client invoker
 
224
         if (timerTask != null)
 
225
         {
 
226
            timerTask.cancel();
 
227
            timerTask = null;
 
228
            startPing();
 
229
         }
 
230
      }
 
231
   }
 
232
 
 
233
   public boolean removeClient(String sessionID)
 
234
   {
 
235
      boolean isLastClientLease = false;
 
236
 
 
237
      if(trace) { log.trace(this + " removing client with session ID " + sessionID); }
 
238
 
 
239
      // Don't remove holder until after client has been removed from server side Lease, to
 
240
      // avoid a race with LeaseTimerTask sending a PING without the Client being removed.
 
241
      ClientHolder holder = (ClientHolder)clientSessionIds.get(sessionID);
 
242
      
 
243
      if (holder != null)
 
244
      {
 
245
         // send disconnect for this client
 
246
         try
 
247
         {
 
248
            Map clientMap = new HashMap();
 
249
            clientMap.put(ClientHolder.CLIENT_HOLDER_KEY, holder);
 
250
            
 
251
            // If disconnectTimeout == 0, skip network i/o.
 
252
            if (disconnectTimeout != 0)
 
253
            {
 
254
               if (disconnectTimeout > 0)
 
255
                  clientMap.put(ServerInvoker.TIMEOUT, Integer.toString(disconnectTimeout));
 
256
               
 
257
               InvocationRequest ir = new InvocationRequest(invokerSessionID, null, "$DISCONNECT$",
 
258
                     clientMap, null, null);
 
259
               invoker.invoke(ir);
 
260
               
 
261
               if(trace) { log.trace(this + " sent out disconnect message to server for lease tied to client with session ID " + sessionID); }
 
262
            }
 
263
         }
 
264
         catch (Throwable throwable)
 
265
         {
 
266
            log.debug(this + " failed sending disconnect for client lease for " +
 
267
                  "client with session ID " + sessionID);
 
268
         }
 
269
         
 
270
         clientSessionIds.remove(sessionID);
 
271
         if (useClientConnectionIdentity)
 
272
         {
 
273
            clients.remove(sessionID);
 
274
         }
 
275
      }
 
276
      else
 
277
      {
 
278
         log.debug(this + " tried to remove lease for client with session ID " + sessionID +
 
279
                   ", but no such lease was found: probably it was registered with an older LeasePinger");
 
280
      }
 
281
      
 
282
      if (clientSessionIds.isEmpty())
 
283
      {
 
284
         isLastClientLease = true;
 
285
         if(trace) { log.trace(this + " has no more client leases"); }
 
286
      }
 
287
      else
 
288
      {
 
289
         // now need to see if any of the other client holders have a lower lease period than
 
290
         // default
 
291
 
 
292
         long tempPingPeriod = defaultPingPeriod;
 
293
 
 
294
         for (Iterator i = clientSessionIds.values().iterator(); i.hasNext(); )
 
295
         {
 
296
            ClientHolder clientHolder = (ClientHolder)i.next();
 
297
            long clientHolderLeasePeriod = clientHolder.getLeasePeriod();
 
298
            if (clientHolderLeasePeriod > 0 && clientHolderLeasePeriod < tempPingPeriod)
 
299
            {
 
300
               tempPingPeriod = clientHolderLeasePeriod;
 
301
            }
 
302
         }
 
303
 
 
304
         // was there a change in lease period?
 
305
         if (tempPingPeriod != pingPeriod)
 
306
         {
 
307
            // need to update to new ping period and reset timer
 
308
            pingPeriod = tempPingPeriod;
 
309
 
 
310
            if (timerTask != null)
 
311
            {
 
312
               timerTask.cancel();
 
313
               timerTask = null;
 
314
            }
 
315
            startPing();
 
316
         }
 
317
 
 
318
      }
 
319
      return isLastClientLease;
 
320
   }
 
321
 
 
322
   public long getLeasePeriod(String sessionID)
 
323
   {
 
324
      if (timerTask == null)
 
325
      {
 
326
         return -1;
 
327
      }
 
328
 
 
329
      // look to see if the client is still amont those serviced by this lease pinger
 
330
      if (clientSessionIds.containsKey(sessionID))
 
331
      {
 
332
         return pingPeriod;
 
333
      }
 
334
      else
 
335
      {
 
336
         return -1;
 
337
      }
 
338
   }
 
339
 
 
340
   public String toString()
 
341
   {
 
342
      return "LeasePinger[" + leasePingerId + ":" + invoker + "(" + invokerSessionID + ")]";
 
343
   }
 
344
 
 
345
   // Package protected ----------------------------------------------------------------------------
 
346
 
 
347
   // Protected ------------------------------------------------------------------------------------
 
348
 
 
349
   
 
350
   protected int getDisconnectTimeout()
 
351
   {
 
352
      return disconnectTimeout;
 
353
   }
 
354
   
 
355
   protected void setDisconnectTimeout(int disconnectTimeout)
 
356
   {
 
357
      this.disconnectTimeout = disconnectTimeout;
 
358
      if (trace) log.trace(this + " setting disconnect timeout to: " + disconnectTimeout);
 
359
   }
 
360
   
 
361
   protected String getLeasePingerId()
 
362
   {
 
363
      return leasePingerId;
 
364
   }
 
365
 
 
366
   protected void setLeasePingerId(String leasePingerId)
 
367
   {
 
368
      this.leasePingerId = leasePingerId;
 
369
   }
 
370
   
 
371
   boolean isUseClientConnectionIdentity()
 
372
   {
 
373
      return useClientConnectionIdentity;
 
374
   }
 
375
 
 
376
   void setUseClientConnectionIdentity(boolean useClientConnectionIdentity)
 
377
   {
 
378
      this.useClientConnectionIdentity = useClientConnectionIdentity;
 
379
   }
 
380
   
 
381
   // Private --------------------------------------------------------------------------------------
 
382
 
 
383
   private void sendClientPing() throws Throwable
 
384
   {
 
385
      if(trace)
 
386
      {
 
387
         StringBuffer sb = new StringBuffer();
 
388
         if(clientSessionIds != null)
 
389
         {
 
390
            for(Iterator i = clientSessionIds.values().iterator(); i.hasNext(); )
 
391
            {
 
392
               ClientHolder h = (ClientHolder)i.next();
 
393
               sb.append("    ").append(h.getSessionId()).append('\n');
 
394
            }
 
395
         }
 
396
 
 
397
         log.trace(this + " sending ping to server. Currently managing lease " +
 
398
               "for following clients:\n" + sb.toString());
 
399
      }
 
400
 
 
401
      Map clientsClone = new ConcurrentHashMap(clientSessionIds);
 
402
      Map requestClients = new ConcurrentHashMap();
 
403
      requestClients.put(ClientHolder.CLIENT_HOLDER_KEY, clientsClone);
 
404
      requestClients.put(LeasePinger.LEASE_PINGER_ID, leasePingerId);
 
405
      requestClients.put(TIME_STAMP, Long.toString(System.currentTimeMillis()));
 
406
 
 
407
      if (leasePingerTimeout >= 0)
 
408
      {
 
409
         requestClients.put(ServerInvoker.TIMEOUT, Integer.toString(leasePingerTimeout));
 
410
      }
 
411
      
 
412
      InvocationRequest ir = new InvocationRequest(invokerSessionID, null, "$PING$", requestClients, null, null);
 
413
      
 
414
      pingSucceeded = false;
 
415
      pingInvoked = true;
 
416
      invoker.invoke(ir);
 
417
 
 
418
      pingSucceeded = true;
 
419
      pingInvoked = false;
 
420
      if(trace) { log.trace(this + " successfully pinged the server"); }
 
421
   }
 
422
 
 
423
   // Inner classes --------------------------------------------------------------------------------
 
424
 
 
425
   static private class LeaseTimerTask extends TimerTask
 
426
   {
 
427
      private LeasePinger pinger;
 
428
 
 
429
      LeaseTimerTask(final LeasePinger pinger)
 
430
      {
 
431
          this.pinger = pinger;
 
432
      }
 
433
 
 
434
      public void run()
 
435
      {
 
436
         final LeasePinger currentPinger;
 
437
         synchronized(this)
 
438
         {
 
439
             currentPinger = pinger;
 
440
         }
 
441
 
 
442
         if (currentPinger != null)
 
443
         {
 
444
            try
 
445
            {
 
446
               currentPinger.sendClientPing();
 
447
            }
 
448
            catch (Throwable t)
 
449
            {
 
450
               log.debug(this + " failed to ping to server", t);
 
451
               log.warn(this + " failed to ping to server: " + t.getMessage());
 
452
            }
 
453
         }
 
454
      }
 
455
 
 
456
      public boolean cancel()
 
457
      {
 
458
          synchronized(this)
 
459
          {
 
460
              pinger = null;
 
461
          }
 
462
          return super.cancel();
 
463
      }
 
464
   }
 
465
}