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

« back to all changes in this revision

Viewing changes to src/org/jboss/remoting/detection/AbstractDetector.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
 
/*
2
 
* JBoss, Home of Professional Open Source
3
 
* Copyright 2005, JBoss Inc., and individual contributors as indicated
4
 
* by the @authors tag. See the copyright.txt in the distribution for a
5
 
* full listing of individual contributors.
6
 
*
7
 
* This is free software; you can redistribute it and/or modify it
8
 
* under the terms of the GNU Lesser General Public License as
9
 
* published by the Free Software Foundation; either version 2.1 of
10
 
* the License, or (at your option) any later version.
11
 
*
12
 
* This software is distributed in the hope that it will be useful,
13
 
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
 
* Lesser General Public License for more details.
16
 
*
17
 
* You should have received a copy of the GNU Lesser General Public
18
 
* License along with this software; if not, write to the Free
19
 
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20
 
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21
 
*/
22
 
package org.jboss.remoting.detection;
23
 
 
24
 
 
25
 
import org.jboss.logging.Logger;
26
 
import org.jboss.remoting.ConnectionValidator;
27
 
import org.jboss.remoting.InvokerLocator;
28
 
import org.jboss.remoting.InvokerRegistry;
29
 
import org.jboss.remoting.ServerInvoker;
30
 
import org.jboss.remoting.ident.Identity;
31
 
import org.jboss.remoting.network.NetworkInstance;
32
 
import org.jboss.remoting.network.NetworkRegistryFinder;
33
 
import org.jboss.remoting.network.NetworkRegistryMBean;
34
 
import org.jboss.remoting.network.NetworkRegistryWrapper;
35
 
import org.w3c.dom.Element;
36
 
import org.w3c.dom.Node;
37
 
import org.w3c.dom.NodeList;
38
 
 
39
 
import javax.management.MBeanServer;
40
 
import javax.management.MBeanServerInvocationHandler;
41
 
import javax.management.ObjectName;
42
 
 
43
 
import java.security.AccessController;
44
 
import java.security.PrivilegedAction;
45
 
import java.util.ArrayList;
46
 
import java.util.Collection;
47
 
import java.util.HashMap;
48
 
import java.util.HashSet;
49
 
import java.util.List;
50
 
import java.util.Map;
51
 
import java.util.Set;
52
 
import java.util.Timer;
53
 
import java.util.TimerTask;
54
 
 
55
 
 
56
 
/**
57
 
 * AbstractDetector
58
 
 *
59
 
 * @author <a href="mailto:jhaynie@vocalocity.net">Jeff Haynie</a>
60
 
 * @author <a href="mailto:tom.elrod@jboss.com">Tom Elrod</a>
61
 
 * @version $Revision: 5116 $
62
 
 */
63
 
public abstract class AbstractDetector implements AbstractDetectorMBean
64
 
{
65
 
   static protected final Logger log = Logger.getLogger(AbstractDetector.class);
66
 
   
67
 
   private long defaultTimeDelay = 5000;
68
 
   private long heartbeatTimeDelay = 1000;
69
 
   protected MBeanServer mbeanserver;
70
 
   protected ObjectName objectName;
71
 
   protected ObjectName registryObjectName;
72
 
   protected NetworkRegistryMBean networkRegistry;
73
 
 
74
 
   private Identity myself;
75
 
   private Timer heartbeatTimer;
76
 
   private Timer failureTimer;
77
 
   private Map servers = new HashMap();
78
 
   private Element xml;
79
 
   private Set domains = new HashSet();
80
 
   private boolean acceptLocal = false;
81
 
 
82
 
   private Map config;
83
 
 
84
 
   public AbstractDetector()
85
 
   {
86
 
      this(null);
87
 
   }
88
 
 
89
 
   public AbstractDetector(Map config)
90
 
   {
91
 
      this.config = new HashMap();
92
 
      if (config != null)
93
 
         this.config.putAll(config);
94
 
   }
95
 
 
96
 
   /**
97
 
    * The amount of time to wait between sending (and sometimes receiving) detection messages.
98
 
    *
99
 
    * @param heartbeatTimeDelay
100
 
    * @throws IllegalArgumentException
101
 
    */
102
 
   public void setHeartbeatTimeDelay(long heartbeatTimeDelay)
103
 
   {
104
 
      if(heartbeatTimeDelay > 0 && heartbeatTimeDelay < defaultTimeDelay)
105
 
      {
106
 
         this.heartbeatTimeDelay = heartbeatTimeDelay;
107
 
      }
108
 
      else
109
 
      {
110
 
         throw new IllegalArgumentException("Can not set heartbeat time delay (" + heartbeatTimeDelay + ") to a negative number or " +
111
 
                                            "to a number greater than the default time delay (" + defaultTimeDelay + ").");
112
 
      }
113
 
   }
114
 
 
115
 
   /**
116
 
    * The amount of time to wait between sending (and sometimes receiving) detection messages.
117
 
    *
118
 
    * @return
119
 
    */
120
 
   public long getHeartbeatTimeDelay()
121
 
   {
122
 
      return heartbeatTimeDelay;
123
 
   }
124
 
 
125
 
   /**
126
 
    * The amount of time which can elapse without receiving a detection event before a server
127
 
    * will be suspected as being dead and peroforming an explicit invocation on it to verify it is alive.
128
 
    *
129
 
    * @param defaultTimeDelay time in milliseconds
130
 
    * @throws IllegalArgumentException
131
 
    */
132
 
   public void setDefaultTimeDelay(long defaultTimeDelay)
133
 
   {
134
 
      if(defaultTimeDelay >= heartbeatTimeDelay)
135
 
      {
136
 
         this.defaultTimeDelay = defaultTimeDelay;
137
 
      }
138
 
      else
139
 
      {
140
 
         throw new IllegalArgumentException("Can not set the default time delay (" + defaultTimeDelay + ") to be less" +
141
 
                                            " than that of the heartbeat time delay (" + heartbeatTimeDelay + ").");
142
 
      }
143
 
   }
144
 
 
145
 
   /**
146
 
    * @return The amount of time which can elapse without receiving a detection event before a server
147
 
    *         will be suspected as being dead and peroforming an explicit invocation on it to verify it is alive.
148
 
    */
149
 
   public long getDefaultTimeDelay()
150
 
   {
151
 
      return defaultTimeDelay;
152
 
   }
153
 
 
154
 
   /**
155
 
    * Will create a detection message based on the server invokers registered within the local InvokerRegistry.
156
 
    * The detection message will contain the identity and array of server invoker metadata.
157
 
    *
158
 
    * @return
159
 
    */
160
 
   public Detection createDetection()
161
 
   {
162
 
      Detection detection = null;
163
 
 
164
 
      ServerInvoker invokers[] = InvokerRegistry.getServerInvokers();
165
 
      if(invokers == null || invokers.length <= 0)
166
 
      {
167
 
         return detection;
168
 
      }
169
 
      List l = new ArrayList(invokers.length);
170
 
      for(int c = 0; c < invokers.length; c++)
171
 
      {
172
 
         if(invokers[c].isStarted())
173
 
         {
174
 
            ServerInvokerMetadata serverInvoker = new ServerInvokerMetadata(invokers[c].getLocator(),
175
 
                                                                            invokers[c].getSupportedSubsystems());
176
 
            l.add(serverInvoker);
177
 
         }
178
 
      }
179
 
      if(l.isEmpty())
180
 
      {
181
 
         return detection;
182
 
      }
183
 
      ServerInvokerMetadata metadata[] = (ServerInvokerMetadata[]) l.toArray(new ServerInvokerMetadata[l.size()]);
184
 
      detection = new Detection(Identity.get(mbeanserver), metadata);
185
 
      return detection;
186
 
   }
187
 
 
188
 
   /**
189
 
    * called by MBeanServer to start the mbean lifecycle
190
 
    *
191
 
    * @throws Exception
192
 
    */
193
 
   public void start() throws Exception
194
 
   {
195
 
      // get our own identity
196
 
      myself = Identity.get(mbeanserver);
197
 
 
198
 
      // add my domain if domains empty and xml not set
199
 
      if(domains.isEmpty() && xml == null)
200
 
      {
201
 
         domains.add(myself.getDomain());
202
 
      }
203
 
 
204
 
      // find our NetworkRegistry
205
 
      registryObjectName = NetworkRegistryFinder.find(mbeanserver);
206
 
      if(registryObjectName == null)
207
 
      {
208
 
         log.warn("Detector: " + getClass().getName() + " could not be loaded because the NetworkRegistry is not registered");
209
 
         log.warn("This means that only the broadcasting of detection messages will be functional and will not be able to discover other servers.");
210
 
      }
211
 
      else
212
 
      {
213
 
         Object o = MBeanServerInvocationHandler.newProxyInstance(mbeanserver,
214
 
                                                                  registryObjectName,
215
 
                                                                  NetworkRegistryMBean.class,
216
 
                                                                  false);                                                       
217
 
         networkRegistry = new NetworkRegistryWrapper((NetworkRegistryMBean) o);
218
 
      }
219
 
 
220
 
      startPinger(getPingerDelay(), getPingerPeriod());
221
 
      startHeartbeat(getHeartbeatDelay(), getHeartbeatPeriod());
222
 
   }
223
 
 
224
 
   /**
225
 
    * return the delay in milliseconds between when the timer is created to when the first pinger thread runs.
226
 
    * defaults to <tt>5000</tt>
227
 
    *
228
 
    * @return
229
 
    */
230
 
   protected long getPingerDelay()
231
 
   {
232
 
      return 5000;
233
 
   }
234
 
 
235
 
   /**
236
 
    * return the period in milliseconds between checking lost servers against the last detection timestamp.
237
 
    * defaults to <tt>1500</tt>
238
 
    *
239
 
    * @return
240
 
    */
241
 
   protected long getPingerPeriod()
242
 
   {
243
 
      return 1500;
244
 
   }
245
 
 
246
 
   /**
247
 
    * start the pinger timer thread
248
 
    *
249
 
    * @param delay
250
 
    * @param period
251
 
    */
252
 
   protected void startPinger(long delay, long period)
253
 
   {
254
 
      failureTimer = new Timer(false);
255
 
      failureTimer.schedule(new FailureDetector(), delay, period);
256
 
   }
257
 
 
258
 
   /**
259
 
    * stop the pinger timer thread
260
 
    */
261
 
   protected void stopPinger()
262
 
   {
263
 
      if(failureTimer != null)
264
 
      {
265
 
         failureTimer.cancel();
266
 
         failureTimer = null;
267
 
      }
268
 
   }
269
 
 
270
 
   /**
271
 
    * called by the MBeanServer to stop the mbean lifecycle
272
 
    *
273
 
    * @throws Exception
274
 
    */
275
 
   public void stop() throws Exception
276
 
   {
277
 
      stopPinger();
278
 
      stopHeartbeat();
279
 
      stopPinger();
280
 
   }
281
 
 
282
 
   public void postDeregister()
283
 
   {
284
 
   }
285
 
 
286
 
   public void postRegister(Boolean aBoolean)
287
 
   {
288
 
   }
289
 
 
290
 
   public void preDeregister() throws Exception
291
 
   {
292
 
   }
293
 
 
294
 
   public ObjectName preRegister(MBeanServer mBeanServer, ObjectName objectName) throws Exception
295
 
   {
296
 
      this.mbeanserver = mBeanServer;
297
 
      this.objectName = objectName;
298
 
      return objectName;
299
 
   }
300
 
 
301
 
   /**
302
 
    * set the configuration for the domains to be recognized by detector
303
 
    *
304
 
    * @param xml
305
 
    * @jmx.managed-attribute description="Configuration is an xml element indicating domains to be recognized by detector"
306
 
    * access="read-write"
307
 
    */
308
 
   public void setConfiguration(Element xml)
309
 
         throws Exception
310
 
   {
311
 
      this.xml = xml;
312
 
 
313
 
      // check configuration xml
314
 
      if(xml != null)
315
 
      {
316
 
         // clearing collection of domains since have new ones to set
317
 
         domains.clear();
318
 
 
319
 
         NodeList domainNodes = xml.getElementsByTagName("domain");
320
 
         if(domainNodes == null || domainNodes.getLength() <= 0)
321
 
         {
322
 
            // no domains specified, so will accept all domains
323
 
            log.debug("No domains specified.  Will accept all domains.");
324
 
         }
325
 
         int len = domainNodes.getLength();
326
 
         for(int c = 0; c < len; c++)
327
 
         {
328
 
            Node node = domainNodes.item(c);
329
 
            String domain = node.getFirstChild().getNodeValue();
330
 
            domains.add(domain);
331
 
            log.debug("Added domain " + domain + " to detector list.");
332
 
         }
333
 
 
334
 
         // now look to see if local server detection should be accepted
335
 
         NodeList localNode = xml.getElementsByTagName("local");
336
 
         if(localNode != null)
337
 
         {
338
 
            acceptLocal = true;
339
 
         }
340
 
 
341
 
 
342
 
      }
343
 
   }
344
 
 
345
 
   /**
346
 
    * The <code>getConfiguration</code> method
347
 
    *
348
 
    * @return an <code>Element</code> value
349
 
    * @jmx.managed-attribute
350
 
    */
351
 
   public Element getConfiguration()
352
 
   {
353
 
      return xml;
354
 
   }
355
 
 
356
 
   //----------------------- protected
357
 
 
358
 
   /**
359
 
    * start heartbeating
360
 
    *
361
 
    * @param delay
362
 
    * @param period
363
 
    */
364
 
   protected void startHeartbeat(long delay, long period)
365
 
   {
366
 
      if(heartbeatTimer == null)
367
 
      {
368
 
         heartbeatTimer = new Timer(false);
369
 
      }
370
 
 
371
 
      try
372
 
      {
373
 
         heartbeatTimer.schedule(new Heartbeat(), delay, period);
374
 
      }
375
 
      catch (IllegalStateException e)
376
 
      {
377
 
         log.debug("Unable to schedule TimerTask on existing Timer", e);
378
 
         heartbeatTimer = new Timer(false);
379
 
         heartbeatTimer.schedule(new Heartbeat(), delay, period);
380
 
      }
381
 
   }
382
 
 
383
 
   /**
384
 
    * stop heartbeating
385
 
    */
386
 
   protected void stopHeartbeat()
387
 
   {
388
 
      if(heartbeatTimer != null)
389
 
      {
390
 
         try
391
 
         {
392
 
            heartbeatTimer.cancel();
393
 
         }
394
 
         catch(Exception eg)
395
 
         {
396
 
         }
397
 
         heartbeatTimer = null;
398
 
      }
399
 
   }
400
 
 
401
 
   /**
402
 
    * return the initial delay in milliseconds before the initial heartbeat is fired.
403
 
    * Defaults to <tt>0</tt>
404
 
    *
405
 
    * @return
406
 
    */
407
 
   protected long getHeartbeatDelay()
408
 
   {
409
 
      return 0;
410
 
   }
411
 
 
412
 
   /**
413
 
    * return the period in milliseconds between subsequent heartbeats. Defaults to
414
 
    * <tt>1000</tt>
415
 
    *
416
 
    * @return
417
 
    */
418
 
   protected long getHeartbeatPeriod()
419
 
   {
420
 
      return heartbeatTimeDelay;
421
 
   }
422
 
 
423
 
   /**
424
 
    * subclasses must implement to provide the specific heartbeat protocol
425
 
    * for this server to send out to other servers on the network
426
 
    */
427
 
   protected abstract void heartbeat();
428
 
 
429
 
   /**
430
 
    * To be used to force detection to occur in synchronouse manner
431
 
    * instead of being passive and waiting for detection messages to
432
 
    * come in from remote detectors.  The servers returned should be
433
 
    * the remote servers that are online at this point in time.  Note, calling this
434
 
    * method may take a few seconds to complete.
435
 
    * @return
436
 
    */
437
 
   public NetworkInstance[] forceDetection()
438
 
   {
439
 
      forceHeartbeat();
440
 
      if(networkRegistry != null)
441
 
      {
442
 
         return (NetworkInstance[]) AccessController.doPrivileged( new PrivilegedAction()
443
 
         {
444
 
            public Object run()
445
 
            {
446
 
               return networkRegistry.getServers();
447
 
            }
448
 
         });
449
 
      }
450
 
      else
451
 
      {
452
 
         return null;
453
 
      }
454
 
   }
455
 
 
456
 
   /**
457
 
    * Used to force detection messages to be sent by remoting servers
458
 
    * and consumed by detector and registered with network registry.
459
 
    */
460
 
   protected abstract void forceHeartbeat();
461
 
 
462
 
 
463
 
   /**
464
 
    * called when a remote detection from a peer is received by a detector
465
 
    *
466
 
    * @param detection
467
 
    */
468
 
   protected void detect(final Detection detection)
469
 
   {
470
 
      if (detection != null)
471
 
      {
472
 
         if (log.isTraceEnabled())
473
 
         {
474
 
            log.trace("Detection message received.");
475
 
            log.trace("Id = " + detection.getIdentity() != null ? detection.getIdentity().getInstanceId() : "null");
476
 
            log.trace("isRemoteDetection() = " + isRemoteDetection(detection));
477
 
         }
478
 
         // we only track detections within our own domain and not ourself
479
 
         if (isRemoteDetection(detection))
480
 
         {
481
 
            try
482
 
            {
483
 
               boolean found = false;
484
 
               Server server = null;
485
 
 
486
 
               synchronized (servers)
487
 
               {
488
 
                  server = (Server) servers.get(detection);
489
 
                  found = server != null;
490
 
                  if (!found)
491
 
                  {
492
 
                     // update either way the timestamp and the detection
493
 
                     servers.put(detection, new Server(detection));
494
 
                  }
495
 
                  else
496
 
                  {
497
 
                     server.lastDetection = System.currentTimeMillis();
498
 
                  }
499
 
               }
500
 
               if (found == false)
501
 
               {
502
 
                  if (networkRegistry != null)
503
 
                  {
504
 
                     log.debug(this + " detected NEW server: " + detection);
505
 
                 
506
 
                     AccessController.doPrivileged( new PrivilegedAction()
507
 
                     {
508
 
                        public Object run()
509
 
                        {
510
 
                           networkRegistry.addServer(detection.getIdentity(), detection.getServerInvokers());
511
 
                           return null;
512
 
                        }
513
 
                     });
514
 
                  }
515
 
               }
516
 
               else
517
 
               {
518
 
                  if (server.changed(detection))
519
 
                  {
520
 
                     // update hash
521
 
                     servers.put(detection, new Server(detection));
522
 
                     if (networkRegistry != null)
523
 
                     {
524
 
                        if (log.isTraceEnabled())
525
 
                        {
526
 
                           log.trace(this + " detected UPDATE for server: " + detection);
527
 
                        }
528
 
                        
529
 
                        AccessController.doPrivileged( new PrivilegedAction()
530
 
                        {
531
 
                           public Object run()
532
 
                           {
533
 
                              networkRegistry.updateServer(detection.getIdentity(), detection.getServerInvokers());
534
 
                              return null;
535
 
                           }
536
 
                        });
537
 
                     }
538
 
                  }
539
 
               }
540
 
            }
541
 
            catch (Exception e)
542
 
            {
543
 
               log.warn("Error during detection of: " + detection);
544
 
               log.debug("Error during detection of: " + detection, e);
545
 
            }
546
 
         }
547
 
         else if (log.isTraceEnabled())
548
 
         {
549
 
            log.trace("detection from myself - ignored");
550
 
         }
551
 
      }
552
 
   }
553
 
 
554
 
   protected boolean isRemoteDetection(Detection detection)
555
 
   {
556
 
      String domain = null;
557
 
      if(detection != null)
558
 
      {
559
 
         Identity identity = detection.getIdentity();
560
 
         if(identity != null)
561
 
         {
562
 
            domain = identity.getDomain();
563
 
         }
564
 
      }
565
 
      // is detection domain in accepted domain collection and not local
566
 
      // if domains empty, then accept all
567
 
      return (domain == null || domains.isEmpty() || domains.contains(domain)) &&
568
 
             (acceptLocal ? true : (myself.isSameJVM(detection.getIdentity()) == false));
569
 
   }
570
 
 
571
 
   protected boolean checkInvokerServer(final Detection detection, ClassLoader cl)
572
 
   {
573
 
      boolean ok = false;
574
 
      ServerInvokerMetadata[] invokerMetadataArray = detection.getServerInvokers();
575
 
      ArrayList validinvokers = new ArrayList();
576
 
      for(int c = 0; c < invokerMetadataArray.length; c++)
577
 
      {
578
 
         InvokerLocator locator = null;
579
 
         try
580
 
         {
581
 
            ServerInvokerMetadata invokerMetadata = invokerMetadataArray[c];
582
 
            locator = invokerMetadata.getInvokerLocator();
583
 
 
584
 
            boolean isValid = ConnectionValidator.checkConnection(locator, config);
585
 
            if(isValid)
586
 
            {
587
 
               // the transport was successful
588
 
               ok = true;
589
 
               validinvokers.add(invokerMetadata);
590
 
               if(log.isTraceEnabled())
591
 
               {
592
 
                  log.trace("Successful connection check for " + locator);
593
 
               }
594
 
            }
595
 
 
596
 
         }
597
 
         catch(Throwable ig)
598
 
         {
599
 
            log.debug("failed calling ping on " + detection + " due to " + ig.getMessage());
600
 
            if(log.isTraceEnabled())
601
 
            {
602
 
               log.trace(ig);
603
 
            }
604
 
         }
605
 
      }
606
 
      if(ok == false)
607
 
      {
608
 
         // the server is down!
609
 
         // would be nice to also remove from the invoker registry as well, but since
610
 
         // don't know all the possible entries for the config map passed when was created,
611
 
         // won't be able to identify it.  This means that clients currently using that invoker
612
 
         // for the server will have to find out the hard way (by getting exception calling on it).
613
 
         try
614
 
         {
615
 
            if(networkRegistry != null)
616
 
            {  
617
 
               AccessController.doPrivileged( new PrivilegedAction()
618
 
               {
619
 
                  public Object run()
620
 
                  {
621
 
                     networkRegistry.removeServer(detection.getIdentity());
622
 
                     return null;
623
 
                  }
624
 
               });
625
 
               
626
 
               log.debug("Removed detection " + detection);
627
 
            }
628
 
         }
629
 
         catch(Exception ex)
630
 
         {
631
 
            log.debug("Error removing server for detection (" + detection + ").  Possible network registry does not exist.");
632
 
         }
633
 
         finally
634
 
         {
635
 
            // remove this server, it isn't available any more
636
 
            servers.remove(detection);
637
 
         }
638
 
      }
639
 
      else // at least one of the server invokers is still valid
640
 
      {
641
 
         if(log.isTraceEnabled())
642
 
         {
643
 
            log.trace("Done checking all locators for suspected dead server.  " +
644
 
                      "There are " + validinvokers.size() + " out of original " +
645
 
                      invokerMetadataArray.length + " still valid.");
646
 
         }
647
 
         // need to cause an update to be fired if any server invokers failed
648
 
         if(validinvokers.size() != invokerMetadataArray.length)
649
 
         {
650
 
            ServerInvokerMetadata[] newLocators = (ServerInvokerMetadata[])validinvokers.toArray(new ServerInvokerMetadata[validinvokers.size()]);
651
 
            Detection newDetection = new Detection(detection.getIdentity(), newLocators);
652
 
            if(log.isTraceEnabled())
653
 
            {
654
 
               log.trace("Since at least one invoker failed while doing connection check, will be re-evaluating detection for:\n" + newDetection);
655
 
            }
656
 
            detect(newDetection);
657
 
         }
658
 
      }
659
 
 
660
 
      return ok;
661
 
   }
662
 
 
663
 
 
664
 
   private final class FailureDetector extends TimerTask
665
 
   {
666
 
      private int threadCounter = 0;
667
 
 
668
 
      public void run()
669
 
      {
670
 
         Thread.currentThread().setName("Remoting Detector - Failure Detector Thread: " + threadCounter++);
671
 
 
672
 
         synchronized (servers)
673
 
         {
674
 
            if (servers.isEmpty())
675
 
            {
676
 
               return;
677
 
            }
678
 
            ClassLoader cl = (ClassLoader) AccessController.doPrivileged( new PrivilegedAction()
679
 
            {
680
 
               public Object run()
681
 
               {
682
 
                  return AbstractDetector.class.getClassLoader();
683
 
               }
684
 
            });
685
 
            // walk through each detection and see if it needs checking up on ...
686
 
            Collection serverCollection = servers.values();
687
 
            Server[] serverArray = (Server[])serverCollection.toArray(new Server[serverCollection.size()]);
688
 
            for(int x = 0; x < serverArray.length; x++)
689
 
            {
690
 
               Server svr = serverArray[x];
691
 
               Detection detect = svr.detection;
692
 
               long lastDetection = svr.lastDetection;
693
 
               long duration = System.currentTimeMillis() - lastDetection;
694
 
               if (duration >= defaultTimeDelay)
695
 
               {
696
 
                  if (log.isTraceEnabled())
697
 
                  {
698
 
                     log.trace("detection for: " + detect + " has not been received in: " + defaultTimeDelay + " ms, contacting..");
699
 
                  }
700
 
                  // OK, we've exceeded the time delay since the last time we've detected
701
 
                  // this dude, he might be down, let's walk through each of his transports and
702
 
                  // see if any of them lead to a valid invocation
703
 
                  if (checkInvokerServer(detect, cl))
704
 
                  {
705
 
                     if (log.isTraceEnabled())
706
 
                     {
707
 
                        log.trace("detection for: " + detect + " recovered on ping");
708
 
                     }
709
 
                     svr.lastDetection = System.currentTimeMillis();
710
 
                  }
711
 
               }
712
 
            }
713
 
         }
714
 
      }
715
 
 
716
 
   }
717
 
 
718
 
   private final class Server
719
 
   {
720
 
      Detection detection;
721
 
      private int hashCode = 0;
722
 
      long lastDetection = System.currentTimeMillis();
723
 
 
724
 
      Server(Detection detection)
725
 
      {
726
 
         this.detection = detection;
727
 
         rehash(detection);
728
 
      }
729
 
 
730
 
      private void rehash(Detection d)
731
 
      {
732
 
         this.hashCode = hash(d);
733
 
      }
734
 
 
735
 
      private int hash(Detection d)
736
 
      {
737
 
         int hc = 0;
738
 
         InvokerLocator locators[] = d.getLocators();
739
 
         if(locators != null)
740
 
         {
741
 
            for(int c = 0; c < locators.length; c++)
742
 
            {
743
 
               hc += locators[c].hashCode();
744
 
            }
745
 
         }
746
 
         return hc;
747
 
      }
748
 
 
749
 
      boolean changed(Detection detection)
750
 
      {
751
 
         return hashCode != hash(detection);
752
 
      }
753
 
 
754
 
      public boolean equals(Object obj)
755
 
      {
756
 
         return obj instanceof Server && hashCode == obj.hashCode();
757
 
      }
758
 
 
759
 
      public int hashCode()
760
 
      {
761
 
         return hashCode;
762
 
      }
763
 
   }
764
 
 
765
 
   private final class Heartbeat extends TimerTask
766
 
   {
767
 
      private int threadCounter = 0;
768
 
 
769
 
      public void run()
770
 
      {
771
 
         Thread.currentThread().setName("Remoting Detector - Heartbeat Thread: " + threadCounter++);
772
 
         heartbeat();
773
 
      }
774
 
   }
775
 
}