1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 package org.apache.river.fiddler; 19 20 import java.io.IOException; 21 import java.io.InputStream; 22 import java.io.InvalidObjectException; 23 import java.io.ObjectInput; 24 import java.io.ObjectInputStream; 25 import java.io.ObjectOutputStream; 26 import java.io.OutputStream; 27 import java.io.Serializable; 28 import java.lang.reflect.Array; 29 import java.net.InetAddress; 30 import java.rmi.MarshalledObject; 31 import java.rmi.NoSuchObjectException; 32 import java.rmi.RemoteException; 33 import java.rmi.activation.ActivationException; 34 import java.rmi.activation.ActivationID; 35 import java.rmi.activation.ActivationSystem; 36 import java.security.AccessControlContext; 37 import java.security.AccessController; 38 import java.security.PrivilegedAction; 39 import java.security.PrivilegedActionException; 40 import java.security.PrivilegedExceptionAction; 41 import java.util.ArrayList; 42 import java.util.Collection; 43 import java.util.Collections; 44 import java.util.HashMap; 45 import java.util.HashSet; 46 import java.util.Iterator; 47 import java.util.List; 48 import java.util.Map; 49 import java.util.Set; 50 import java.util.TreeMap; 51 import java.util.TreeSet; 52 import java.util.concurrent.ExecutorService; 53 import java.util.concurrent.TimeUnit; 54 import java.util.concurrent.locks.Condition; 55 import java.util.logging.Level; 56 import java.util.logging.Logger; 57 import javax.security.auth.Subject; 58 import javax.security.auth.login.LoginContext; 59 import javax.security.auth.login.LoginException; 60 import net.jini.activation.ActivationGroup; 61 import net.jini.config.Configuration; 62 import net.jini.config.ConfigurationException; 63 import net.jini.config.ConfigurationProvider; 64 import net.jini.core.discovery.LookupLocator; 65 import net.jini.core.entry.CloneableEntry; 66 import net.jini.core.entry.Entry; 67 import net.jini.core.event.EventRegistration; 68 import net.jini.core.event.RemoteEventListener; 69 import net.jini.core.lease.Lease; 70 import net.jini.core.lease.UnknownLeaseException; 71 import net.jini.core.lookup.ServiceID; 72 import net.jini.core.lookup.ServiceRegistrar; 73 import net.jini.discovery.DiscoveryChangeListener; 74 import net.jini.discovery.DiscoveryEvent; 75 import net.jini.discovery.DiscoveryGroupManagement; 76 import net.jini.discovery.DiscoveryLocatorManagement; 77 import net.jini.discovery.DiscoveryManagement; 78 import net.jini.discovery.LookupDiscoveryManager; 79 import net.jini.discovery.LookupDiscoveryRegistration; 80 import net.jini.discovery.RemoteDiscoveryEvent; 81 import net.jini.export.CodebaseAccessor; 82 import net.jini.export.Exporter; 83 import net.jini.export.ProxyAccessor; 84 import net.jini.lookup.ServiceAttributesAccessor; 85 import net.jini.lookup.ServiceIDAccessor; 86 import net.jini.lookup.ServiceProxyAccessor; 87 import net.jini.id.Uuid; 88 import net.jini.id.UuidFactory; 89 import net.jini.io.MarshalledInstance; 90 import net.jini.lookup.JoinManager; 91 import net.jini.lookup.entry.Comment; 92 import net.jini.lookup.entry.ServiceInfo; 93 import net.jini.lookup.entry.Status; 94 import net.jini.lookup.entry.StatusType; 95 import net.jini.security.ProxyPreparer; 96 import net.jini.security.Security; 97 import net.jini.security.TrustVerifier; 98 import net.jini.security.proxytrust.ServerProxyTrust; 99 import net.jini.security.proxytrust.TrustEquivalence; 100 import org.apache.river.api.io.AtomicSerial; 101 import org.apache.river.api.io.AtomicSerial.GetArg; 102 import org.apache.river.api.io.AtomicSerial.ReadInput; 103 import org.apache.river.api.io.AtomicSerial.ReadObject; 104 import org.apache.river.api.util.Startable; 105 import org.apache.river.config.Config; 106 import org.apache.river.constants.ThrowableConstants; 107 import org.apache.river.constants.TimeConstants; 108 import org.apache.river.constants.VersionConstants; 109 import org.apache.river.logging.Levels; 110 import org.apache.river.lookup.entry.BasicServiceType; 111 import org.apache.river.lookup.entry.LookupAttributes; 112 import org.apache.river.proxy.ThrowThis; 113 import org.apache.river.reliableLog.LogHandler; 114 import org.apache.river.reliableLog.ReliableLog; 115 import org.apache.river.start.lifecycle.LifeCycle; 116 import org.apache.river.thread.InterruptedStatusThread; 117 import org.apache.river.thread.ReadersWriter; 118 import org.apache.river.thread.ReadersWriter.ConcurrentLockException; 119 import org.apache.river.thread.ReadyState; 120 import org.apache.river.fiddler.proxy.*; 121 import org.apache.river.proxy.CodebaseProvider; 122 123 /** 124 * This class is the server side of an implementation of the lookup 125 * discovery service. Multiple client-side proxy classes are used to 126 * interact and communicate with this backend server. Those proxy 127 * classes are: <code>FiddlerProxy</code> (the proxy for the 128 * <code>LookupDiscoveryService</code> interface which defines how clients 129 * register with the lookup discovery service), <code>FiddlerAdminProxy</code> 130 * (the proxy for the <code>FiddlerAdmin</code> interface which specifies 131 * the methods through which administration duties such as joining, persistent 132 * state logging policy, and shutting down the lookup discovery service can 133 * be performed), and <code>FiddlerRegistration</code> (the proxy for the 134 * <code>LookupDiscoveryRegistration</code> interface which defines the 135 * methods through which clients can perform duties such as group and 136 * locator management, state retrieval, and discarding discovered but 137 * unavailable lookup services so they are eligible for re-discovery). 138 * <p> 139 * It is through the proxies that communicate with this class that clients 140 * interact with the lookup discovery service. When a client makes a method 141 * invocation on one of the proxies, the proxy makes a corresponding call 142 * on the methods specified in the <code>Fiddler</code> interface which 143 * are implemented in this class, ultimately executing on the backend server. 144 * <p> 145 * 146 * This implementation of the lookup discovery service employs a number of 147 * {@link java.util.logging.Logger}s. The details of each such 148 * {@link java.util.logging.Logger} are described 149 * <a href="./package-summary.html#fiddlerLoggers">here</a>. 150 * <p> 151 * The configuration entries supported by this implementation are described 152 * <a href="./package-summary.html#fiddlerConfigEntries">here</a>. 153 * 154 * @author Sun Microsystems, Inc. 155 */ 156 public class FiddlerImpl implements ServerProxyTrust, ProxyAccessor, Fiddler, 157 Startable, CodebaseAccessor, 158 ServiceProxyAccessor, ServiceAttributesAccessor, ServiceIDAccessor { 159 160 /* Name of this component; used in config entry retrieval and the logger.*/ 161 static final String COMPONENT_NAME = "org.apache.river.fiddler"; 162 /* Loggers used by this implementation of the service. */ 163 static final Logger problemLogger = Logger.getLogger(COMPONENT_NAME+ 164 ".problem"); 165 static final Logger startupLogger = Logger.getLogger(COMPONENT_NAME+ 166 ".startup"); 167 static final Logger tasksLogger = Logger.getLogger(COMPONENT_NAME+ 168 ".tasks"); 169 static final Logger eventsLogger = Logger.getLogger(COMPONENT_NAME+ 170 ".events"); 171 static final Logger groupsLogger = Logger.getLogger(COMPONENT_NAME+ 172 ".groups"); 173 static final Logger locatorsLogger = Logger.getLogger(COMPONENT_NAME+ 174 ".locators"); 175 static final Logger discardLogger = Logger.getLogger(COMPONENT_NAME+ 176 ".discard"); 177 static final Logger leaseLogger = Logger.getLogger(COMPONENT_NAME+ 178 ".lease"); 179 static final Logger registrationLogger = Logger.getLogger(COMPONENT_NAME+ 180 ".registration"); 181 static final Logger persistLogger = Logger.getLogger(COMPONENT_NAME+ 182 ".persist"); 183 184 @Override 185 public Entry[] getServiceAttributes() throws IOException { 186 readyState.check(); 187 concurrentObj.readLock(); 188 try { 189 return joinMgr.getAttributes(); 190 } finally { 191 concurrentObj.readUnlock(); 192 } 193 } 194 195 @Override 196 public ServiceID serviceID() throws IOException { 197 readyState.check(); 198 concurrentObj.readLock(); 199 try { 200 return serviceID; 201 } finally { 202 concurrentObj.readUnlock(); 203 } 204 } 205 206 @Override 207 public String getClassAnnotation() throws IOException { 208 return "".equals(codebase) ? 209 CodebaseProvider.getClassAnnotation(Fiddler.class) 210 : codebase; 211 } 212 213 @Override 214 public String getCertFactoryType() throws IOException { 215 return certFactoryType; 216 } 217 218 @Override 219 public String getCertPathEncoding() throws IOException { 220 return certPathEncoding; 221 } 222 223 @Override 224 public byte[] getEncodedCerts() throws IOException { 225 return encodedCerts.clone(); 226 } 227 228 /** Data structure - associated with a <code>ServiceRegistrar</code> - 229 * containing the <code>LookupLocator</code> and the member groups of 230 * the registrar 231 */ 232 static final class LocatorGroupsStruct { 233 final LookupLocator locator; 234 final String[] groups; 235 LocatorGroupsStruct(LookupLocator locator, String[] groups) { 236 this.locator = locator; 237 this.groups = groups; 238 } 239 }//end class LocatorGroupsStruct 240 241 /* ServiceInfo values */ 242 private static final String PRODUCT = "Lookup Discovery Service"; 243 private static final String MANUFACTURER = "Sun Microsystems, Inc."; 244 private static final String VENDOR = MANUFACTURER; 245 private static final String VERSION = VersionConstants.SERVER_VERSION; 246 247 /** When re-setting the bound on lease durations, that bound cannot be 248 * set to a value larger than this value */ 249 static final long MAX_LEASE = 1000L * 60 * 60 * 24 * 365 * 1000; 250 /** Log format version */ 251 private static final int LOG_VERSION = 2; 252 253 /** The outer (smart) proxy to this server */ 254 private FiddlerProxy outerProxy; 255 /** The inner proxy (stub or dynamic proxy) to this server */ 256 private Fiddler innerProxy; 257 /** The admin proxy to this server */ 258 private FiddlerAdminProxy adminProxy; 259 /** The service ID associated with this service when it is registered 260 * with any lookup service. 261 */ 262 private ServiceID serviceID = null; 263 /** The activation id of the current instance of the lookup discovery 264 * service, if it happens to be and activatable instance 265 */ 266 private final ActivationID activationID; 267 /* Holds the prepared proxy to the ActivationSystem */ 268 private final ActivationSystem activationSystem; 269 /** The unique identifier generated (or recovered) when an instance of 270 * this service is constructed. This ID is typically used to determine 271 * equality between the proxies of any two instances of this service. 272 */ 273 private Uuid proxyID = null; 274 /** Map from the set of all currently discovered registrars to their 275 * corresponding [locator,member groups] pairs (locatorGroupsStuct). 276 */ 277 private final HashMap allDiscoveredRegs = new HashMap(11); 278 /** Map from registrationID to registrationInfo. Every registration is in 279 * this map under its registrationID. 280 */ 281 private final HashMap registrationByID = new HashMap(11); 282 /** Map from registrationInfo to registrationInfo (that is, to itself), 283 * where the elements of the map are ordered by lease expiration time. 284 */ 285 private final TreeMap registrationByTime = new TreeMap(); 286 /** Performs all group and locator discovery on behalf of clients */ 287 private final LookupDiscoveryManager discoveryMgr; 288 /** The listener registered for both group discovery events and locator 289 * discovery events. 290 */ 291 private final LookupDiscoveryListener discoveryListener 292 = new LookupDiscoveryListener(); 293 /** For each registration created by the lookup discovery service, an 294 * event identifier that uniquely maps the registration to the 295 * registration's listener and managed sets will be generated and 296 * associated with the registration through the EventRegistration 297 * field of the registrationInfo. This event ID is unique across 298 * all registrations with the current instance of the lookup discovery 299 * service. 300 */ 301 private long curEventID = 0; 302 /** Earliest expiration time over all active registrations */ 303 private long minExpiration = Long.MAX_VALUE; 304 /** The lookup discovery manager this service's join manager will use */ 305 private final DiscoveryManagement joinMgrLDM; 306 /** Manager for discovering and registering with lookup services */ 307 private JoinManager joinMgr; 308 /** Executor for sending remote discovery events */ 309 private final ExecutorService executorService; 310 /** Registration lease expiration thread */ 311 private final LeaseExpireThread leaseExpireThread; 312 /** Snapshot-taking thread */ 313 private final SnapshotThread snapshotThread; 314 315 /** Concurrent object to control read and write access */ 316 private final ReadersWriter concurrentObj = new ReadersWriter(); 317 /** Object for synchronizing with the registration expire thread */ 318 private final Condition leaseExpireThreadSyncObj; 319 /** Object on which the snapshot-taking thread will synchronize */ 320 private final Condition snapshotThreadSyncObj; 321 322 /** Reliable log object to hold persistent state of the service. 323 * This object is also used as a flag: non-null ==> persistent service 324 * null ==> non-persistent service 325 */ 326 private final ReliableLog log; 327 /** Flag indicating whether system is in a state of recovery */ 328 private boolean inRecovery; 329 /** Current number of records in the Log File since the last snapshot */ 330 private int logFileSize = 0; 331 /** The name of the directory to which the persistent modes of this service 332 * will log the service's state (using ReliableLog). 333 */ 334 private final String persistDir; 335 /** least upper bound applied to all granted lease durations */ 336 private long leaseBound = 1000 * 60 * 30; 337 /** Weight factor applied to snapshotSize when deciding to take snapshot */ 338 private float snapshotWt = 10; 339 /** Log File must contain this many records before snapshot allowed */ 340 private int snapshotThresh = 200; 341 /** Groups whose members are lookup services this service should join. 342 * Unless configured otherwise, this service will initially join the 343 * un-named public group. The desired join groups for this service can 344 * be set administratively after start up. 345 */ 346 private String[] thisServicesGroups = new String[] {""}; 347 /** Locators of specific lookup services this service should join. 348 * This service will initially join no lookups found through locator 349 * discovery. The locators of the specific lookup services that are 350 * desired for this service to join should be set administratively 351 * after start up. 352 */ 353 private LookupLocator[] thisServicesLocators = {}; 354 /** The attributes to use when joining lookup service(s) */ 355 private Entry[] thisServicesAttrs 356 = new Entry[] 357 { new ServiceInfo(PRODUCT,MANUFACTURER,VENDOR,VERSION,"",""), 358 new BasicServiceType("Lookup Discovery Service") 359 }; 360 /* Object used to obtain the configuration items for this service. */ 361 private Configuration config; 362 /* The JAAS login context to use when performing a JAAS login. */ 363 private final LoginContext loginContext; 364 /* The exporter used to export this service. */ 365 private final Exporter serverExporter; 366 /* Maximum value of upper bound on lease durations.*/ 367 private final long leaseMax; 368 /* Flag indicating this service is being started for the very 1st time */ 369 private boolean initialStartup = true; 370 /** Object that, if non-<code>null</code>, will cause the object's 371 * <code>unregister</code> method to be invoked during service shutdown 372 * to notify the service starter framework that the reference to this 373 * service's implementation can be 'released' for garbage collection; 374 * the framework is notified that it does not have to hold on to the 375 * service reference any longer. Note hat this object is used only 376 * in the non-activatable case. 377 */ 378 private final LifeCycle lifeCycle; 379 380 /* ProxyPreparer fields were originally static and set every time a 381 * constructor was called, this was done to enable the static class 382 * RegistrationInfo to prepare recovered proxy's after deserialization. 383 * 384 * These fields are now final instance fields. This would for instance 385 * enable multiple FiddlerImpl to co exist in one jvm if necessary using 386 * different configurations. 387 */ 388 /* Preparer for proxies to remote listeners newly registered with this 389 * service. 390 */ 391 private final ProxyPreparer listenerPreparer; 392 /* Preparer for proxies to remote listeners, previously prepared, and 393 * recovered from this service's persisted state. 394 */ 395 private final ProxyPreparer recoveredListenerPreparer; 396 /* Preparer for initial and new lookup locators this service should 397 * discover and join. 398 */ 399 private final ProxyPreparer locatorToJoinPreparer; 400 /* Preparer for lookup locators this service should discover and join 401 * that were previously prepared and which were recovered from this 402 * service's persisted state. 403 */ 404 private final ProxyPreparer recoveredLocatorToJoinPreparer; 405 /* Preparer for initial and new lookup locators this service should 406 * discover on behalf of the clients that register with it. 407 */ 408 private final ProxyPreparer locatorToDiscoverPreparer; 409 /* Preparer for lookup locators this service should discover on behalf 410 * of its registered clients that were previously prepared and which 411 * were recovered from this service's persisted state. 412 */ 413 private final ProxyPreparer recoveredLocatorToDiscoverPreparer; 414 /** Object used to prevent access to this service during the service's 415 * initialization or shutdown processing. 416 */ 417 private final ReadyState readyState = new ReadyState(); 418 419 private boolean persistent; 420 private LocalLogHandler logHandler; 421 private final AccessControlContext context; 422 423 private boolean started; 424 425 private String codebase; 426 private String certFactoryType; 427 private String certPathEncoding; 428 private byte[] encodedCerts; 429 430 /* ************************* BEGIN Constructors ************************ */ 431 /** 432 * Constructs a new instance of FiddlerImpl. This version of the 433 * constructor is used to create an activatable instance of the lookup 434 * discovery service that logs its state information to persistent storage. 435 * <p> 436 * A constructor having this signature is required for the class to be 437 * activatable. This constructor is automatically called by the 438 * activation group when the lookup discovery service is activated. 439 * 440 * @param activationID the activation ID generated by the activation 441 * system and assigned to the instance of the server 442 * being activated 443 * @param data state data (represented as a 444 * <code>MarshalledObject</code>) which is needed to 445 * re-activate this server 446 * 447 * @throws IOException this exception can occur when there is 448 * a problem recovering data from disk, 449 * exporting the server that's being 450 * activated, or when unmarshalling the 451 * given <code>data</code> parameter. 452 * @throws ConfigurationException this exception can occur when a 453 * problem occurs while retrieving an item 454 * from the <code>Configuration</code> 455 * generated from the contents of the 456 * given <code>data</code> parameter 457 * @throws ActivationException this exception can occur when a problem 458 * occurs while activating the service 459 * @throws LoginException this exception occurs when authentication 460 * fails while performing a JAAS login for 461 * this service 462 * @throws ClassNotFoundException this exception can occur while 463 * unmarshalling the given <code>data</code> 464 * parameter; when a class needed in the 465 * unmarshalling process cannot be found. 466 * @throws ClassCastException this exception can occur while 467 * unmarshalling the given <code>data</code> 468 * parameter; when the contents of that 469 * parameter is not a <code>String</code> 470 * array. 471 */ 472 FiddlerImpl(ActivationID activationID, 473 MarshalledObject data) throws IOException, 474 ActivationException, 475 ConfigurationException, 476 LoginException, 477 ClassNotFoundException 478 { 479 this(init( (String[]) new MarshalledInstance(data).get(false), true /* persistent */, activationID ), null); 480 }//end activatable constructor 481 482 /** 483 * Constructs a new instance of FiddlerImpl. This version of the 484 * constructor is used to create a NON-activatable instance of the 485 * lookup discovery service. 486 * 487 * @param configArgs <code>String</code> array whose elements are 488 * the arguments to use when creating this version of 489 * the server 490 * @param lifeCycle instance of <code>LifeCycle</code> that, if 491 * non-<code>null</code>, will cause this object's 492 * <code>unregister</code> method to be invoked during 493 * shutdown to notify the service starter framework that 494 * the reference to this service's implementation can be 495 * 'released' for garbage collection. A value of 496 * <code>null</code> for this argument is allowed. 497 * @param persistent if <code>true</code>, then the service should persist 498 * its state. 499 * 500 * @throws IOException this exception can occur when there is 501 * a problem recovering data from disk, or 502 * while exporting the server that's being 503 * created. 504 * @throws ConfigurationException this exception can occur when an 505 * problem occurs while retrieving an item 506 * from the <code>Configuration</code> 507 * generated from the contents of the 508 * given <code>configArgs</code> parameter 509 * @throws LoginException this exception occurs when authentication 510 * fails while performing a JAAS login for 511 * this service 512 */ 513 FiddlerImpl(String[] configArgs, LifeCycle lifeCycle, boolean persistent) 514 throws IOException, 515 ConfigurationException, 516 LoginException 517 { 518 this(init(configArgs, persistent), lifeCycle); 519 }//end non-activatable constructor 520 521 FiddlerImpl(FiddlerInit i, LifeCycle lifeCycle){ 522 this.snapshotThreadSyncObj = concurrentObj.newCondition(); 523 this.leaseExpireThreadSyncObj = concurrentObj.newCondition(); 524 this.lifeCycle = lifeCycle; 525 this.codebase = i.codebase; 526 this.certFactoryType = i.certFactoryType; 527 this.certPathEncoding = i.certPathEncoding; 528 this.encodedCerts = i.encodedCerts.clone(); 529 discoveryMgr = i.discoveryMgr; 530 listenerPreparer = i.listenerPreparer; 531 locatorToJoinPreparer = i.locatorToJoinPreparer; 532 locatorToDiscoverPreparer = i.locatorToDiscoverPreparer; 533 recoveredListenerPreparer = i.recoveredListenerPreparer; 534 recoveredLocatorToJoinPreparer = i.recoveredLocatorToJoinPreparer; 535 recoveredLocatorToDiscoverPreparer = i.recoveredLocatorToDiscoverPreparer; 536 persistDir = i.persistDir; 537 log = i.log; 538 joinMgrLDM = i.joinMgrLDM; 539 leaseMax = i.leaseMax; 540 executorService = i.executorService; 541 activationSystem = i.activationSystem; 542 serverExporter = i.serverExporter; 543 logHandler = i.logHandler; 544 activationID = i.activationID; 545 // These three fields are used by the Starter.start() implementation. 546 persistent = i.persistent; 547 config = i.config; 548 context = i.context; 549 loginContext = i.loginContext; 550 leaseExpireThread = AccessController.doPrivileged( 551 new PrivilegedAction<LeaseExpireThread>(){ 552 @Override 553 public LeaseExpireThread run() { 554 return new LeaseExpireThread(FiddlerImpl.this); 555 } 556 557 }, context); 558 if (log != null){ 559 snapshotThread = AccessController.doPrivileged( 560 new PrivilegedAction<SnapshotThread>(){ 561 @Override 562 public SnapshotThread run() { 563 return new SnapshotThread(FiddlerImpl.this); 564 } 565 566 }, context); 567 } else { 568 snapshotThread = null; 569 } 570 } 571 /* ************************** END Constructors ************************* */ 572 573 /* ******************* BEGIN Inner Class Definitions ******************* */ 574 /** Class which is used to communicate the status of this service to 575 * interested entities. In particular, when certain errors occur during 576 * operation, an instance of this class will be registered as an 577 * attribute in all of the lookup services with which this service 578 * is registered. By registering for notification (from the lookup 579 * services) of the existence of this attribute, interested entities 580 * such as administrative clients and clients wishing to use this 581 * service will be informed when this service can not proceed with its 582 * processing, and can take appropriate action. 583 */ 584 private static class FiddlerStatus extends Status { 585 private static final long serialVersionUID = -8511826097053446749L; 586 public FiddlerStatus(StatusType severity) { 587 super(severity); 588 } 589 }//end class FiddlerStatus 590 591 /** Class whose discovered() method is invoked by threads in the 592 * LookupDiscovery class whenever a new lookup service is discovered 593 * on behalf of a client registration 594 */ 595 private class LookupDiscoveryListener implements DiscoveryChangeListener { 596 public LookupDiscoveryListener() { 597 super(); 598 } 599 public void discovered(DiscoveryEvent event) { 600 executorService.execute(new DiscoveredEventTask(event)); 601 } 602 public void discarded(DiscoveryEvent event) { 603 executorService.execute(new DiscardedEventTask(event)); 604 } 605 public void changed(DiscoveryEvent event) { 606 executorService.execute(new ChangedEventTask(event)); 607 } 608 }//end class LookupDiscoveryListener 609 610 /** This class acts as a record of one registration with the lookup 611 * discovery service; containing all of the information about that 612 * registration. 613 */ 614 @AtomicSerial 615 private final static class RegistrationInfo 616 implements Comparable, Serializable 617 { 618 private static final long serialVersionUID = 2L; 619 620 /** The unique identifier assigned to the registration to which the 621 * data in the current implementation of this class corresponds. 622 * This identifier is unique across all other active registrations 623 * generated with the current instance of the lookup discovery 624 * service. 625 * @serial 626 */ 627 public final Uuid registrationID; 628 /** Map from the set of instances of the <code>ServiceRegistrar</code> 629 * interface, to the set of marshalled instances of the 630 * <code>ServiceRegistrar</code> interface, where each key and 631 * each value (which is the marshalled form of its corresponding 632 * key) is a proxy to one of the lookup service(s) that have been 633 * discovered for the current registration. The contents of 634 * this set represents the 'remote state' of the registration's 635 * currently discovered lookup service(s). 636 * @serial 637 */ 638 public final Map<ServiceRegistrar, MarshalledObject> discoveredRegsMap; 639 /** The managed set containing the names of the groups whose 640 * members are the lookup services the lookup discovery service 641 * should attempt to discover for the current registration. 642 * (HashSet is used to prevent duplicates.) 643 * @serial 644 */ 645 public Set<String> groups; 646 /** The managed set containing the locators of the specific lookup 647 * services the lookup discovery service should attempt to discover 648 * for the current registration. (HashSet is used to prevent 649 * duplicates.) 650 * @serial 651 */ 652 public Set<LookupLocator> locators; 653 /** The ID of the lease placed on the current registration. 654 * @serial 655 */ 656 public final Uuid leaseID; 657 /** The absolute expiration time of the current lease. 658 * @serial 659 */ 660 public long leaseExpiration; 661 /** The identifier that maps the current registration to the remote 662 * event listener and the managed set of groups and locators. 663 */ 664 public long eventID; 665 /** The current sequence number of the set of remote discovery events 666 * sent to the current registration's listener. When a registration 667 * is granted, this class is instantiated to contain the information 668 * related to that particular registration. The event sequence 669 * number is initialized to 0 upon instantiation because the 670 * remote discovery events are sent to the listeners of each 671 * separate registration. Thus, each registration has its own 672 * sequence of events. 673 * @serial 674 */ 675 public long seqNum; 676 /** The handback object returned with every remote discovery event 677 * sent to the current registration's listener. 678 * @serial 679 */ 680 public final MarshalledObject handback; 681 /** When the lookup discovery service discards a registrar as a 682 * result of some internal condition (such as multicast announcements 683 * ceasing) and not as a result of a request from a registration, 684 * every registration configured for group discovery of that discarded 685 * registrar will be sent a remote discarded event. On the other 686 * hand, for the case where a registrar is discarded as a result 687 * of a request from a registration, only those registrations that 688 * actually request that the registrar be discarded will be sent 689 * a remote discarded event. This flag is used to determine whether 690 * to send a remote discarded event to one or multiple listeners. 691 */ 692 public boolean discardFlag; 693 /** The remote event listener registered by the client. This field 694 * is transient because it is marshalled separately from the rest 695 * of this class when being serialized. (See the description for 696 * <code>writeObject</code> below.) 697 */ 698 public transient RemoteEventListener listener; 699 700 private static RemoteEventListener check(GetArg arg) throws IOException { 701 Object registrationID = arg.get("registrationID", null); 702 if (!(registrationID instanceof Uuid)) 703 throw new InvalidObjectException( 704 "registrationID must be instanceof Uuid and non null"); 705 Map<ServiceRegistrar, MarshalledObject> discoveredRegsMap 706 = (Map<ServiceRegistrar, MarshalledObject>) 707 arg.get("discoveredRegsMap", null); 708 Map<ServiceRegistrar, MarshalledObject> checkedRegsMap = 709 Collections.checkedMap( 710 new HashMap(discoveredRegsMap.size()), 711 ServiceRegistrar.class, MarshalledObject.class); 712 checkedRegsMap.putAll(discoveredRegsMap); 713 Set<String> groups = (Set<String>) arg.get("groups", null); 714 Set<String> checkedGroups = 715 Collections.checkedSet(new TreeSet<String>(), String.class); 716 checkedGroups.addAll(groups); 717 Set<LookupLocator> locators = (Set<LookupLocator>) arg.get("locators", null); 718 Set<LookupLocator> checkedLocators = 719 Collections.checkedSet( 720 new HashSet(locators.size()), LookupLocator.class); 721 checkedLocators.addAll(locators); 722 Object leaseID = arg.get("leaseID", null); 723 if (!(leaseID instanceof Uuid)) 724 throw new InvalidObjectException( 725 "leaseID must be instanceof Uuid and non null"); 726 arg.get("leaseExpiration", 0L); // Checks existance 727 arg.get("eventID", 0L); // Checks existance 728 arg.get("seqNum", 0L); // Checks existance 729 Object handback = arg.get("handback", null); 730 if (handback != null && !(handback instanceof MarshalledObject)) 731 throw new InvalidObjectException( 732 "handback, if non null, must be an instance of MarshalledObject"); 733 arg.get("discardFlag", false); // Checks existance 734 return ((RO)arg.getReader()).listener; 735 } 736 737 RegistrationInfo(GetArg arg) throws IOException { 738 this(arg, check(arg)); 739 } 740 741 private RegistrationInfo(GetArg arg, RemoteEventListener listener) throws IOException { 742 this.listener = listener; 743 registrationID = (Uuid) arg.get("registrationID", null); 744 discoveredRegsMap = new HashMap<ServiceRegistrar, MarshalledObject>( 745 (Map<ServiceRegistrar, MarshalledObject>) 746 arg.get("discoveredRegsMap", null)); 747 groups = new HashSet<String>((Set<String>) arg.get("groups", null)); 748 locators = new HashSet<LookupLocator>( 749 (Set<LookupLocator>) arg.get("locators", null)); 750 leaseID = (Uuid) arg.get("leaseID", null); 751 leaseExpiration = arg.get("leaseExpiration", 0L); 752 eventID = arg.get("eventID", 0L); 753 seqNum = arg.get("seqNum", 0L); 754 handback = (MarshalledObject) arg.get("handback", null); 755 discardFlag = arg.get("discardFlag", false); 756 } 757 758 /** Constructs an instance of this class and stores the information 759 * related to the current registration: IDs, managed sets, lease 760 * information, and event registration information. 761 */ 762 public RegistrationInfo(Uuid registrationID, 763 String[] groups, 764 LookupLocator[] locators, 765 Uuid leaseID, 766 long leaseExpiration, 767 long eventID, 768 MarshalledObject handback, 769 RemoteEventListener listener) 770 { 771 this.registrationID = registrationID; 772 /* Initialize the groups field, removing nulls and duplicates */ 773 if(groups != null) { 774 this.groups = new HashSet<String>(groups.length); 775 for(int i=0;i<groups.length;i++) { 776 if(groups[i] == null) continue; 777 this.groups.add(groups[i]); 778 } 779 } 780 /* Initialize the locators field, removing nulls and duplicates */ 781 this.locators = new HashSet(locators.length); 782 if( (locators != null) && (locators.length > 0) ) { 783 for(int i=0;i<locators.length;i++) { 784 if(locators[i] == null) continue; 785 this.locators.add(locators[i]); 786 } 787 } 788 this.discoveredRegsMap = new HashMap<ServiceRegistrar, MarshalledObject>(11); 789 this.leaseID = leaseID; 790 this.leaseExpiration = leaseExpiration; 791 792 this.eventID = eventID; 793 this.seqNum = 0; // initialize to 0 794 this.handback = handback; 795 this.discardFlag = false;//set true only on first discard request 796 this.listener = listener; 797 }//end constructor 798 799 /** Attempts to marshal each element of the input set of instances of 800 * the <code>ServiceRegistrar</code> interface and then map the 801 * registrar to its marshalled form, and store the mapping in this 802 * registration's <code>discoveredRegsMap</code> field. 803 * <p> 804 * This method is typically invoked to handle discovered (as opposed 805 * to discarded) registrars. Note that if a particular registrar 806 * cannot be serialized (marshalled), it is not included in the 807 * mapping; nor is it included in the return set. 808 * 809 * @param regMapIn mapping in which the key values are the registrars 810 * to serialize and store, and the map values are data 811 * structures of type <code>LocatorGroupsStruct</code> 812 * that contain the locator and member groups of the 813 * corresponding registrar key 814 * 815 * @return a <code>HashMap</code> whose keys are the registrars 816 * whose marshalled form and un-marshalled form were inserted 817 * as key/value pairs into the <code>discoveredRegsMap</code> 818 * field of this regInfo; and whose values are the member 819 * groups of each corresponding registrar key. 820 */ 821 public Map addToDiscoveredRegs(Map regMapIn) { 822 HashMap regMapOut = new HashMap(regMapIn.size()); 823 Iterator itr = (regMapIn.entrySet()).iterator(); 824 nextReg: 825 for(int i=0;itr.hasNext();i++) { 826 Map.Entry pair = (Map.Entry)itr.next(); 827 ServiceRegistrar reg = (ServiceRegistrar)pair.getKey(); 828 /* If reg is already in map, go to next registrar */ 829 if( discoveredRegsMap.containsKey(reg) ) continue nextReg; 830 /* It doesn't contain it, try to marshal it */ 831 MarshalledObject mReg = null; 832 try { 833 mReg = new MarshalledInstance(reg).convertToMarshalledObject(); 834 } catch(IOException e) { continue nextReg; } //failed, next reg 835 /* Succeeded, map registrar to its marshalled form */ 836 discoveredRegsMap.put(reg,mReg); 837 /* Map the registrar to its member groups for the return map */ 838 regMapOut.put(reg, 839 ((LocatorGroupsStruct)pair.getValue()).groups); 840 }//end loop 841 return regMapOut; 842 }//end addToDiscoveredRegs 843 844 /** Performs a primary sort by leaseExpiration, and a secondary sort 845 * by registrationID. The secondary sort is immaterial, except to 846 * ensure a total order (required by <code>TreeMap</code>). 847 */ 848 public int compareTo(Object obj) { 849 RegistrationInfo regInfo = (RegistrationInfo)obj; 850 if (this == regInfo) return 0; 851 if ( (leaseExpiration < regInfo.leaseExpiration) 852 || ( (leaseExpiration == regInfo.leaseExpiration) 853 && (eventID < regInfo.eventID) ) ) 854 { 855 return -1; 856 }//endif 857 return 1; 858 }//end compareTo 859 860 /** When a registration is granted to a client, the client registers 861 * a remote listener with the lookup discovery service so that the 862 * lookup discovery service may send remote discovery events to the 863 * client. The client typically annotates the listener with an RMI 864 * codebase from which the backend server can download the remote 865 * listener's proxy (stub). When the current registration is logged 866 * to persistent storage (for example, a snapshot is taken), the 867 * listener is written to the output snapshot or log file through 868 * an <code>ObjectOutputStream</code> which only serializes the 869 * listener; it does not marshal the listener. Thus, when the 870 * listener field of this class is logged, unless special action 871 * is taken, the codebase from which to retrieve the listener will 872 * not be included in the output. 873 * 874 * In order to include the codebase with the listener when saving 875 * state, the following custom <code>writeObject</code> method 876 * is provided which first serializes the current instance of 877 * this class (excluding the transient <code>listener</code> field), 878 * and then explicitly marshals the listener to preserve the 879 * codebase upon writing to the file. In this way, the listener -- 880 * along with its codebase -- is persisted through a mechanism that 881 * is separate from the normal mechanism applied to the remaining 882 * fields of this class. 883 */ 884 private void writeObject(ObjectOutputStream stream) throws IOException{ 885 stream.defaultWriteObject(); 886 stream.writeObject(new MarshalledInstance(listener).convertToMarshalledObject()); 887 }//end writeObject 888 889 /** When this class is deserialized, this method is invoked. This 890 * method first deserializes the non-transient elements of this 891 * class, and then unmarshals the remote event listener. (See the 892 * description for <code>writeObject</code> above.) 893 */ 894 private void readObject(ObjectInputStream stream) 895 throws IOException, ClassNotFoundException 896 { 897 stream.defaultReadObject(); 898 MarshalledObject mo = (MarshalledObject)stream.readObject(); 899 try { 900 listener = (RemoteEventListener) new MarshalledInstance(mo).get(false); 901 } catch (Throwable e) { 902 problemLogger.log(Level.INFO, "problem recovering listener " 903 +"for recovered registration", e); 904 if((e instanceof Error) && (ThrowableConstants.retryable(e) 905 == ThrowableConstants.BAD_OBJECT)) 906 { 907 throw (Error)e; 908 }//endif 909 } 910 }//end readObject 911 912 @ReadInput 913 private static ReadObject getRO(){ 914 return new RO(); 915 } 916 917 private static class RO implements ReadObject { 918 919 RemoteEventListener listener; 920 921 @Override 922 public void read(ObjectInput stream) throws IOException, ClassNotFoundException { 923 MarshalledObject mo = (MarshalledObject)stream.readObject(); 924 try { 925 listener = (RemoteEventListener) new MarshalledInstance(mo).get(false); 926 } catch (Throwable e) { 927 problemLogger.log(Level.INFO, "problem recovering listener " 928 +"for recovered registration", e); 929 if((e instanceof Error) && (ThrowableConstants.retryable(e) 930 == ThrowableConstants.BAD_OBJECT)) 931 { 932 throw (Error)e; 933 }//endif 934 } 935 } 936 937 } 938 939 /** 940 * Must be called immediately after de-serialization to prepare 941 * proxies. 942 * 943 * @param recoveredListenerPreparer 944 * @param recoveredLocatorToDiscoverPreparer 945 */ 946 public void prepare(ProxyPreparer recoveredListenerPreparer, 947 ProxyPreparer recoveredLocatorToDiscoverPreparer ) 948 { 949 try { 950 /* Re-prepare the recovered listener */ 951 listener = (RemoteEventListener) 952 recoveredListenerPreparer.prepareProxy(listener); 953 } catch (Throwable e) { 954 problemLogger.log(Level.INFO, "problem recovering listener " 955 +"for recovered registration", e); 956 if((e instanceof Error) && (ThrowableConstants.retryable(e) 957 == ThrowableConstants.BAD_OBJECT)) 958 { 959 throw (Error)e; 960 }//endif 961 } 962 963 /* Prepare the locators recovered from the stream */ 964 int nUnprepared = (locators).size(); 965 locators = (HashSet)prepareOldLocators 966 ( recoveredLocatorToDiscoverPreparer, 967 locators ); 968 if( nUnprepared != (locators).size() ) { 969 /* Failure occurred when preparing one of the locs. Because 970 * this breaks the contract with the client, this registration 971 * will not be recovered so that the client will eventually 972 * be notified. To facilitate this, the listener is set to 973 * null so that the registration will not be added to the 974 * managed set, and so that when the client eventually attempts 975 * to renew the lease on that registration, an exception will 976 * occur; causing the client to be "notified" that there was 977 * a problem with that registration. The client can then 978 * retry the registration; and if problems still exist, the 979 * exception the client receives may give the client more 980 * useful information from which the client can determine 981 * how to proceed. 982 */ 983 listener = null; 984 if( problemLogger.isLoggable(Level.WARNING) ) { 985 problemLogger.log(Level.WARNING, "failure preparing " 986 +"locator while recovering registration" 987 +"... discarding recovered" 988 +"registration"); 989 }//endif 990 } 991 } 992 993 }//end class RegistrationInfo 994 995 /** This class represents a <code>Task</code> object that is placed 996 * in the <code>TaskManager</code> queue for processing in the thread 997 * pool. Instances of this class are placed on the task queue when 998 * registrations are granted. 999 * <p> 1000 * The <code>run</code> method of this class will determine if any of 1001 * the new registration's desired lookup service(s) have already been 1002 * discovered, and will send the appropriate remote discovery event to 1003 * the registration's listener. 1004 */ 1005 private final class NewRegistrationTask implements Runnable { 1006 /** The data structure record corresponding to the new registration */ 1007 public final RegistrationInfo regInfo; 1008 /** Constructs an instance of this class and stores the registration 1009 * information. 1010 */ 1011 public NewRegistrationTask(RegistrationInfo regInfo) { 1012 this.regInfo = regInfo; 1013 }//end constructor 1014 /** This method processes the information associated with the new 1015 * registration and determines, based on the current state of the 1016 * set of 'already-discovered' lookup service(s), whether to send 1017 * a <code>RemoteDiscoveryEvent</code> to the new registration's 1018 * listener. 1019 */ 1020 public void run() { 1021 concurrentObj.writeLock(); 1022 try { 1023 logInfoTasks("NewRegistrationTask.run(): " 1024 +"new Registration added"); 1025 maybeSendDiscoveredEvent(regInfo,allDiscoveredRegs); 1026 } finally { 1027 concurrentObj.writeUnlock(); 1028 } 1029 }//end run 1030 1031 }//end class NewRegistrationTask 1032 1033 /** This class represents a <code>Task</code> object that is placed 1034 * in the <code>TaskManager</code> queue for processing in the thread 1035 * pool. An instance of this class is placed on the task queue when a 1036 * <code>DiscoveryEvent</code> instance indicating a discovered event 1037 * is received from the local discovery process. 1038 * <p> 1039 * The <code>run</code> method of this class will process discovery 1040 * event information and determine to which active registrations the 1041 * appropriate <code>RemoteDiscoveryEvent</code> should be sent; and 1042 * then sends that event. 1043 */ 1044 private final class DiscoveredEventTask implements Runnable { 1045 /** The local event sent by the discovery manager. */ 1046 public final DiscoveryEvent event; 1047 /** Constructs an instance of this class and stores the event*/ 1048 public DiscoveredEventTask(DiscoveryEvent event) { 1049 this.event = event; 1050 }//end constructor 1051 /** This method processes the local discovery event information and 1052 * determines, based on the current state of each active 1053 * registration, to which such registration the appropriate 1054 * <code>RemoteDiscoveryEvent</code> should be sent. After making 1055 * the determination, the remote event appropriate for each 1056 * registration is constructed and sent. 1057 */ 1058 public void run() { 1059 /* Get locators before sync block (no remote calls in sync block)*/ 1060 Map groupsMap = event.getGroups(); 1061 ServiceRegistrar[] regs = event.getRegistrars(); 1062 HashMap regMap = new HashMap(regs.length); 1063 for(int i=0;i<regs.length;i++) { 1064 try { 1065 LookupLocator regLoc = regs[i].getLocator(); 1066 String[] regGroups = (String[])groupsMap.get(regs[i]); 1067 LocatorGroupsStruct regLocGroups 1068 = new LocatorGroupsStruct(regLoc,regGroups); 1069 regMap.put(regs[i],regLocGroups); 1070 } catch(Exception e) { 1071 problemLogger.log(Levels.FAILED, 1072 "problem retrieving locator " 1073 +"from discovered lookup service ... " 1074 +"discarded the lookup service", e); 1075 discoveryMgr.discard(regs[i]); 1076 } 1077 }//end loop 1078 /* Synchronization block -- no remote calls here */ 1079 concurrentObj.writeLock(); 1080 logInfoTasks("DiscoveredEventTask.run(): processing DISCOVERED " 1081 +"event from discovery manager"); 1082 try { 1083 /* Update the global allDiscoveredRegs map with new pairs */ 1084 Set eSet = regMap.entrySet(); 1085 for(Iterator itr = eSet.iterator(); itr.hasNext(); ) { 1086 Map.Entry pair = (Map.Entry)itr.next(); 1087 allDiscoveredRegs.put(pair.getKey(),pair.getValue()); 1088 }//end loop 1089 /* Loop thru regInfo's, adding only those not already known */ 1090 for( Iterator itr=registrationByID.values().iterator(); 1091 itr.hasNext(); ) 1092 { 1093 RegistrationInfo regInfo = (RegistrationInfo)itr.next(); 1094 /* Build and send the "discovered event" if appropriate */ 1095 maybeSendDiscoveredEvent(regInfo,regMap); 1096 }//end loop 1097 } finally { 1098 concurrentObj.writeUnlock(); 1099 } 1100 }//end run 1101 1102 }//end class DiscoveredEventTask 1103 1104 /** This class represents a <code>Task</code> object that is placed 1105 * in the <code>TaskManager</code> queue for processing in the thread 1106 * pool. An instance of this class is placed on the task queue when a 1107 * <code>DiscoveryEvent</code> instance indicating a discarded event 1108 * is received from the local discovery process. 1109 * <p> 1110 * The <code>run</code> method of this class will process event 1111 * information resulting from the "discarding" of one or more 1112 * lookup services (registrars), and will determine to which active 1113 * registrations the appropriate <code>RemoteDiscoveryEvent</code> 1114 * should be sent; and then sends that event. 1115 */ 1116 private final class DiscardedEventTask implements Runnable { 1117 /** The local event sent by the discovery manager. */ 1118 public final DiscoveryEvent event; 1119 /** Constructs an instance of this class and stores the event*/ 1120 public DiscardedEventTask(DiscoveryEvent event) { 1121 this.event = event; 1122 }//end constructor 1123 /** This method processes the local discovery event information and 1124 * determines, based on the current state of each active 1125 * registration, to which such registration the appropriate 1126 * <code>RemoteDiscoveryEvent</code> should be sent. After making 1127 * the determination, the remote event appropriate for each 1128 * registration is constructed and sent. 1129 */ 1130 public void run() { 1131 concurrentObj.writeLock(); 1132 logInfoTasks("DiscardedEventTask.run(): processing DISCARDED " 1133 +"event from discovery manager"); 1134 try { 1135 /* Get the registrars that were just discarded */ 1136 Map groupsMap = event.getGroups(); 1137 HashSet allDiscardedRegs = new HashSet(groupsMap.size()); 1138 /* Determine if we're here because of an external request for 1139 * discard from one of the regInfo's (an active communication 1140 * discard), or because the discovery manager has determined 1141 * one or more of the discovered registrars has become 1142 * unreachable (a passive communication discard) 1143 */ 1144 RegistrationInfo regInfo = externalDiscardRequest(); 1145 /* If an external request, send the discarded event to only 1146 * the regInfo that requested the discard; otherwise, send 1147 * it to all regInfo's that might be interested. 1148 */ 1149 if(regInfo != null) { 1150 /* Send discard event to only this one registration */ 1151 HashSet discardedRegs = maybeSendDiscardedEvent 1152 (regInfo,groupsMap,true); 1153 /* Transfer the just-discarded regs to the summary set */ 1154 for(Iterator jtr=discardedRegs.iterator();jtr.hasNext(); ){ 1155 allDiscardedRegs.add(jtr.next()); 1156 } 1157 } else { 1158 /* Send discard event to each "eligible" registration */ 1159 for( Iterator itr=registrationByID.values().iterator(); 1160 itr.hasNext(); ) 1161 { 1162 regInfo = (RegistrationInfo)itr.next(); 1163 HashSet discardedRegs = maybeSendDiscardedEvent 1164 (regInfo,groupsMap,false); 1165 /* Transfer the just-discarded regs to summary set */ 1166 for(Iterator jtr=discardedRegs.iterator(); 1167 jtr.hasNext(); ) { 1168 allDiscardedRegs.add(jtr.next()); 1169 } 1170 }//end loop 1171 }//endif 1172 maybeRemoveDiscardedRegsFromGlobalSet(allDiscardedRegs); 1173 } finally { 1174 concurrentObj.writeUnlock(); 1175 } 1176 }//end run 1177 1178 /** This method determines, based on the current state of the 1179 * <code>regInfo</code> parameter, whether or not to send a 1180 * remote discarded event to the regInfo's listener, and then builds 1181 * and sends the event if appropriate. This method is called in 1182 * response to one of the following situations: 1183 * <p> 1184 * 1 after invocation of the public <code>discard</code> method 1185 * 2 after receipt of a "passive" discarded event from the discovery 1186 * manager. 1187 * <p> 1188 * For case 1, such an event typically indicates what is referred to 1189 * as an "active, communication" discarded event. This term is used 1190 * in this situation because the regInfo takes the specific action 1191 * of requesting that a registrar the client has determined is 1192 * unreachable be discarded. 1193 * <p> 1194 * For case 2, such an event typically indicates what is referred to 1195 * as a "passive, communication" discarded event. This term is used 1196 * here because the discovery manager - not the client - has determined 1197 * that one or more of the previously discovered registrars are now 1198 * unreachable. In this case, the client remains "passive", and it 1199 * is the discovery manager that discards the unreachable registrars 1200 * and notifies the client(s). 1201 * 1202 * @param regInfo the data structure record corresponding to the 1203 * registration whose listener will receive the event 1204 * @param groupsMap mapping from the registrars referenced in the 1205 * just-received event to their corresponding set of 1206 * member groups 1207 * @param active flag indicating whether the event is an "active" 1208 * or a "passive" discarded event 1209 * 1210 * @return set of registrars that were discarded for the given regInfo 1211 */ 1212 private HashSet maybeSendDiscardedEvent(RegistrationInfo regInfo, 1213 Map<ServiceRegistrar,String[]> groupsMap, 1214 boolean active) 1215 { 1216 HashSet discardedRegs = new HashSet(groupsMap.size()); //return val 1217 /* If no interest in groups or locators, go to next regInfo*/ 1218 if( (regInfo.groups != null) && ((regInfo.groups).size() == 0) 1219 && ((regInfo.locators).size() == 0) ) 1220 { 1221 return discardedRegs; 1222 } 1223 HashMap<ServiceRegistrar,String[]> discardMap = new HashMap<ServiceRegistrar,String[]>(groupsMap.size()); 1224 /* loop thru the (registrar,groups) pairs, find regs to discard */ 1225 Set eSet = groupsMap.entrySet(); 1226 for(Iterator itr = eSet.iterator(); itr.hasNext(); ) { 1227 Map.Entry pair = (Map.Entry)itr.next(); 1228 ServiceRegistrar reg = (ServiceRegistrar)pair.getKey(); 1229 /* Include the current reg in the discard map only if that 1230 * reg is in the regInfo's discovered set. 1231 */ 1232 if( (regInfo.discoveredRegsMap).containsKey(reg) ) { 1233 /* The groups corresponding to the discarded registrar that 1234 * arrived in the event may be more up-to-date than the 1235 * groups associated with the registrar in the global map. 1236 * Thus, if the event is a passive communication discarded 1237 * event, when determining whether the regInfo is still 1238 * interested in the discarded registrar, use the old group 1239 * info rather than the group info sent in the event. 1240 */ 1241 String[] regGroups = (active ? (String[])pair.getValue() : 1242 ((LocatorGroupsStruct)allDiscoveredRegs.get(reg)).groups ); 1243 1244 if( active || interested(regGroups,regInfo.groups) ) { 1245 discardMap.put(reg,regGroups); 1246 discardedRegs.add(reg); 1247 (regInfo.discoveredRegsMap).remove(reg); 1248 }//end if 1249 }//end if 1250 }//end loop 1251 /* Build and send the "discarded event" */ 1252 RemoteDiscoveryEvent event = buildEvent(regInfo,discardMap,true); 1253 if(event != null) { 1254 queueEvent(regInfo,event); 1255 logInfoEvents("DiscardedEventTask.run(): " 1256 +"DISCARDED Event SENT to regInfo\n"); 1257 } 1258 return discardedRegs; 1259 }//end maybeSendDiscardedEvent 1260 1261 }//end class DiscardedEventTask 1262 1263 /** This class represents a <code>Task</code> object that is placed 1264 * in the <code>TaskManager</code> queue for processing in the thread 1265 * pool. Instances of this class are placed on the task queue when 1266 * registrations request that a given registrar be discarded. 1267 * <p> 1268 * The <code>run</code> method of this class will remove the indicated 1269 * registrar from the registration's set of discovered registrars and 1270 * if successfully removed, will build and send a remote discarded event 1271 * to the registration's listener. 1272 */ 1273 private final class DiscardRegistrarTask implements Runnable { 1274 /** Data structure record corresponding to the registration that has 1275 * requested to have one of its discovered registrars discarded 1276 */ 1277 public final RegistrationInfo regInfo; 1278 /** The registrar to discard */ 1279 public final ServiceRegistrar registrar; 1280 /** Constructs an instance of this class and stores the registration 1281 * information. 1282 */ 1283 public DiscardRegistrarTask(RegistrationInfo regInfo, 1284 ServiceRegistrar registrar) 1285 { 1286 this.regInfo = regInfo; 1287 this.registrar = registrar; 1288 }//end constructor 1289 /** This method attempts to remove the indicated registrar from 1290 * the registration's set of discovered registrars. If successful, 1291 * this method builds and sends a remote discarded event to the 1292 * registration's listener. 1293 */ 1294 public void run() { 1295 concurrentObj.writeLock(); 1296 try { 1297 logInfoTasks("DiscardRegistrarTask.run(): " 1298 +"registrar requested to be discarded"); 1299 /* Remove registrar from regInfo's set and send event */ 1300 if( (regInfo.discoveredRegsMap).remove(registrar) != null) { 1301 HashMap groupsMap = mapRegToGroups(registrar, 1302 ((LocatorGroupsStruct)allDiscoveredRegs.get(registrar)).groups); 1303 1304 RemoteDiscoveryEvent event = buildEvent 1305 (regInfo,groupsMap,true); 1306 if(event != null) { 1307 queueEvent(regInfo,event); 1308 logInfoEvents("DiscardRegistrarTask.run(): " 1309 +"DISCARDED Event was SENT\n"); 1310 }//endif 1311 maybeRemoveDiscardedRegFromGlobalSet(registrar); 1312 } 1313 } finally { 1314 concurrentObj.writeUnlock(); 1315 } 1316 }//end run 1317 }//end class DiscardRegistrarTask 1318 1319 /** This class represents a <code>Task</code> object that is placed 1320 * in the <code>TaskManager</code> queue for processing in the thread 1321 * pool. An instance of this class is placed on the task queue when a 1322 * <code>DiscoveryEvent</code> instance indicating a changed event 1323 * is received from the local discovery process. 1324 * <p> 1325 * The <code>run</code> method of this class will process event 1326 * information resulting from a change in the state of the member 1327 * groups of one or more lookup services (registrars). This task 1328 * analyzes the group information in the event and, based on that 1329 * information, determines which active registrations are no longer 1330 * interested in the registrars referenced in the event. A 1331 * <code>RemoteDiscoveryEvent</code> indicating a discarded event 1332 * will be sent to each active registration that has lost interest 1333 * in any of the registrars of the event. 1334 */ 1335 private final class ChangedEventTask implements Runnable { 1336 /** The local event sent by the discovery manager. */ 1337 public final DiscoveryEvent event; 1338 /** Constructs an instance of this class and stores the event*/ 1339 public ChangedEventTask(DiscoveryEvent event) { 1340 this.event = event; 1341 }//end constructor 1342 /** This method processes the local discovery event information and 1343 * determines, based on the current state of each active 1344 * registration, to which such registration the appropriate 1345 * <code>RemoteDiscoveryEvent</code> should be sent. After making 1346 * the determination, the remote event appropriate for each 1347 * registration is constructed and sent. 1348 */ 1349 public void run() { 1350 concurrentObj.writeLock(); 1351 logInfoTasks("ChangedEventTask.run(): processing CHANGED " 1352 +"event from discovery manager"); 1353 try { 1354 Map groupsMap = event.getGroups(); 1355 HashSet allDiscardedRegs = new HashSet(groupsMap.size()); 1356 HashMap locatorMap = new HashMap(groupsMap.size()); 1357 /* Retrieve the locators of each registrar in the event */ 1358 for(Iterator itr = (groupsMap.keySet()).iterator(); 1359 itr.hasNext(); ) 1360 { 1361 ServiceRegistrar reg = (ServiceRegistrar)itr.next(); 1362 locatorMap.put(reg, 1363 ((LocatorGroupsStruct)allDiscoveredRegs.get(reg)).locator); 1364 }//end loop 1365 1366 for( Iterator itr=registrationByID.values().iterator(); 1367 itr.hasNext(); ) 1368 { 1369 RegistrationInfo regInfo = (RegistrationInfo)itr.next(); 1370 HashSet discardedRegs = maybeSendDiscardedEvent 1371 (regInfo,groupsMap,locatorMap); 1372 /* Transfer the just-discarded regs to the summary set */ 1373 for(Iterator jtr=discardedRegs.iterator();jtr.hasNext(); ){ 1374 allDiscardedRegs.add(jtr.next()); 1375 }//end loop 1376 }//end loop 1377 maybeRemoveDiscardedRegsFromGlobalSet(allDiscardedRegs); 1378 updateGroupsInGlobalSet(groupsMap); //replace with new groups 1379 } finally { 1380 concurrentObj.writeUnlock(); 1381 } 1382 }//end run 1383 1384 /** This method determines, based on the current state of the 1385 * <code>regInfo</code> parameter, whether or not to send a 1386 * remote discarded event to the regInfo's listener, and then builds 1387 * and sends the event if appropriate. This method is called in 1388 * response to the receipt of a changed event from the discovery 1389 * manager. 1390 * <p> 1391 * Such an event may indicate what is referred to as a 1392 * "passive, no interest" discard; passive because the event 1393 * resulted from action taken by the discovery manager rather than 1394 * the client, and no interest because the discovery manager sends 1395 * such an event when it determines that one or more of the 1396 * previously discovered registrars - although still reachable - 1397 * have changed their member groups in such a way that they may 1398 * now be of no interest to one or more of the client registrations. 1399 * <p> 1400 * Note that changed events can be sent for registrars having a 1401 * locator and member groups that the current regInfo never asked 1402 * to be discovered. This can happen because some other regInfo 1403 * asked that the registrar's locator or groups be discovered. 1404 * <p> 1405 * If a particular registrar is contained in the discovered set 1406 * of the given regInfo, then we know that that regInfo must 1407 * have requested discovery of the registrar (through either 1408 * locator or group discovery). If the registrar is not contained 1409 * in that set, then there's no need to proceed with the processing 1410 * of the registrar since we don't want to send a discarded event 1411 * to a regInfo that was never interested in that registrar in the 1412 * first place. 1413 * <p> 1414 * If the locator of the registrar is contained in the regInfo's 1415 * set of locators to discover, then that regInfo is considered 1416 * "still interested" in the registrar; and so no discarded event 1417 * is sent to the regInfo. 1418 * <p> 1419 * Thus, a discarded event is sent to the given regInfo only 1420 * if the regInfo is not interested in discovering the registrar 1421 * through locator discovery, and the registrar's member groups have 1422 * changed in such a way that it now belongs to groups that 1423 * the regInfo is not interested in discovering and joining. 1424 * 1425 * @param regInfo the data structure record corresponding to the 1426 * registration whose listener will receive the event 1427 * @param groupsMap mapping from the registrars referenced in the 1428 * just-received event to their corresponding set of 1429 * member groups 1430 * @param locatorMap mapping from the registrars referenced in the 1431 * just-received event to their corresponding locator 1432 * 1433 * @return the registrars that were discarded for the given regInfo 1434 */ 1435 private HashSet maybeSendDiscardedEvent(RegistrationInfo regInfo, 1436 Map groupsMap, 1437 Map locatorMap) 1438 { 1439 /* For each registrar discard candidate, send a discarded event if: 1440 * The candidate is in the discovered set and 1441 * a. regInfo is configured for at least group discovery 1442 * b. candidate is NOT to be discovered by locator discovery 1443 * c. regInfo is no longer interested in the candidate's groups 1444 */ 1445 HashSet discardedRegs = new HashSet(groupsMap.size()); //return val 1446 /* If this regInfo isn't interested in groups, go to next regInfo*/ 1447 if( (regInfo.groups != null) && ((regInfo.groups).size() == 0) ) 1448 { 1449 return discardedRegs; 1450 } 1451 HashMap discardMap = new HashMap(groupsMap.size()); 1452 /* loop thru the (registrar,groups) pairs, find regs to discard */ 1453 Set eSet = groupsMap.entrySet(); 1454 for(Iterator itr = eSet.iterator(); itr.hasNext(); ) { 1455 Map.Entry pair = (Map.Entry)itr.next(); 1456 ServiceRegistrar reg = (ServiceRegistrar)pair.getKey(); 1457 String[] regGroups = (String[])pair.getValue(); 1458 LookupLocator regLoc = (LookupLocator)locatorMap.get(reg); 1459 /* Include the current reg in the discard map only if that 1460 * reg is in the regInfo's discovered set, the regInfo 1461 * is not interested in discovering the reg through locator 1462 * discovery, and the reg's member groups have changed in 1463 * such a way that it now belongs to groups that the regInfo 1464 * is not interested in discovering and joining. 1465 */ 1466 if( ( (regInfo.discoveredRegsMap).containsKey(reg) ) 1467 && (!interested(regLoc,regGroups, 1468 regInfo.locators,regInfo.groups)) ) 1469 { 1470 discardMap.put(reg,regGroups); 1471 discardedRegs.add(reg); 1472 (regInfo.discoveredRegsMap).remove(reg); 1473 } 1474 }//end loop 1475 /* Build and send the "discarded event" */ 1476 RemoteDiscoveryEvent event = buildEvent(regInfo,discardMap,true); 1477 if(event != null) { 1478 queueEvent(regInfo,event); 1479 logInfoEvents("ChangedEventTask.run(): " 1480 +"DISCARDED Event was SENT\n"); 1481 }//endif 1482 return discardedRegs; 1483 }//end maybeSendDiscardedEvent 1484 }//end class ChangedEventTask 1485 1486 /** This class represents a <code>Task</code> object that is placed 1487 * in the <code>TaskManager</code> queue for processing in the thread 1488 * pool. Instances of this class are placed on the task queue when 1489 * a registration has requested the augmentation of the set of groups 1490 * that currently will be discovered for it. 1491 */ 1492 private final class AddGroupsTask implements Runnable { 1493 /** Data structure record of the registration that made the request */ 1494 public final RegistrationInfo regInfo; 1495 /** The group set with which to replace the registration's old set */ 1496 public final String[] groups; 1497 /** Constructs an instance of this class and stores the input */ 1498 public AddGroupsTask(RegistrationInfo regInfo, String[] groups) { 1499 this.regInfo = regInfo; 1500 this.groups = groups; 1501 }//end constructor 1502 public void run() { 1503 /* For the regInfo associated with the current instance of this 1504 * task, do the following: 1505 * a. in the given regInfo data structure, add the new groups, 1506 * with duplicates removed, to that regInfo's current set of 1507 * desired groups 1508 * b. from the global mapping of all currently discovered 1509 * registrars to (locator,groups) pairs, retrieve the elements 1510 * that contain registrars belonging to groups that regInfo 1511 * should now be interested in as a result of the call to 1512 * addGroups 1513 * c. for each registrar-to-(locator,groups) mapping retrieved in 1514 * b. above, add that mapping to the given regInfo data 1515 * structure's discovered state (these are the registrars that 1516 * were previously discovered for OTHER regInfo's, not the 1517 * current regInfo) 1518 * d. for each of the registrars previously discovered for other 1519 * registrations that belong to any of the new groups regInfo 1520 * is now interested in as a result of the call to addGroups, 1521 * queue a remote discovery event to be sent to that regInfo's 1522 * listener 1523 * e. if any of the new groups regInfo is now interested in as 1524 * as a result of the call to addGroups were not previously 1525 * in the local discovery manager's managed set of groups, 1526 * (and the local discovery manager is currently not configured 1527 * to discover ALL_GROUPS), add the new groups to the local 1528 * discovery manager so that when that manager does discover 1529 * one of those groups in the future, a remote discovered 1530 * event will be sent to the given regInfo's listener 1531 */ 1532 concurrentObj.writeLock(); 1533 try { 1534 HashSet newGroupSet = addRegInfoGroups(regInfo,groups); // a. 1535 if(newGroupSet.size() > 0) { 1536 logInfoTasks("AddGroupsTask.run(): adding to the " 1537 +"registration's groups"); 1538 Map discoveredRegs = getDesiredRegsByGroup 1539 (regInfo); // b. 1540 Map regsAdded = regInfo.addToDiscoveredRegs 1541 (discoveredRegs); // c. 1542 RemoteDiscoveryEvent event = buildEvent 1543 (regInfo,regsAdded,false); // d. 1544 if(event != null) { 1545 queueEvent(regInfo,event); // d. 1546 logInfoEvents("AddGroupsTask.run(): DISCOVERED " 1547 +"Event was SENT\n"); 1548 }//endif 1549 updateDiscoveryMgrGroups(); // e. 1550 }//endif(newGroupSet.size() > 0) 1551 } finally { 1552 concurrentObj.writeUnlock(); 1553 } 1554 }//end run 1555 1556 /** Augments the registration's managed set of groups with the new 1557 * groups. 1558 * 1559 * @return the set of new groups added to regInfo's desired groups 1560 */ 1561 private HashSet addRegInfoGroups(RegistrationInfo regInfo, 1562 String[] groups) 1563 { 1564 /* Build a HashSet (removes duplicates) from the input groups */ 1565 HashSet newGroupSet = new HashSet(1); 1566 for(int i=0;i<groups.length;i++) { 1567 newGroupSet.add(groups[i]); 1568 }//end loop 1569 /* If the input set was not empty, add the new groups to the 1570 * registration's managed set of groups. 1571 */ 1572 if( newGroupSet.size() > 0 ) { 1573 (regInfo.groups).addAll(newGroupSet); 1574 }//endif 1575 return newGroupSet; 1576 }//end addRegInfoGroups 1577 1578 }//end class AddGroupsTask 1579 1580 /** This class represents a <code>Task</code> object that is placed 1581 * in the <code>TaskManager</code> queue for processing in the thread 1582 * pool. Instances of this class are placed on the task queue when 1583 * a registration has requested the replacement of the set of groups 1584 * that currently will be discovered for it. 1585 */ 1586 private final class SetGroupsTask implements Runnable { 1587 /** Data structure record of the registration that made the request */ 1588 public final RegistrationInfo regInfo; 1589 /** The group set with which to replace the registration's old set */ 1590 public final String[] groups; 1591 /** Constructs an instance of this class and stores the input */ 1592 public SetGroupsTask(RegistrationInfo regInfo, String[] groups) { 1593 this.regInfo = regInfo; 1594 this.groups = groups; 1595 }//end constructor 1596 public void run() { 1597 /* For the regInfo associated with the current instance of this 1598 * task, do the following: 1599 * a. from the global mapping of all currently discovered 1600 * registrars to their (locator,groups) pair, retrieve the 1601 * elements that contain registrars belonging to groups that 1602 * regInfo was interested in PRIOR to the call to setGroups 1603 * b. in the given regInfo data structure, replace that regInfo's 1604 * current set of desired groups with the new set of desired 1605 * groups that resulted from the call to setGroups 1606 * c. again from the global mapping of all currently discovered 1607 * registrars to (locator,groups) pairs, retrieve the elements 1608 * that contain registrars belonging to groups that regInfo 1609 * should now be interested in as a result of the call to 1610 * setGroups 1611 * d. for each registrar-to-(locator,groups) mapping retrieved in 1612 * c. above, add that mapping to the given regInfo data 1613 * structure's state (these are the registrars that were 1614 * previously discovered for OTHER regInfo's, not the current 1615 * regInfo) 1616 * e. for each of the registrars previously discovered for other 1617 * registrations that belong to any of the new groups regInfo 1618 * is now interested in as a result of the call to setGroups, 1619 * queue a remote discovery event to be sent to that regInfo's 1620 * listener 1621 * f. from the mapping of already-discovered registrars that 1622 * regInfo was interested in prior to the call to setGroups 1623 * (the mapping retrieved in a. above), retrieve the elements 1624 * that contain registrars belonging to groups that regInfo is 1625 * no longer interested in due to the call to setGroups 1626 * g. for each registrar-to-(locator,groups) mapping retrieved in 1627 * f. above, remove that mapping from the given regInfo data 1628 * structure's state, and queue a remote discarded event to be 1629 * sent to that regInfo's listener 1630 * h. if any of the new groups regInfo is now interested in as 1631 * as a result of the call to setGroups were not previously 1632 * in the local discovery manager's managed set of groups, 1633 * add those groups to that discovery manager so that when 1634 * that manager does discover one of those groups in the 1635 * future, a remote discovered event will be sent to the given 1636 * regInfo's listener 1637 */ 1638 concurrentObj.writeLock(); 1639 try { 1640 logInfoTasks("SetGroupsTask.run(): setting the " 1641 +"registration's groups"); 1642 Map oldDesiredRegs = getDesiredRegsByGroup(regInfo); // a. 1643 setRegInfoGroups(regInfo,groups); // b. 1644 Map newDesiredRegs = getDesiredRegsByGroup(regInfo); // c. 1645 Map regsAdded = regInfo.addToDiscoveredRegs 1646 (newDesiredRegs); // d. 1647 RemoteDiscoveryEvent event = buildEvent 1648 (regInfo,regsAdded,false); // e. 1649 if(event != null) { 1650 queueEvent(regInfo,event); // e. 1651 logInfoEvents("SetGroupsTask.run(): DISCOVERED " 1652 +"Event was SENT\n"); 1653 }//endif 1654 Map discardRegs = getUndesiredRegsByGroup 1655 (oldDesiredRegs,regInfo); // f. 1656 for(Iterator itr = (discardRegs.keySet()).iterator(); 1657 itr.hasNext(); ) 1658 { 1659 (regInfo.discoveredRegsMap).remove(itr.next()); // g. 1660 }//end loop 1661 event = buildEvent(regInfo,discardRegs,true); // g. 1662 if(event != null) { 1663 queueEvent(regInfo,event); // g. 1664 logInfoEvents("SetGroupsTask.run(): " 1665 +"DISCARDED Event was SENT\n"); 1666 }//endif 1667 updateDiscoveryMgrGroups(); // h. 1668 } finally { 1669 concurrentObj.writeUnlock(); 1670 } 1671 }//end run 1672 1673 /** Replaces the registration's managed set of groups with the new 1674 * groups (even if the new set of groups is empty -- this just means 1675 * group discovery will be "turned off" for this registration). 1676 */ 1677 private void setRegInfoGroups(RegistrationInfo regInfo, 1678 String[] groups) 1679 { 1680 if(groups == DiscoveryGroupManagement.ALL_GROUPS) { 1681 regInfo.groups = null; 1682 } else { 1683 /* Build a HashSet from the input set */ 1684 HashSet newGroups = new HashSet(); 1685 for(int i=0;i<groups.length;i++) { 1686 newGroups.add(groups[i]); 1687 }//end loop 1688 /* Prepare the registration's managed set for replacement */ 1689 if(regInfo.groups == null) { 1690 regInfo.groups = new HashSet(); 1691 } else { 1692 (regInfo.groups).clear(); 1693 }//endif 1694 /* Replace the registration's managed set with the new set */ 1695 (regInfo.groups).addAll(newGroups); 1696 }//end if (groups == DiscoveryGroupManagement.ALL_GROUPS) 1697 }//end setRegInfoGroups 1698 }//end class SetGroupsTask 1699 1700 /** This class represents a <code>Task</code> object that is placed 1701 * in the <code>TaskManager</code> queue for processing in the thread 1702 * pool. Instances of this class are placed on the task queue when 1703 * a registration has requested the removal of a set of groups from 1704 * the current set of groups to discover for it. 1705 */ 1706 private final class RemoveGroupsTask implements Runnable { 1707 /** Data structure record of the registration that made the request */ 1708 public final RegistrationInfo regInfo; 1709 /** The groups to remove from the registration's old set */ 1710 public final String[] groups; 1711 /** Constructs an instance of this class and stores the input */ 1712 public RemoveGroupsTask(RegistrationInfo regInfo, String[] groups) { 1713 this.regInfo = regInfo; 1714 this.groups = groups; 1715 }//end constructor 1716 public void run() { 1717 concurrentObj.writeLock(); 1718 try { 1719 if(groups.length == 0) return; // nothing from which to remove 1720 logInfoTasks("RemoveGroupsTask.run(): removing groups from " 1721 +"the registration's current group set"); 1722 /* regInfo's discovered regs (by group) previously desired */ 1723 Map oldDesiredRegs = getDesiredRegsByGroup(regInfo); 1724 /* update regInfo's desired regs */ 1725 removeRegInfoGroups(regInfo,groups); 1726 /* regInfo's discovered regs (by group) no longer desired */ 1727 Map discardRegs = getUndesiredRegsByGroup(oldDesiredRegs, 1728 regInfo); 1729 /* remove regInfo's undesired regs from its discovered map */ 1730 for(Iterator itr = (discardRegs.keySet()).iterator(); 1731 itr.hasNext(); ) 1732 { 1733 (regInfo.discoveredRegsMap).remove(itr.next()); 1734 }//end loop 1735 RemoteDiscoveryEvent event = buildEvent 1736 (regInfo,discardRegs,true); 1737 if(event != null) { 1738 queueEvent(regInfo,event); 1739 logInfoEvents("RemoveGroupsTask.run(): " 1740 +"DISCARDED Event was SENT\n"); 1741 }//endif 1742 updateDiscoveryMgrGroups(); // may send more discards 1743 } finally { 1744 concurrentObj.writeUnlock(); 1745 } 1746 }//end run 1747 1748 /** Removes the elements of the given set from the given registration's 1749 * current set of groups to discover. 1750 */ 1751 private void removeRegInfoGroups(RegistrationInfo regInfo, 1752 String[] groups) 1753 { 1754 HashSet<String> removeSet = new HashSet<String>(); 1755 int l = groups.length; 1756 for(int i = 0; i < l; i++) { 1757 removeSet.add(groups[i]); 1758 }//end loop 1759 (regInfo.groups).removeAll(removeSet); 1760 }//end setRegInfoGroups 1761 1762 }//end class RemoveGroupsTask 1763 1764 /** This class represents a <code>Task</code> object that is placed 1765 * in the <code>TaskManager</code> queue for processing in the thread 1766 * pool. Instances of this class are placed on the task queue when 1767 * a registration has requested the augmentation of the set of locators 1768 * that currently will be discovered for it. 1769 */ 1770 private final class AddLocatorsTask implements Runnable { 1771 /** Data structure record of the registration that made the request */ 1772 public final RegistrationInfo regInfo; 1773 /** The locator set with which to replace the registration's old set */ 1774 public final LookupLocator[] locators; 1775 /** Constructs an instance of this class and stores the input */ 1776 public AddLocatorsTask(RegistrationInfo regInfo, 1777 LookupLocator[] locators) 1778 { 1779 this.regInfo = regInfo; 1780 this.locators = locators; 1781 }//end constructor 1782 public void run() { 1783 /* For the regInfo associated with the current instance of this 1784 * task, do the following: 1785 * a. in the given regInfo data structure, add the new locators, 1786 * with duplicates removed, to that regInfo's current set of 1787 * desired locators 1788 * b. from the global mapping of all currently discovered 1789 * registrars to (locator,groups) pairs, retrieve the elements 1790 * that contain registrars having locators that regInfo 1791 * should now be interested in as a result of the call to 1792 * addLocators 1793 * c. for each registrar-to-(locator,groups) mapping retrieved in 1794 * b. above, add that mapping to the given regInfo data 1795 * structure's discovered state (these are the registrars that 1796 * were previously discovered for OTHER regInfo's, not the 1797 * current regInfo) 1798 * d. for each of the registrars previously discovered for other 1799 * registrations that have locators equal to any of the new 1800 * locators regInfo is now interested in as a result of the 1801 * call to addLocators, queue a remote discovery event to be 1802 * sent to that regInfo's listener 1803 * e. if any of the new locators regInfo is now interested in as 1804 * as a result of the call to addLocators were not previously 1805 * in the local discovery manager's managed set of locators, 1806 * add the new locators to the local discovery manager so that 1807 * when that manager does discover one of those locators in 1808 * the future, a remote discovered event will be sent to the 1809 * given regInfo's listener 1810 */ 1811 concurrentObj.writeLock(); 1812 try { 1813 HashSet newLocSet = addRegInfoLocators(regInfo,locators);// a. 1814 if(newLocSet.size() > 0) { 1815 logInfoTasks("AddLocatorsTask.run(): adding to the " 1816 +"registration's locators"); 1817 Map discoveredRegs = getDesiredRegsByLocator 1818 (regInfo); // b. 1819 Map regsAdded = regInfo.addToDiscoveredRegs 1820 (discoveredRegs); // c. 1821 RemoteDiscoveryEvent event = buildEvent 1822 (regInfo,regsAdded,false); // d. 1823 if(event != null) { 1824 queueEvent(regInfo,event); // d. 1825 logInfoEvents("AddLocatorsTask.run(): DISCOVERED " 1826 +"Event was SENT\n"); 1827 }//endif 1828 updateDiscoveryMgrLocators(); // e. 1829 }//endif(newLocSet.size() > 0) 1830 } finally { 1831 concurrentObj.writeUnlock(); 1832 } 1833 }//end run 1834 1835 /** Augments the registration's managed set of locators with the new 1836 * locators. 1837 * 1838 * @return the set of new locators added to regInfo's desired locators 1839 */ 1840 private HashSet addRegInfoLocators(RegistrationInfo regInfo, 1841 LookupLocator[] locators) 1842 { 1843 /* Build a HashSet (removes duplicates) from the input locators */ 1844 HashSet newLocSet = new HashSet(1); 1845 for(int i=0;i<locators.length;i++) { 1846 newLocSet.add(locators[i]); 1847 }//end loop 1848 /* If the input set was not empty, add the new locators to the 1849 * registration's managed set of locators. 1850 */ 1851 if( newLocSet.size() > 0 ) { 1852 (regInfo.locators).addAll(newLocSet); 1853 }//endif 1854 return newLocSet; 1855 }//end addRegInfoLocators 1856 }//end class AddLocatorsTask 1857 1858 /** This class represents a <code>Task</code> object that is placed 1859 * in the <code>TaskManager</code> queue for processing in the thread 1860 * pool. Instances of this class are placed on the task queue when 1861 * a registration has requested the replacement of the set of locators 1862 * that currently will be discovered for it. 1863 */ 1864 private final class SetLocatorsTask implements Runnable { 1865 /** Data structure record of the registration that made the request */ 1866 public final RegistrationInfo regInfo; 1867 /** The locator set with which to replace the registration's old set */ 1868 public final LookupLocator[] locators; 1869 /** Constructs an instance of this class and stores the input */ 1870 public SetLocatorsTask(RegistrationInfo regInfo, 1871 LookupLocator[] locators) 1872 { 1873 this.regInfo = regInfo; 1874 this.locators = locators; 1875 }//end constructor 1876 public void run() { 1877 /* For the regInfo associated with the current instance of this 1878 * task, do the following: 1879 * a. from the global mapping of all currently discovered 1880 * registrars to their (locator,groups) pair, retrieve the 1881 * elements that contain registrars having locators that 1882 * regInfo was interested in PRIOR to the call to setGroups 1883 * b. in the given regInfo data structure, replace that regInfo's 1884 * current set of desired locators with the new set of desired 1885 * locators that resulted from the call to setLocators 1886 * c. again from the global mapping of all currently discovered 1887 * registrars to (locator,groups) pairs, retrieve the elements 1888 * that contain registrars having locators that regInfo should 1889 * now be interested in as a result of the call to setLocators 1890 * d. for each registrar-to-(locator,groups) mapping retrieved in 1891 * c. above, add that mapping to the given regInfo data 1892 * structure's state (these are the registrars that were 1893 * previously discovered for OTHER regInfo's, not the current 1894 * regInfo) 1895 * e. for each of the registrars previously discovered for other 1896 * registrations that have locators equal to the new locators 1897 * regInfo is now interested in as a result of the call to 1898 * setLocators, queue a remote discovery event to be sent to 1899 * that regInfo's listener 1900 * f. from the mapping of already-discovered registrars that 1901 * regInfo was interested in prior to the call to setLocators 1902 * (the mapping retrieved in a. above), retrieve the elements 1903 * that contain registrars having locators that regInfo is 1904 * no longer interested in due to the call to setLocators 1905 * g. for each registrar-to-(locator,groups) mapping retrieved in 1906 * f. above, remove that mapping from the given regInfo data 1907 * structure's state, and queue a remote discarded event to be 1908 * sent to that regInfo's listener 1909 * h. if any of the new locators regInfo is now interested in as 1910 * as a result of the call to setLocators were not previously 1911 * in the local discovery manager's managed set of locators, 1912 * add those locators to that discovery manager so that when 1913 * that manager does discover one of those locators in the 1914 * future, a remote discovery event will be sent to the given 1915 * regInfo's listener 1916 */ 1917 concurrentObj.writeLock(); 1918 try { 1919 logInfoTasks("SetLocatorsTask.run(): setting the " 1920 +"registration's locators"); 1921 Map oldDesiredRegs = getDesiredRegsByLocator(regInfo); // a. 1922 setRegInfoLocators(regInfo,locators); // b. 1923 Map newDesiredRegs = getDesiredRegsByLocator(regInfo);// c. 1924 Map regsAdded = regInfo.addToDiscoveredRegs 1925 (newDesiredRegs); // d. 1926 RemoteDiscoveryEvent event = buildEvent 1927 (regInfo,regsAdded,false); // e. 1928 if(event != null) { 1929 queueEvent(regInfo,event); // e. 1930 logInfoEvents("SetLocatorsTask.run(): DISCOVERED " 1931 +"Event was SENT\n"); 1932 }//endif 1933 Map undesiredRegs = getUndesiredRegsByLocator 1934 (oldDesiredRegs,regInfo); // f. 1935 HashMap discardRegs = new HashMap(undesiredRegs.size()); 1936 for(Iterator itr = (undesiredRegs.keySet()).iterator(); 1937 itr.hasNext(); ) 1938 { 1939 ServiceRegistrar reg = (ServiceRegistrar)itr.next(); 1940 (regInfo.discoveredRegsMap).remove(reg); // g. 1941 discardRegs.put(reg, 1942 ((LocatorGroupsStruct)allDiscoveredRegs.get(reg)).groups); 1943 1944 }//end loop 1945 event = buildEvent(regInfo,discardRegs,true); // g. 1946 if(event != null) { 1947 queueEvent(regInfo,event); // g. 1948 logInfoEvents("SetLocatorsTask.run(): " 1949 +"DISCARDED Event was SENT\n"); 1950 }//endif 1951 updateDiscoveryMgrLocators(); // h. 1952 } finally { 1953 concurrentObj.writeUnlock(); 1954 } 1955 }//end run 1956 1957 /** Replaces the registration's managed set of locators with the new 1958 * locators (even if the new set of locators is empty -- this just 1959 * means locator discovery will be "turned off" for this registration) 1960 */ 1961 private void setRegInfoLocators(RegistrationInfo regInfo, 1962 LookupLocator[] locators) 1963 { 1964 /* Build a HashSet from the input set */ 1965 HashSet newLocSet = new HashSet(); 1966 for(int i=0;i<locators.length;i++) { 1967 newLocSet.add(locators[i]); 1968 }//end loop 1969 /* Prepare the registration's managed set for replacement */ 1970 if(regInfo.locators == null) { 1971 regInfo.locators = new HashSet(); 1972 } else { 1973 (regInfo.locators).clear(); 1974 }//endif 1975 /* Replace the registration's managed set with the new set */ 1976 (regInfo.locators).addAll(newLocSet); 1977 }//end setRegInfoLocators 1978 1979 }//end class SetLocatorsTask 1980 1981 /** This class represents a <code>Task</code> object that is placed 1982 * in the <code>TaskManager</code> queue for processing in the thread 1983 * pool. Instances of this class are placed on the task queue when 1984 * a registration has requested the removal of a set of locators 1985 * from the current set of locators to discover for it. 1986 */ 1987 private final class RemoveLocatorsTask implements Runnable { 1988 /** Data structure record of the registration that made the request */ 1989 public final RegistrationInfo regInfo; 1990 /** The locators to remove from the registration's old set */ 1991 public final LookupLocator[] locators; 1992 /** Constructs an instance of this class and stores the input */ 1993 public RemoveLocatorsTask(RegistrationInfo regInfo, 1994 LookupLocator[] locators) 1995 { 1996 this.regInfo = regInfo; 1997 this.locators = locators; 1998 }//end constructor 1999 public void run() { 2000 concurrentObj.writeLock(); 2001 try { 2002 if(locators.length == 0) return; //nothing from which to remove 2003 2004 logInfoTasks("RemoveLocatorsTask.run(): removing locators " 2005 +"from the registration's current locator set"); 2006 /* regInfo's discovered regs (by locator) previously desired */ 2007 Map oldDesiredRegs = getDesiredRegsByLocator(regInfo); 2008 /* update regInfo's desired regs */ 2009 removeRegInfoLocators(regInfo,locators); 2010 /* regInfo's discovered regs (by locator) no longer desired */ 2011 Map undesiredRegs = getUndesiredRegsByLocator 2012 (oldDesiredRegs,regInfo); 2013 /* remove regInfo's undesired regs from its discovered map, 2014 * and construct the registrars-to-groups map for the event 2015 */ 2016 HashMap discardRegs = new HashMap(undesiredRegs.size()); 2017 for(Iterator itr = (undesiredRegs.keySet()).iterator(); 2018 itr.hasNext(); ) 2019 { 2020 ServiceRegistrar reg = (ServiceRegistrar)itr.next(); 2021 (regInfo.discoveredRegsMap).remove(reg); 2022 discardRegs.put(reg, 2023 ((LocatorGroupsStruct)allDiscoveredRegs.get(reg)).groups); 2024 }//end loop 2025 /* Construct the registrars-to-groups map for the event */ 2026 RemoteDiscoveryEvent event = buildEvent 2027 (regInfo,discardRegs,true); 2028 if(event != null) { 2029 queueEvent(regInfo,event); 2030 logInfoEvents("SetLocatorsTask.run(): " 2031 +"DISCARDED Event was SENT\n"); 2032 }//endif 2033 updateDiscoveryMgrLocators(); // may send more discards 2034 } finally { 2035 concurrentObj.writeUnlock(); 2036 } 2037 }//end run 2038 2039 /** Removes the elements of the given set from the given registration's 2040 * current set of locators to discover. 2041 */ 2042 private void removeRegInfoLocators(RegistrationInfo regInfo, 2043 LookupLocator[] locators) 2044 { 2045 /* Build a HashSet from the input set */ 2046 HashSet removeSet = new HashSet(); 2047 for(int i=0;i<locators.length;i++) { 2048 removeSet.add(locators[i]); 2049 }//end loop 2050 (regInfo.locators).removeAll(removeSet); 2051 }//end removeRegInfoLocators 2052 }//end class RemoveLocatorsTask 2053 2054 /** This class represents a <code>Task</code> object that is placed 2055 * in the <code>TaskManager</code> queue for processing in the thread 2056 * pool. Instances of this class are placed on the task queue when 2057 * a remote event is to be sent to a given registration. 2058 * <p> 2059 * Remote events are sent in a separate task such as this to avoid 2060 * making the remote call to the registration's listener within a 2061 * synchronization block. 2062 */ 2063 private final class SendEventTask implements Runnable { 2064 /** Data structure record corresponding to registration to get event */ 2065 public final RegistrationInfo regInfo; 2066 /** The remote event to send to the given registration's listener */ 2067 public final RemoteDiscoveryEvent event; 2068 /** Constructs an instance of this class and stores the registration 2069 * information. 2070 */ 2071 public SendEventTask(RegistrationInfo regInfo, 2072 RemoteDiscoveryEvent event) 2073 { 2074 this.regInfo = regInfo; 2075 this.event = event; 2076 }//end constructor 2077 /** This method sends a <code>RemoteDiscoveryEvent</code> to the 2078 * listener of the registration that corresponds to the 2079 * <code>regInfo</code> field of this class. This method handles 2080 * all exceptions and error conditions in the appropriate manner. 2081 */ 2082 public void run() { 2083 try { 2084 regInfo.listener.notify(event); 2085 } catch (Throwable e) { 2086 problemLogger.log(Level.INFO, "Exception in SendEventTask", e); 2087 switch (ThrowableConstants.retryable(e)) { 2088 case ThrowableConstants.BAD_OBJECT: 2089 if(e instanceof Error) throw (Error)e; 2090 case ThrowableConstants.BAD_INVOCATION: 2091 case ThrowableConstants.UNCATEGORIZED: 2092 /* If the listener throws UnknownEvent or some other 2093 * definite exception, or the listener is gone, it's 2094 * okay to cancel the lease. 2095 */ 2096 concurrentObj.writeLock(); 2097 try { 2098 try { 2099 logInfoEvents 2100 (" Cancelling lease on registration: " 2101 +" (registrationID,leaseID) = (" 2102 +regInfo.registrationID+", " 2103 +regInfo.leaseID+")"); 2104 cancelLeaseDo(regInfo,regInfo.leaseID); 2105 addLogRecord(new LeaseCancelledLogObj 2106 (regInfo.registrationID, 2107 regInfo.leaseID)); 2108 } catch (UnknownLeaseException ee) { 2109 } catch (IOException ee) { } 2110 } finally { 2111 concurrentObj.writeUnlock(); 2112 } 2113 }//end switch 2114 }//end try 2115 }//end run 2116 }//end class SendEventTask 2117 2118 /** 2119 * Handler class for the persistent storage facility. 2120 * <p> 2121 * At any point during processing in this service, there will exist 2122 * both a 'snapshot' of the service's state and a set of records 2123 * detailing each significant change that has occurred to the state 2124 * since the snapshot was taken. The snapshot information and the 2125 * incremental change information will be stored in separate files 2126 * called, respectively, the snapshot file and the log file. Together, 2127 * these files are used to recover the state of the service after a 2128 * crash or a network outage (or if the service or its ActivationGroup 2129 * is un-registered and then re-registered through the Activation Daemon). 2130 * <p> 2131 * This class contains the methods that are used to record and recover 2132 * the snapshot of the service's state; as well as the method used to 2133 * apply the state changes that were recorded in the log file. 2134 * <p> 2135 * When the ReliableLog class is instantiated, a new instance of this 2136 * class is passed to its constructor so that the methods of this 2137 * class may be invoked by the methods defined in the ReliableLog. 2138 * Because this class extends the LogHandler class associated with 2139 * the ReliableLog class, this class must provide implementations of 2140 * the abstract methods declared in the LogHandler. Also, some of the 2141 * methods defined in this class override the methods of the LogHandler 2142 * in order to customize the handling of snapshot creation and 2143 * retrieval. 2144 * <p> 2145 * Each significant change to the service's state is written to the 2146 * log file as an individual record (when addLogRecord() is invoked). 2147 * After the number of records logged exceeds a pre-defined threshold, 2148 * a snapshot of the state is recorded by invoking -- through the 2149 * ReliableLog and its LogHandler -- the snapshot() method defined in 2150 * this class. After the snapshot is taken, the log file is cleared 2151 * and the incremental log process starts over. 2152 * <p> 2153 * The contents of the snapshot file reflect the DATA contained in 2154 * the fields making up the current state of the service. That data 2155 * represents many changes -- over time -- to the service's state. 2156 * On the other hand, each record written to the log file is an object 2157 * that reflects both the data used and the ACTIONS taken to make one 2158 * change to the service's state at a particular point in time. 2159 * <p> 2160 * During recovery, the state of the service at the time of a crash 2161 * or outage is re-constructed by first retrieving the 'base' state from 2162 * the snapshot file; and then modifying that base state according to 2163 * the records retrieved from the log file. The reconstruction of the 2164 * base state is achieved by invoking the recover() method defined in 2165 * this class. The modifications recorded in the log file are then 2166 * applied to the base state by invoking the applyUpdate() method 2167 * defined in this class. Both recover() and applyUpdate() are invoked 2168 * through the ReliableLog and its associated LogHandler. 2169 * <p> 2170 * NOTE: The following lines must be added to the service's policy file 2171 * <pre> 2172 * permission java.io.FilePermission "dirname", "read,write,delete"; 2173 * permission java.io.FilePermission "dirname/-", "read,write,delete"; 2174 * </pre> 2175 * where 'dirname' is the name of the directory path (relative or 2176 * absolute) where the snapshot and log file will be maintained. 2177 */ 2178 static class LocalLogHandler extends LogHandler { 2179 private FiddlerImpl fiddler; 2180 /** No-arg public constructor */ 2181 public LocalLogHandler() { } 2182 2183 synchronized void setFiddler(FiddlerImpl fiddler){ 2184 this.fiddler = fiddler; 2185 } 2186 2187 /* Overrides snapshot() defined in ReliableLog's LogHandler class. */ 2188 public synchronized void snapshot(OutputStream out) throws IOException { 2189 fiddler.takeSnapshot(out); 2190 }//end snapshot 2191 2192 /* Overrides recover() defined in ReliableLog's LogHandler class. */ 2193 public synchronized void recover(InputStream in) 2194 throws IOException, ClassNotFoundException 2195 { 2196 fiddler.recoverSnapshot(in); 2197 }//end recover 2198 2199 /** 2200 * Required method that implements the abstract applyUpdate() 2201 * defined in ReliableLog's associated LogHandler class. 2202 * <p> 2203 * During state recovery, the recover() method defined in the 2204 * ReliableLog class is invoked. That method invokes the method 2205 * recoverUpdates() which invokes the method readUpdates(). Both 2206 * of those methods are defined in ReliableLog. The method 2207 * readUpdates() retrieves a record from the log file and then 2208 * invokes this method. 2209 * <p> 2210 * This method invokes the version of the method apply() that 2211 * corresponds to the particular type of 'log record' object 2212 * that is input as the first argument. The log record object and its 2213 * corresponding apply() method are defined in one of the so-called 2214 * LogObj classes. Any instance of one the LogObj classes is an 2215 * implementation of the LogRecord interface. The particular 2216 * implementation that is input to this method is dependent on the 2217 * type of record that was originally logged. The apply() method 2218 * will then modify the state of the service in a way dictated 2219 * by the type of record that was retrieved. 2220 */ 2221 public synchronized void applyUpdate(Object logRecObj) { 2222 ((LogRecord)logRecObj).apply(fiddler); 2223 }//end applyUpdate 2224 }//end class LocalLogHandler 2225 /* ******************* END Inner Class Definitions ********************* */ 2226 2227 /* ******************* BEGIN Thread Class Definitions ****************** */ 2228 /** Thread which is used to monitor the current leases in effect and 2229 * cancel (expire) those leases with expiration times that have exceeded 2230 * the current time. 2231 */ 2232 static class LeaseExpireThread extends InterruptedStatusThread { 2233 2234 private final FiddlerImpl fiddler; 2235 2236 public LeaseExpireThread(FiddlerImpl fiddler) { 2237 super("lease expire"); 2238 setDaemon(false); 2239 this.fiddler = fiddler; 2240 }//end constructor 2241 2242 public void run() { 2243 try { 2244 fiddler.concurrentObj.writeLock(); 2245 } catch (ConcurrentLockException e) { 2246 return; 2247 } 2248 try { 2249 while (!hasBeenInterrupted()) { 2250 long curTime = System.currentTimeMillis(); 2251 fiddler.minExpiration = Long.MAX_VALUE; 2252 /* Loop through registrationByTime removing registrations 2253 * with expiration times that are earlier than the current 2254 * time. The logic of this loop relies on the fact that 2255 * registrationByTime is a TreeMap in which the elements 2256 * are ordered (in ascending order) by the lease expiration 2257 * times. Thus, when one registration is encountered with 2258 * an expiration time that is later than the current time, 2259 * it can be assumed that all remaining registrations have 2260 * expiration times that are also later than the current 2261 * time; and the loop can be exited. Until such a 2262 * registration is encountered, each registration is 2263 * removed from its various storage locations. 2264 */ 2265 while (!fiddler.registrationByTime.isEmpty()) { 2266 RegistrationInfo regInfo 2267 = (RegistrationInfo)fiddler.registrationByTime.firstKey(); 2268 if (regInfo.leaseExpiration > curTime) { 2269 fiddler.minExpiration = regInfo.leaseExpiration; 2270 break; 2271 } 2272 /* The removal of a registration typically involves the 2273 * the modification of the managed sets in the 2274 * discovery manager, which usually involves starting 2275 * the discovery protocol. An IOException can occur 2276 * when the discovery protocol fails to start. When 2277 * such an exception does occur, register an ERROR 2278 * status attribute (along with a Comment attribute 2279 * describing the nature of the problem) to all lookup 2280 * services with which this service is registered. 2281 * 2282 * Administrative clients, as well as clients that use 2283 * this service should have registered for notification 2284 * of the existence of this attribute. 2285 */ 2286 try { 2287 fiddler.removeRegistration(regInfo); 2288 } catch(IOException e) { 2289 String eStr = "Failure while removing " 2290 +"registration (ID = " 2291 +regInfo.registrationID 2292 +") from service state"; 2293 if( problemLogger.isLoggable(Level.INFO) ) { 2294 problemLogger.log(Level.INFO, eStr, e); 2295 }//endif 2296 Entry[] errorAttrs 2297 = new Entry[] 2298 { new FiddlerStatus(StatusType.ERROR), 2299 new Comment(eStr) 2300 }; 2301 fiddler.joinMgr.addAttributes(errorAttrs,true); 2302 } 2303 }//end while 2304 try { 2305 fiddler.leaseExpireThreadSyncObj.await( 2306 fiddler.minExpiration - curTime, 2307 TimeUnit.MILLISECONDS); 2308 } catch (InterruptedException ex) { 2309 Thread.currentThread().interrupt();// restore 2310 return; 2311 } 2312 }//end while 2313 } finally { 2314 fiddler.concurrentObj.writeUnlock(); 2315 } 2316 }//end run 2317 }//end class LeaseExpireThread 2318 2319 /** 2320 * Snapshot-taking thread. 2321 * <p> 2322 * A snapshot is taken when -- after writing a new record to the 2323 * log file -- it is determined that the size of the log file has 2324 * exceeded a certain threshold. The code which adds the new record 2325 * to the log file and which, in turn, decides that a snapshot 2326 * must be taken is "wrapped" in a writer mutex. That is, synchronization 2327 * of processing is achieved in this service through a "reader/writer" 2328 * mutex construct. This construct allows only one writer at any one 2329 * time; but allows an unlimited number of simultaneous readers as 2330 * long as no writer has locked the mutex. During steady-state, it is 2331 * anticipated that far more "read actions" will occur (e.g. discovery 2332 * events being sent) than "write actions" (e.g. modifying the managed 2333 * sets). Since the process of taking a snapshot can be time-consuming, 2334 * if the whole snapshot-taking process occupies that single writer 2335 * mutex, then a significant number of read actions will be un-necessarily 2336 * blocked; possibly resulting in an unacceptable degradation in 2337 * response time. 2338 * <p> 2339 * It is for the above reason that the process of taking a snapshot is 2340 * performed in a separate thread. The thread waits on the monitor 2341 * belonging to the snapshotThreadSyncObj instance until it is notified 2342 * (or "signalled") that a snapshot must be taken. The notification 2343 * is sent by another thread, created by this service, which determines 2344 * when the conditions are right for a snapshot. The notification takes 2345 * the form of an interrupt indicating that the snapshot monitor is 2346 * available. Although the interrupt is sent while the writer mutex is 2347 * locked, the act of sending the notification is less time-consuming 2348 * than the act of taking the snapshot itself. When the thread receives 2349 * a notification, it awakens and requests a lock on the reader mutex 2350 * (this is all done in the readerWait() method). Because a reader -- not 2351 * a writer -- mutex is locked, read-only processes still have access 2352 * to the system state, so discovery events can be sent and the service's 2353 * state can be queried; but the reader mutex prevents changes to the 2354 * state while the snapshot is in progress. 2355 * <p> 2356 * Note that the current snapshot is guaranteed to complete before the 2357 * next snapshot request is received. This is because even though 2358 * the act of taking a snapshot can be viewed as a writer process, 2359 * the fact that the next snapshot notification will be wrapped in a 2360 * writer mutex, combined with the fact that a writer mutex can not 2361 * be locked while a reader mutex is locked, allows the snapshot to 2362 * be treated as a reader process. 2363 */ 2364 static class SnapshotThread extends InterruptedStatusThread { 2365 private final FiddlerImpl fiddler; 2366 2367 /** Not a daemon thread, to avoid termination by jvm during snapshot */ 2368 public SnapshotThread(FiddlerImpl fiddler) { 2369 super("snapshot thread"); 2370 setDaemon(false); 2371 this.fiddler = fiddler; 2372 } 2373 2374 public void run() { 2375 try { 2376 fiddler.concurrentObj.writeLock(); 2377 } catch (ConcurrentLockException e) { 2378 return; 2379 } 2380 try { 2381 while (!hasBeenInterrupted()) { 2382 try { 2383 fiddler.snapshotThreadSyncObj.await(); 2384 } catch (InterruptedException ex) { 2385 Thread.currentThread().interrupt();// restore 2386 return; 2387 } 2388 try { 2389 fiddler.log.snapshot(); 2390 fiddler.logFileSize = 0; 2391 } catch (Exception e) { 2392 if (hasBeenInterrupted()) return; 2393 /* If taking the snapshot fails for any reason, 2394 * then register an ERROR status attribute (along 2395 * with a Comment attribute describing the nature 2396 * of the problem) to all lookup services with 2397 * which this service is registered. 2398 * 2399 * Administrative clients, as well as clients that 2400 * use this service should have registered for 2401 * notification of the existence of this attribute. 2402 */ 2403 String eStr = "Failure while taking a snapshot of " 2404 +"the service state"; 2405 problemLogger.log(Level.INFO, eStr, e); 2406 Entry[] errorAttrs 2407 = new Entry[] 2408 { new FiddlerStatus(StatusType.ERROR), 2409 new Comment(eStr) 2410 }; 2411 fiddler.joinMgr.addAttributes(errorAttrs,true); 2412 } 2413 }//end while 2414 } finally { 2415 fiddler.concurrentObj.writeUnlock(); 2416 } 2417 }//end run 2418 }//end class SnapshotThread 2419 2420 /** Thread which is used to terminate the current executing instance 2421 * of the Fiddler implementation of the lookup discovery service. 2422 * Termination processing is performed in a separate thread (that is, 2423 * in an instance of this class) in order to avoid deadlock that 2424 * can occur because ActivationGroup.inactive will block until all 2425 * in-progress RMI calls have completed. 2426 */ 2427 private class DestroyThread extends InterruptedStatusThread { 2428 /** Maximum delay for unexport attempts */ 2429 private static final long MAX_UNEXPORT_DELAY = 2*TimeConstants.MINUTES; 2430 2431 /** Constructor that creates a non-daemon thread */ 2432 public DestroyThread() { 2433 super("destroy"); 2434 /* override inheritance from RMI daemon thread */ 2435 setDaemon(false); 2436 } 2437 2438 public void run() { 2439 /* Must unregister before unexporting. Unregistering makes sure 2440 * that the object corresponding to the given activation ID can 2441 * no longer be activated through that ID. 2442 */ 2443 if (activationID != null) { 2444 try { 2445 activationSystem.unregisterObject(activationID); 2446 } catch (RemoteException e) { 2447 problemLogger.log(Level.WARNING, "aborting shutdown - " 2448 +"could not unregister activation ID", e); 2449 return;//give up until we can at least unregister 2450 } catch (ActivationException e) { 2451 problemLogger.log(Levels.HANDLED, "shutdown problem - " 2452 +"could not unregister activation ID", e); 2453 } 2454 } 2455 readyState.shutdown(); 2456 /* Unexport the object. This removes the object from the RMI 2457 * runtime so that the object can no longer accept incoming RMI 2458 * calls. 2459 * 2460 * An attempt to 'gracefully' unexport the object is initially 2461 * made. That is, for a finite period of time, an attempt is 2462 * made to allow all calls to the object that are in progress 2463 * or pending to complete before the object is unexported. If, 2464 * after that finite period of time, the object has not been 2465 * successfully unexported, the object is 'forcibly' unexported; 2466 * that is, the object is unexported even if there are calls to 2467 * the object that are in progress or still pending. 2468 */ 2469 final long endTime = System.currentTimeMillis()+MAX_UNEXPORT_DELAY; 2470 boolean unexported = false; 2471 boolean interrupted = false; 2472 /* Unexport only if there are no pending or in-progress calls*/ 2473 while(!unexported && (System.currentTimeMillis() < endTime)) { 2474 unexported = serverExporter.unexport(false); 2475 if(!unexported) try { 2476 Thread.sleep(500L); 2477 } catch (InterruptedException ex) { 2478 interrupted = true; 2479 continue; 2480 } 2481 }//end loop 2482 // Restore the interrupt. 2483 if (interrupted) Thread.currentThread().interrupt(); 2484 if(!unexported) {//Not yet unexported. Forcibly unexport 2485 serverExporter.unexport(true); 2486 }//endif 2487 /* all daemons must terminate before deleting persistent store */ 2488 leaseExpireThread.interrupt(); 2489 if(log != null) snapshotThread.interrupt(); 2490 executorService.shutdown(); 2491 joinMgr.terminate(); 2492 joinMgrLDM.terminate(); 2493 discoveryMgr.terminate(); 2494 try { 2495 leaseExpireThread.join(); 2496 if(log != null) snapshotThread.join(); 2497 } catch (InterruptedException e) { 2498 // Should the interrupt really be swallowed? Or should we reset 2499 // the status for later handling? 2500 Thread.currentThread().interrupt(); 2501 } 2502 if(log != null) log.deletePersistentStore(); 2503 if (activationID != null) { 2504 /* Inform the activation system that the object corresponding 2505 * to the given activation ID is no longer active. 2506 */ 2507 try { 2508 ActivationGroup.inactive(activationID, serverExporter); 2509 } catch (RemoteException e) { 2510 } catch (ActivationException e) { } 2511 } else {//not activatable, tell starter it's ok to release for gc 2512 if(lifeCycle != null) lifeCycle.unregister(FiddlerImpl.this); 2513 }//endif(activationID != null) 2514 /* If applicable, logout of the JAAS login session */ 2515 if(loginContext != null) { 2516 try { 2517 loginContext.logout(); 2518 } catch(Exception e) { 2519 startupLogger.log(Level.INFO,"Problem logging out of " 2520 +"JAAS login session",e); 2521 } 2522 }//endif 2523 logInfoShutdown(); 2524 }//end run 2525 }//end class DestroyThread 2526 /* ******************* END Thread Class Definitions ******************** */ 2527 2528 /* ************************ BEGIN Public Methods *********************** */ 2529 /* -------------------------------------------------------------------- 2530 * BEGIN net.jini.security.proxytrust.ServerProxyTrust 2531 */ 2532 /** 2533 * Returns a <code>TrustVerifier</code> specific to this service which 2534 * can be used to verify that a given proxy to this service can be 2535 * trusted. 2536 * <p> 2537 * The verifier returned by this method contains the method 2538 * {@link TrustVerifier#isTrustedObject isTrustedObject}. That method 2539 * can be called with a candidate proxy as the first argument, and 2540 * {@link net.jini.security.TrustVerifier.Context} 2541 * as the second argument. When called in this way, the 2542 * <code>isTrustedObject</code> determines whether or not the input 2543 * proxy is trusted. Thus, the verifier returned by this method should 2544 * be able to verify as trusted, all proxies to this service; including 2545 * proxies such as leases, event registrations, and administrative 2546 * proxies. 2547 * 2548 * @return a <code>TrustVerifier</code> which can be used to verify that 2549 * a given proxy to this service can be trusted. 2550 * 2551 * @throws java.rmi.NoSuchObjectException if this method is called during 2552 * service initialization or shutdown processing 2553 * 2554 * @throws UnsupportedOperationException if the server proxy does not 2555 * implement both 2556 * {@link net.jini.core.constraint.RemoteMethodControl} 2557 * and {@link TrustEquivalence} 2558 * 2559 * @see net.jini.security.proxytrust.ServerProxyTrust#getProxyVerifier 2560 */ 2561 public TrustVerifier getProxyVerifier() throws NoSuchObjectException { 2562 readyState.check(); 2563 return new ProxyVerifier(innerProxy, proxyID); 2564 }//end getProxyVerifier 2565 /* END net.jini.security.proxytrust.ServerProxyTrust */ 2566 /* -------------------------------------------------------------------- */ 2567 2568 /* -------------------------------------------------------------------- 2569 * BEGIN net.jini.export.ProxyAccessor 2570 */ 2571 /** 2572 * Public method that facilitates the use of the mechanism provided by 2573 * {@link org.apache.river.start.ServiceStarter} to create an activatable 2574 * instance of this server. 2575 * 2576 * @return the inner proxy (stub or dynamic proxy) for the server 2577 */ 2578 public Object getProxy() { 2579 return innerProxy; 2580 }//end getProxy 2581 /* END net.jini.export.ProxyAccessor */ 2582 /* -------------------------------------------------------------------- */ 2583 2584 /* -------------------------------------------------------------------- 2585 * BEGIN org.apache.river.fiddler.proxy.Fiddler --> net.jini.admin.Administrable 2586 */ 2587 /** 2588 * Returns a proxy to the current instance of this class through which 2589 * a client may administer the lookup discovery service 2590 * 2591 * @return a proxy object through which the lookup discovery service 2592 * may be administered. 2593 * 2594 * @throws java.rmi.NoSuchObjectException if this method is called during 2595 * service initialization or shutdown processing 2596 * 2597 * @throws java.rmi.RemoteException typically, this exception occurs when 2598 * there is a communication failure between the client and the 2599 * server. 2600 * 2601 * see org.apache.river.fiddler.proxy.FiddlerAdminProxy#getAdmin (?) 2602 * @see net.jini.admin.Administrable#getAdmin 2603 */ 2604 public Object getAdmin() throws NoSuchObjectException, RemoteException { 2605 readyState.check(); 2606 concurrentObj.readLock(); 2607 try { 2608 return adminProxy; 2609 } finally { 2610 concurrentObj.readUnlock(); 2611 } 2612 } 2613 /* END org.apache.river.fiddler.proxy.Fiddler --> net.jini.admin.Administrable */ 2614 /* -------------------------------------------------------------------- */ 2615 2616 /* -------------------------------------------------------------------- 2617 * BEGIN org.apache.river.fiddler.proxy.Fiddler 2618 * --> org.apache.river.fiddler.proxy.FiddlerAdmin 2619 * --> net.jini.admin.JoinAdmin 2620 */ 2621 /** 2622 * Returns the current attribute sets for the lookup discovery service. 2623 * 2624 * @return array of net.jini.core.entry.Entry containing the current 2625 * attribute sets for the lookup discovery service 2626 * 2627 * @throws java.rmi.NoSuchObjectException if this method is called during 2628 * service initialization or shutdown processing 2629 * 2630 * @throws java.rmi.RemoteException typically, this exception occurs when 2631 * there is a communication failure between the client and the 2632 * lookup discovery service. 2633 * 2634 * @see org.apache.river.fiddler.proxy.FiddlerAdminProxy#getLookupAttributes 2635 * @see net.jini.admin.JoinAdmin#getLookupAttributes 2636 */ 2637 public Entry[] getLookupAttributes() 2638 throws NoSuchObjectException, RemoteException 2639 { 2640 readyState.check(); 2641 concurrentObj.readLock(); 2642 try { 2643 return thisServicesAttrs; 2644 } finally { 2645 concurrentObj.readUnlock(); 2646 } 2647 }//end getLookupAttributes 2648 2649 /** 2650 * Adds attribute sets to the current set of attributes associated 2651 * with the lookup discovery service. The resulting set will be used 2652 * for all future registrations with lookup services. The new attribute 2653 * sets are also added to the lookup discovery service's attributes 2654 * on each lookup service with which the lookup discovery service 2655 * is currently registered. 2656 * 2657 * @param attrSets array of net.jini.core.entry.Entry containing the 2658 * attribute sets to add 2659 * 2660 * @throws java.rmi.NoSuchObjectException if this method is called during 2661 * service initialization or shutdown processing 2662 * 2663 * @throws java.rmi.RemoteException typically, this exception occurs when 2664 * there is a communication failure between the client and the 2665 * lookup discovery service. When this exception does occur, the 2666 * attributes may or may not have been added successfully. 2667 * 2668 * @see org.apache.river.fiddler.proxy.FiddlerAdminProxy#addLookupAttributes 2669 * @see net.jini.admin.JoinAdmin#addLookupAttributes 2670 */ 2671 public void addLookupAttributes(Entry[] attrSets) 2672 throws NoSuchObjectException, RemoteException 2673 { 2674 readyState.check(); 2675 concurrentObj.writeLock(); 2676 try { 2677 joinMgr.addAttributes(attrSets, true); 2678 thisServicesAttrs = joinMgr.getAttributes(); 2679 addLogRecord(new LookupAttrsAddedLogObj(this,attrSets)); 2680 } finally { 2681 concurrentObj.writeUnlock(); 2682 } 2683 }//end addLookupAttributes 2684 2685 /** 2686 * Modifies the current set of attributes associated with the lookup 2687 * discovery service. The resulting set will be used for all future 2688 * registrations with lookup services. The same modifications are 2689 * also made to the lookup discovery service's attributes on each 2690 * lookup service with which the lookup discovery service is currently 2691 * registered. 2692 * 2693 * @param attrSetTemplates array of net.jini.core.entry.Entry containing 2694 * the templates to use for selecting the attributes (contained 2695 * within the set of existing attributes) that are to be 2696 * modified 2697 * @param attrSets array of net.jini.core.entry.Entry containing the 2698 * modifications to make to matching sets 2699 * 2700 * @throws java.rmi.NoSuchObjectException if this method is called during 2701 * service initialization or shutdown processing 2702 * 2703 * @throws java.rmi.RemoteException typically, this exception occurs when 2704 * there is a communication failure between the client and the 2705 * lookup discovery service. When this exception does occur, the 2706 * attributes may or may not have been modified successfully. 2707 * 2708 * @see org.apache.river.fiddler.proxy.FiddlerAdminProxy#modifyLookupAttributes 2709 * @see net.jini.admin.JoinAdmin#modifyLookupAttributes 2710 */ 2711 public void modifyLookupAttributes(Entry[] attrSetTemplates, 2712 Entry[] attrSets) 2713 throws NoSuchObjectException, RemoteException 2714 { 2715 readyState.check(); 2716 concurrentObj.writeLock(); 2717 try { 2718 joinMgr.modifyAttributes(attrSetTemplates, attrSets, true); 2719 thisServicesAttrs = joinMgr.getAttributes(); 2720 addLogRecord 2721 (new LookupAttrsModifiedLogObj(this,attrSetTemplates,attrSets)); 2722 } finally { 2723 concurrentObj.writeUnlock(); 2724 } 2725 }//end modifyLookupAttributes 2726 2727 /** 2728 * Get the names of the groups whose members are lookup services the 2729 * lookup discovery services wishes to register with (join). 2730 * 2731 * @return String array containing the names of the groups whose members 2732 * are lookup services the lookup discovery service wishes to 2733 * join. 2734 * <p> 2735 * If the array returned is empty, the lookup discovery service 2736 * is configured to join no groups. If null is returned, the 2737 * lookup discovery service is configured to join all groups. 2738 * 2739 * @throws java.rmi.NoSuchObjectException if this method is called during 2740 * service initialization or shutdown processing 2741 * 2742 * @throws java.rmi.RemoteException typically, this exception occurs when 2743 * there is a communication failure between the client and the 2744 * lookup discovery service. 2745 * 2746 * @see org.apache.river.fiddler.proxy.FiddlerAdminProxy#getLookupGroups 2747 * @see net.jini.admin.JoinAdmin#getLookupGroups 2748 */ 2749 public String[] getLookupGroups() 2750 throws NoSuchObjectException, RemoteException 2751 { 2752 readyState.check(); 2753 concurrentObj.readLock(); 2754 try { 2755 return thisServicesGroups; 2756 } finally { 2757 concurrentObj.readUnlock(); 2758 } 2759 }//end getLookupGroups 2760 2761 /** 2762 * Add new names to the set consisting of the names of groups whose 2763 * members are lookup services the lookup discovery service wishes 2764 * to register with (join). Any lookup services belonging to the 2765 * new groups that the lookup discovery service has not yet registered 2766 * with, will be discovered and joined. 2767 * 2768 * @param groups String array containing the names of the groups to add 2769 * 2770 * @throws java.rmi.NoSuchObjectException if this method is called during 2771 * service initialization or shutdown processing 2772 * 2773 * @throws java.rmi.RemoteException typically, this exception occurs when 2774 * there is a communication failure between the client and the 2775 * lookup discovery service. When this exception does occur, the 2776 * group names may or may not have been added successfully. 2777 * 2778 * @see org.apache.river.fiddler.proxy.FiddlerAdminProxy#addLookupGroups 2779 * @see net.jini.admin.JoinAdmin#addLookupGroups 2780 */ 2781 public void addLookupGroups(String[] groups) 2782 throws NoSuchObjectException, RemoteException 2783 { 2784 readyState.check(); 2785 concurrentObj.writeLock(); 2786 try { 2787 try { 2788 ((DiscoveryGroupManagement)joinMgrLDM).addGroups(groups); 2789 } catch (IOException e) { 2790 throw new RuntimeException(e.toString()); 2791 } 2792 thisServicesGroups 2793 = ((DiscoveryGroupManagement)joinMgrLDM).getGroups(); 2794 addLogRecord(new LookupGroupsChangedLogObj(thisServicesGroups)); 2795 } finally { 2796 concurrentObj.writeUnlock(); 2797 } 2798 }//end addLookupGroups 2799 2800 /** 2801 * Remove a set of group names from lookup discovery service's managed 2802 * set of groups (the set consisting of the names of groups whose 2803 * members are lookup services the lookup discovery service wishes 2804 * to join). Any leases granted to the lookup discovery service by 2805 * lookup services that are not members of the groups whose names 2806 * remain in the managed set will be cancelled at those lookup services. 2807 * 2808 * @param groups String array containing the names of the groups to remove 2809 * 2810 * @throws java.rmi.NoSuchObjectException if this method is called during 2811 * service initialization or shutdown processing 2812 * 2813 * @throws java.rmi.RemoteException typically, this exception occurs when 2814 * there is a communication failure between the client and the 2815 * lookup discovery service. When this exception does occur, the 2816 * group names may or may not have been removed successfully. 2817 * 2818 * @see org.apache.river.fiddler.proxy.FiddlerAdminProxy#removeLookupGroups 2819 * @see net.jini.admin.JoinAdmin#removeLookupGroups 2820 */ 2821 public void removeLookupGroups(String[] groups) 2822 throws NoSuchObjectException, RemoteException 2823 { 2824 readyState.check(); 2825 concurrentObj.writeLock(); 2826 try { 2827 ((DiscoveryGroupManagement)joinMgrLDM).removeGroups(groups); 2828 thisServicesGroups 2829 = ((DiscoveryGroupManagement)joinMgrLDM).getGroups(); 2830 addLogRecord(new LookupGroupsChangedLogObj(thisServicesGroups)); 2831 } finally { 2832 concurrentObj.writeUnlock(); 2833 } 2834 }//end removeLookupGroups 2835 2836 /** 2837 * Replace the lookup discovery service's managed set of groups with a 2838 * new set of group names. Any leases granted to the lookup discovery 2839 * service by lookup services that are not members of the groups whose 2840 * names are in the new managed set will be cancelled at those lookup 2841 * services. Lookup services that are members of groups reflected in 2842 * the new managed set will be discovered and joined. 2843 * 2844 * @param groups String array containing the names of the new groups 2845 * 2846 * @throws java.rmi.NoSuchObjectException if this method is called during 2847 * service initialization or shutdown processing 2848 * 2849 * @throws java.rmi.RemoteException typically, this exception occurs when 2850 * there is a communication failure between the client and the 2851 * lookup discovery service. When this exception does occur, the 2852 * group names may or may not have been replaced successfully. 2853 * 2854 * @see org.apache.river.fiddler.proxy.FiddlerAdminProxy#setLookupGroups 2855 * @see net.jini.admin.JoinAdmin#setLookupGroups 2856 */ 2857 public void setLookupGroups(String[] groups) 2858 throws NoSuchObjectException, RemoteException 2859 { 2860 readyState.check(); 2861 concurrentObj.writeLock(); 2862 try { 2863 try { 2864 ((DiscoveryGroupManagement)joinMgrLDM).setGroups(groups); 2865 } catch (IOException e) { 2866 throw new RuntimeException(e.toString()); 2867 } 2868 thisServicesGroups 2869 = ((DiscoveryGroupManagement)joinMgrLDM).getGroups(); 2870 addLogRecord(new LookupGroupsChangedLogObj(thisServicesGroups)); 2871 } finally { 2872 concurrentObj.writeUnlock(); 2873 } 2874 }//end setLookupGroups 2875 2876 /** 2877 * Get the lookup discovery service's managed set of locators. The 2878 * managed set of locators is the set of LookupLocator objects 2879 * corresponding to the specific lookup services with which the lookup 2880 * discovery service wishes to register (join). 2881 * 2882 * @return array of objects of type net.jini.core.discovery.LookupLocator, 2883 * each of which corresponds to a specific lookup service the 2884 * lookup discovery service wishes to join. 2885 * 2886 * @throws java.rmi.NoSuchObjectException if this method is called during 2887 * service initialization or shutdown processing 2888 * 2889 * @throws java.rmi.RemoteException typically, this exception occurs when 2890 * there is a communication failure between the client and the 2891 * lookup discovery service. 2892 * 2893 * @see org.apache.river.fiddler.proxy.FiddlerAdminProxy#getLookupLocators 2894 * @see net.jini.admin.JoinAdmin#getLookupLocators 2895 */ 2896 public LookupLocator[] getLookupLocators() 2897 throws NoSuchObjectException, RemoteException 2898 { 2899 readyState.check(); 2900 concurrentObj.readLock(); 2901 try { 2902 return thisServicesLocators; 2903 } finally { 2904 concurrentObj.readUnlock(); 2905 } 2906 }//end getLookupLocators 2907 2908 /** 2909 * Add a set of LookupLocator objects to the lookup discovery service's 2910 * managed set of locators. The managed set of locators is the set of 2911 * LookupLocator objects corresponding to the specific lookup services 2912 * with which the lookup discovery service wishes to register (join). 2913 * <p> 2914 * Any lookup services corresponding to the new locators that the lookup 2915 * discovery service has not yet joined, will be discovered and joined. 2916 * 2917 * @param locators array of net.jini.core.discovery.LookupLocator objects to add 2918 * to the managed set of locators 2919 * 2920 * @throws java.rmi.NoSuchObjectException if this method is called during 2921 * service initialization or shutdown processing 2922 * 2923 * @throws java.rmi.RemoteException typically, this exception occurs when 2924 * there is a communication failure between the client and the 2925 * lookup discovery service. When this exception does occur, the 2926 * new locators may or may not have been added successfully. 2927 * 2928 * @see org.apache.river.fiddler.proxy.FiddlerAdminProxy#addLookupLocators 2929 * @see net.jini.admin.JoinAdmin#addLookupLocators 2930 */ 2931 public void addLookupLocators(LookupLocator[] locators) 2932 throws NoSuchObjectException, RemoteException 2933 { 2934 readyState.check(); 2935 /* Prepare outside of sync block because of possible remote call */ 2936 prepareNewLocators(locatorToJoinPreparer,locators); 2937 concurrentObj.writeLock(); 2938 try { 2939 ((DiscoveryLocatorManagement)joinMgrLDM).addLocators(locators); 2940 thisServicesLocators 2941 = ((DiscoveryLocatorManagement)joinMgrLDM).getLocators(); 2942 addLogRecord 2943 (new LookupLocatorsChangedLogObj(thisServicesLocators)); 2944 } finally { 2945 concurrentObj.writeUnlock(); 2946 } 2947 }//end addLookupLocators 2948 2949 /** 2950 * Remove a set of LookupLocator objects from the lookup discovery 2951 * service's managed set of locators. The managed set of locators is the 2952 * set of LookupLocator objects corresponding to the specific lookup 2953 * services with which the lookup discovery service wishes to register 2954 * (join). 2955 * <p> 2956 * Note that any leases granted to the lookup discovery service by 2957 * lookup services that do not correspond to any of the locators 2958 * remaining in the managed set will be cancelled at those lookup 2959 * services. 2960 * 2961 * @param locators array of net.jini.core.discovery.LookupLocator objects to 2962 * remove from the managed set of locators 2963 * 2964 * @throws java.rmi.NoSuchObjectException if this method is called during 2965 * service initialization or shutdown processing 2966 * 2967 * @throws java.rmi.RemoteException typically, this exception occurs when 2968 * there is a communication failure between the client and the 2969 * lookup discovery service. When this exception does occur, the 2970 * new locators may or may not have been removed successfully. 2971 * 2972 * @see org.apache.river.fiddler.proxy.FiddlerAdminProxy#removeLookupLocators 2973 * @see net.jini.admin.JoinAdmin#removeLookupLocators 2974 */ 2975 public void removeLookupLocators(LookupLocator[] locators) 2976 throws NoSuchObjectException, RemoteException 2977 { 2978 readyState.check(); 2979 /* Prepare outside of sync block because of possible remote call */ 2980 prepareNewLocators(locatorToJoinPreparer,locators); 2981 concurrentObj.writeLock(); 2982 try { 2983 ((DiscoveryLocatorManagement)joinMgrLDM).removeLocators(locators); 2984 thisServicesLocators 2985 = ((DiscoveryLocatorManagement)joinMgrLDM).getLocators(); 2986 addLogRecord 2987 (new LookupLocatorsChangedLogObj(thisServicesLocators)); 2988 } finally { 2989 concurrentObj.writeUnlock(); 2990 } 2991 }//end removeLookupLocators 2992 2993 /** 2994 * Replace the lookup discovery service's managed set of locators with 2995 * a new set of locators. The managed set of locators is the set of 2996 * LookupLocator objects corresponding to the specific lookup services 2997 * with which the lookup discovery service wishes to register (join). 2998 * <p> 2999 * Note that any leases granted to the lookup discovery service by 3000 * lookup services whose corresponding locator is removed from the 3001 * managed set will be cancelled at those lookup services. The lookup 3002 * services corresponding to the new locators in the managed set 3003 * will be discovered and joined. 3004 * 3005 * @param locators array of net.jini.core.discovery.LookupLocator objects with 3006 * which to replace the current managed set of locators 3007 * remove from the managed set of locators 3008 * 3009 * @throws java.rmi.NoSuchObjectException if this method is called during 3010 * service initialization or shutdown processing 3011 * 3012 * @throws java.rmi.RemoteException typically, this exception occurs when 3013 * there is a communication failure between the client and the 3014 * lookup discovery service. When this exception does occur, the 3015 * locators in the managed set may or may not have been replaced 3016 * successfully. 3017 * 3018 * @see org.apache.river.fiddler.proxy.FiddlerAdminProxy#setLookupLocators 3019 * @see net.jini.admin.JoinAdmin#setLookupLocators 3020 */ 3021 public void setLookupLocators(LookupLocator[] locators) 3022 throws NoSuchObjectException, RemoteException 3023 { 3024 readyState.check(); 3025 /* Prepare outside of sync block because of possible remote call */ 3026 prepareNewLocators(locatorToJoinPreparer,locators); 3027 concurrentObj.writeLock(); 3028 try { 3029 ((DiscoveryLocatorManagement)joinMgrLDM).setLocators(locators); 3030 thisServicesLocators 3031 = ((DiscoveryLocatorManagement)joinMgrLDM).getLocators(); 3032 addLogRecord 3033 (new LookupLocatorsChangedLogObj(thisServicesLocators)); 3034 } finally { 3035 concurrentObj.writeUnlock(); 3036 } 3037 }//end setLookupLocators 3038 /* END org.apache.river.fiddler.proxy.Fiddler --> org.apache.river.fiddler.proxy.FiddlerAdmin 3039 * --> net.jini.admin.JoinAdmin 3040 * -------------------------------------------------------------------- */ 3041 3042 /* -------------------------------------------------------------------- 3043 * BEGIN org.apache.river.fiddler.proxy.Fiddler 3044 * --> org.apache.river.fiddler.proxy.FiddlerAdmin 3045 * --> org.apache.river.admin.DestroyAdmin 3046 */ 3047 /** 3048 * Destroy the lookup discovery service, if possible, including its 3049 * persistent storage. This method will typically spawn a separate 3050 * thread to do the actual work asynchronously, so a successful 3051 * return from this method usually does not mean that the service 3052 * has been destroyed. 3053 * 3054 * @throws java.rmi.NoSuchObjectException if this method is called during 3055 * service initialization or shutdown processing 3056 * 3057 * @throws java.rmi.RemoteException typically, this exception occurs when 3058 * there is a communication failure between the client and the 3059 * lookup discovery service. When this exception does occur, the 3060 * lookup discovery service may or may not have been successfully 3061 * destroyed. 3062 * 3063 * @see org.apache.river.fiddler.proxy.FiddlerAdminProxy#destroy 3064 * @see org.apache.river.admin.DestroyAdmin#destroy 3065 */ 3066 public void destroy() throws NoSuchObjectException, RemoteException { 3067 readyState.check(); 3068 destroyDo(); 3069 }//end destroy 3070 /* END org.apache.river.fiddler.proxy.Fiddler 3071 * --> org.apache.river.fiddler.proxy.FiddlerAdmin 3072 * --> org.apache.river.admin.DestroyAdmin 3073 * -------------------------------------------------------------------- */ 3074 3075 /* -------------------------------------------------------------------- 3076 * BEGIN org.apache.river.fiddler.proxy.Fiddler 3077 * --> org.apache.river.fiddler.proxy.FiddlerAdmin 3078 */ 3079 /** 3080 * Changes the least upper bound applied to all lease durations granted 3081 * by the lookup discovery service. 3082 * <p> 3083 * This method is a mechanism for an entity with the appropriate 3084 * privileges to administratively change the value of the least upper 3085 * bound that will be applied by the Fiddler implementation of the lookup 3086 * discovery service when determining the duration to assign to the lease 3087 * on a requested registration. 3088 * 3089 * @param newBound <code>long</code> value representing the new least 3090 * upper bound (in milliseconds) on the set of all possible 3091 * lease durations that may be granted 3092 * 3093 * @throws java.rmi.NoSuchObjectException if this method is called during 3094 * service initialization or shutdown processing 3095 * 3096 * @throws java.rmi.RemoteException typically, this exception occurs when 3097 * there is a communication failure between the client and the 3098 * lookup discovery service. When this exception does occur, the 3099 * bound value may or may not have been changed successfully. 3100 * 3101 * @see org.apache.river.fiddler.proxy.FiddlerAdminProxy#setLeaseBound 3102 * @see org.apache.river.admin.FiddlerAdmin#setLeaseBound 3103 */ 3104 @Override 3105 public void setLeaseBound(long newBound) 3106 throws NoSuchObjectException, RemoteException 3107 { 3108 readyState.check(); 3109 concurrentObj.writeLock(); 3110 try { 3111 if (newBound > leaseMax) { 3112 throw new IllegalArgumentException("max duration exceeded"); 3113 }//endif 3114 leaseBound = newBound; 3115 addLogRecord(new LeaseBoundSetLogObj(newBound)); 3116 } finally { 3117 concurrentObj.writeUnlock(); 3118 } 3119 }//end setLeaseBound 3120 3121 /** 3122 * Retrieves the least upper bound applied to all lease durations granted 3123 * by the lookup discovery service. 3124 * 3125 * @return <code>long</code> value representing the current least 3126 * upper bound (in milliseconds) on the set of all possible 3127 * lease durations that may be granted 3128 * 3129 * @throws java.rmi.NoSuchObjectException if this method is called during 3130 * service initialization or shutdown processing 3131 * 3132 * @throws java.rmi.RemoteException typically, this exception occurs when 3133 * there is a communication failure between the client and the 3134 * lookup discovery service. 3135 * 3136 * @see org.apache.river.fiddler.proxy.FiddlerAdminProxy#getLeaseBound 3137 * @see org.apache.river.admin.FiddlerAdmin#getLeaseBound 3138 */ 3139 public long getLeaseBound() throws NoSuchObjectException, RemoteException { 3140 readyState.check(); 3141 concurrentObj.readLock(); 3142 try { 3143 return leaseBound; 3144 } finally { 3145 concurrentObj.readUnlock(); 3146 } 3147 }//end getLeaseBound 3148 3149 /** 3150 * Change the weight factor applied by the lookup discovery service 3151 * to the snapshot size during the test to determine whether or not 3152 * to take a "snapshot" of the system state. 3153 * 3154 * @param weight weight factor for snapshot size 3155 * 3156 * @throws java.rmi.NoSuchObjectException if this method is called during 3157 * service initialization or shutdown processing 3158 * 3159 * @throws java.rmi.RemoteException typically, this exception occurs when 3160 * there is a communication failure between the client and the 3161 * lookup discovery service. When this exception does occur, the 3162 * weight factor may or may not have been changed successfully. 3163 * 3164 * @see org.apache.river.fiddler.proxy.FiddlerAdminProxy#setPersistenceSnapshotWeight 3165 * @see org.apache.river.admin.FiddlerAdmin#setPersistenceSnapshotWeight 3166 */ 3167 public void setPersistenceSnapshotWeight(float weight) 3168 throws NoSuchObjectException, RemoteException 3169 { 3170 readyState.check(); 3171 concurrentObj.writeLock(); 3172 try { 3173 snapshotWt = weight; 3174 addLogRecord(new SnapshotWeightSetLogObj(weight)); 3175 } finally { 3176 concurrentObj.writeUnlock(); 3177 } 3178 }//end setPersistenceSnapshotWeight 3179 3180 /** 3181 * Retrieve the weight factor applied by the lookup discovery service 3182 * to the snapshot size during the test to determine whether or not to 3183 * take a "snapshot" of the system state. 3184 * 3185 * @return float value corresponding to the weight factor for snapshot 3186 * size 3187 * 3188 * @throws java.rmi.NoSuchObjectException if this method is called during 3189 * service initialization or shutdown processing 3190 * 3191 * @throws java.rmi.RemoteException typically, this exception occurs when 3192 * there is a communication failure between the client and the 3193 * lookup discovery service. 3194 * 3195 * @see org.apache.river.fiddler.proxy.FiddlerAdminProxy#getPersistenceSnapshotWeight 3196 * @see org.apache.river.admin.FiddlerAdmin#getPersistenceSnapshotWeight 3197 */ 3198 public float getPersistenceSnapshotWeight() 3199 throws NoSuchObjectException, RemoteException 3200 { 3201 readyState.check(); 3202 concurrentObj.readLock(); 3203 try { 3204 return snapshotWt; 3205 } finally { 3206 concurrentObj.readUnlock(); 3207 } 3208 }//end getPersistenceSnapshotWeight 3209 3210 /** 3211 * Change the value of the size threshold of the snapshot; which is 3212 * employed by the lookup discovery service in the test to determine 3213 * whether or not to take a "snapshot" of the system state. 3214 * 3215 * @param threshold size threshold for taking a snapshot 3216 * 3217 * @throws java.rmi.NoSuchObjectException if this method is called during 3218 * service initialization or shutdown processing 3219 * 3220 * @throws java.rmi.RemoteException typically, this exception occurs when 3221 * there is a communication failure between the client and the 3222 * lookup discovery service. When this exception does occur, the 3223 * threshold may or may not have been changed successfully. 3224 * 3225 * @see org.apache.river.fiddler.proxy.FiddlerAdminProxy 3226 * #setPersistenceSnapshotThreshold 3227 * @see org.apache.river.admin.FiddlerAdmin#setPersistenceSnapshotThreshold 3228 */ 3229 public void setPersistenceSnapshotThreshold(int threshold) 3230 throws NoSuchObjectException, RemoteException 3231 { 3232 readyState.check(); 3233 concurrentObj.writeLock(); 3234 try { 3235 snapshotThresh = threshold; 3236 addLogRecord(new SnapshotThresholdSetLogObj(threshold)); 3237 } finally { 3238 concurrentObj.writeUnlock(); 3239 } 3240 }//end setPersistenceSnapshotThreshold 3241 3242 /** 3243 * Retrieve the value of the size threshold of the snapshot; which is 3244 * employed by the lookup discovery service in the test to determine 3245 * whether or not to take a "snapshot" of the system state. 3246 * 3247 * @return int value corresponding to the size threshold of the snapshot 3248 * 3249 * @throws java.rmi.NoSuchObjectException if this method is called during 3250 * service initialization or shutdown processing 3251 * 3252 * @throws java.rmi.RemoteException typically, this exception occurs when 3253 * there is a communication failure between the client and the 3254 * lookup discovery service. 3255 * 3256 * @see org.apache.river.fiddler.proxy.FiddlerAdminProxy 3257 * #getPersistenceSnapshotThreshold 3258 * @see org.apache.river.admin.FiddlerAdmin#getPersistenceSnapshotThreshold 3259 */ 3260 public int getPersistenceSnapshotThreshold() 3261 throws NoSuchObjectException, RemoteException 3262 { 3263 readyState.check(); 3264 concurrentObj.readLock(); 3265 try { 3266 return snapshotThresh; 3267 } finally { 3268 concurrentObj.readUnlock(); 3269 } 3270 }//end getPersistenceSnapshotThreshold 3271 3272 /* END org.apache.river.fiddler.proxy.Fiddler --> org.apache.river.fiddler.proxy.FiddlerAdmin 3273 * -------------------------------------------------------------------- */ 3274 3275 /* -------------------------------------------------------------------- 3276 * BEGIN org.apache.river.fiddler.proxy.Fiddler 3277 * --> net.jini.lookup.ServiceProxyAccessor 3278 */ 3279 /** 3280 * Public method that facilitates the use of the mechanism provided by 3281 * {@link org.apache.river.start.ServiceStarter} to create an activatable 3282 * instance of this server. 3283 * 3284 * @throws java.rmi.NoSuchObjectException if this method is called during 3285 * service initialization or shutdown processing 3286 * 3287 * @return the outer (smart) proxy for the server 3288 */ 3289 public Object getServiceProxy() throws NoSuchObjectException { 3290 readyState.check(); 3291 concurrentObj.readLock(); 3292 try { 3293 return outerProxy; 3294 } finally { 3295 concurrentObj.readUnlock(); 3296 } 3297 }//end getServiceProxy 3298 3299 /* END org.apache.river.fiddler.proxy.Fiddler 3300 * --> net.jini.lookup.ServiceProxyAccessor */ 3301 /* -------------------------------------------------------------------- */ 3302 3303 /* -------------------------------------------------------------------- 3304 * BEGIN org.apache.river.fiddler.proxy.Fiddler 3305 */ 3306 /** 3307 * Returns the unique identifier generated (or recovered) by the backend 3308 * implementation of the lookup discovery service when an instance of 3309 * that service is constructed. This ID is typically used to determine 3310 * equality between the proxies of any two instances of the lookup 3311 * discovery service. 3312 * 3313 * @return the unique ID that was generated (or recovered) by the 3314 * backend implementation of the lookup discovery service 3315 * at creation time 3316 * 3317 * @throws java.rmi.NoSuchObjectException if this method is called during 3318 * service initialization or shutdown processing 3319 * 3320 * @throws java.rmi.RemoteException typically, this exception occurs when 3321 * there is a communication failure between the client and the 3322 * server. When this exception does occur, the registration may 3323 * or may not have completed successfully. 3324 */ 3325 public Uuid getProxyID() throws NoSuchObjectException, RemoteException { 3326 readyState.check(); 3327 concurrentObj.readLock(); 3328 try { 3329 return proxyID; 3330 } finally { 3331 concurrentObj.readUnlock(); 3332 } 3333 }//end getProxyID 3334 3335 /** 3336 * Registers with the lookup discovery service. When a client invokes 3337 * this method, it requests that the lookup discovery service perform 3338 * discovery processing on its behalf. 3339 * 3340 * @param groups String array, none of whose elements may be null, 3341 * consisting of zero or more names of groups to 3342 * which lookup services to discover belong. 3343 * A null value or an empty array 3344 * (DiscoveryGroupManagement.ALL_GROUPS or 3345 * DiscoveryGroupManagement.NO_GROUPS) are both 3346 * acceptable. 3347 * @param locators array of zero or more non-null LookupLocator 3348 * objects, each corresponding to a specific lookup 3349 * service to discover. If either the empty array 3350 * or null is passed to this argument, then no 3351 * locator discovery will be performed for the 3352 * associated registration. 3353 * @param listener a non-null instance of RemoteEventListener. This 3354 * argument specifies the entity that will receive 3355 * events notifying the registration that a lookup 3356 * service of interest has been discovered. A 3357 * non-null value must be passed to this argument, 3358 * otherwise a NullPointerException will be thrown 3359 * and the registration. 3360 * @param handback null or an instance of MarshalledObject. This 3361 * argument specifies an object that will be 3362 * included in the notification event that the 3363 * lookup discovery service sends to the registered 3364 * listener. 3365 * @param leaseDuration long value representing the amount of time (in 3366 * milliseconds) for which the resources of the 3367 * lookup discovery service are being requested. 3368 * 3369 * @return an instance of FiddlerRegistration which implements the 3370 * LookupDiscoveryRegistration interface, and acts as a proxy 3371 * to the registration-related methods of the backend server 3372 * of the Fiddler implementation of the lookup discovery service 3373 * 3374 * @throws java.rmi.NoSuchObjectException if this method is called during 3375 * service initialization or shutdown processing 3376 * 3377 * @throws java.rmi.RemoteException typically, this exception occurs when 3378 * there is a communication failure between the client and the 3379 * server. When this exception does occur, the registration may 3380 * or may not have completed successfully. 3381 * 3382 * @throws java.lang.NullPointerException this exception occurs when 3383 * null is input to the <code>listener</code> parameter, as well 3384 * as when one or more of the elements of the <code>groups</code> 3385 * parameter is null. 3386 * 3387 * @throws java.lang.IllegalArgumentException this exception occurs when 3388 * the value input to the <code>leaseDuration</code> parameter 3389 * is neither positive, Lease.FOREVER, nor Lease.ANY. 3390 * 3391 * @see net.jini.discovery.LookupDiscoveryService 3392 */ 3393 public LookupDiscoveryRegistration register(String[] groups, 3394 LookupLocator[] locators, 3395 RemoteEventListener listener, 3396 MarshalledObject handback, 3397 long leaseDuration) 3398 throws NoSuchObjectException, 3399 RemoteException 3400 { 3401 readyState.check(); 3402 /* The spec says that a null locators array implies no loc discovery */ 3403 if( locators == null) { 3404 locators = new LookupLocator[0]; 3405 }//endif 3406 if(containsNullElement(groups)) { 3407 throw new NullPointerException(" on call to register() method, at " 3408 +"least one null element in groups"); 3409 } else if (containsNullElement(locators)) { 3410 throw new NullPointerException(" on call to register() method, at " 3411 +"least one null element in locators"); 3412 } else if (listener == null) { 3413 throw new NullPointerException(" null listener input to " 3414 +"register() method"); 3415 }//endif 3416 /* Prepare the locators associated with the requested registration 3417 * outside of the sync block because of possible remote call. 3418 */ 3419 prepareNewLocators(locatorToDiscoverPreparer,locators); 3420 LookupDiscoveryRegistration reg = null; 3421 concurrentObj.writeLock(); 3422 try { 3423 /* Grant the registration request and add the registration to 3424 * to this service's state. 3425 * 3426 * The addition of a registration to this service's state 3427 * typically involves the modification of the managed sets in 3428 * the discovery manager, which usually involves starting the 3429 * discovery protocol. An IOException can occur when the 3430 * discovery protocol fails to start. When such an exception 3431 * does occur, register an ERROR status attribute (along with 3432 * a Comment attribute describing the nature of the problem) to 3433 * all lookup services with which this service is registered. 3434 * 3435 * Administrative clients, as well as clients that use this 3436 * service should have registered for notification of the 3437 * existence of this attribute. 3438 */ 3439 reg = registerDo(groups,locators,listener,handback,leaseDuration); 3440 } catch(RemoteException e) { 3441 /* Catch, log, and rethrow so RemoteException is not included 3442 * in the catch block for IOException below. 3443 */ 3444 problemLogger.log(Level.INFO, 3445 "cannot grant registration request", e); 3446 throw e; 3447 } catch(IOException e) { 3448 problemLogger.log(Level.INFO, "cannot grant registration " 3449 +"request - multicast problem", e); 3450 Entry[] errorAttrs 3451 = new Entry[] { new FiddlerStatus(StatusType.ERROR), 3452 new Comment("Failure during registration") 3453 }; 3454 joinMgr.addAttributes(errorAttrs,true); 3455 } finally { 3456 concurrentObj.writeUnlock(); 3457 } 3458 return reg; 3459 }//end register 3460 3461 /** 3462 * This method is the "backend" server counterpart to the method of 3463 * the same name provided by the <code>LookupDiscoveryRegistration</code> 3464 * proxy (an instance of <code>FiddlerRegistration</code>) that is 3465 * returned by this service when a client requests a registration. 3466 * <p> 3467 * This method returns an array consisting of proxies to the lookup 3468 * service(s) that have already been discovered for the registration 3469 * corresponding to the <code>registrationID</code> input parameter. 3470 * Each element of the return set is a marshalled instance of the 3471 * <code>ServiceRegistrar</code> interface. 3472 * 3473 * @param registrationID unique identifier assigned to the registration 3474 * from which the set of registrars is being 3475 * retrieved 3476 * 3477 * @return an array of MarshalledObject objects where each element is 3478 * is a marshalled instance of ServiceRegistrar. 3479 * 3480 * @throws java.rmi.NoSuchObjectException if this method is called during 3481 * service initialization or shutdown processing 3482 * 3483 * @throws java.rmi.RemoteException typically, this exception occurs when 3484 * there is a communication failure between the client and the 3485 * lookup discovery service. 3486 * 3487 * @throws org.apache.river.proxy.ThrowThis which is a non-remote "wrapper" 3488 * class used to wrap various remote exceptions (for example, 3489 * NoSuchObjectException) that this method wishes to throw. 3490 * When a service is implemented as a smart proxy with a 3491 * backend server, and a method on the backend which was invoked 3492 * through the proxy wishes to explicitly throw a particular 3493 * remote exception, it cannot simply throw that exception if 3494 * it wishes that exception to be visible to the proxy running 3495 * on the "client side". This is because when the backend throws 3496 * any remote exception, the RMI sub-system automatically wraps 3497 * that exception in a java.rmi.ServerException. Thus, the proxy 3498 * will only be able to "see" the ServerException (the actual 3499 * exception that the backend tried to throw is "buried" in the 3500 * detail field of the ServerException). Thus, in order to allow 3501 * the proxy access to the actual remote exception this method 3502 * throws, that exception wraps the desired remote exception in 3503 * the non-remote exception ThrowThis; which will not be wrapped 3504 * in a ServerException. 3505 * 3506 * This method throws a NoSuchObjectException wrapped in a 3507 * ThrowThis exception whenever the <code>registrationID</code> 3508 * parameter references an invalid or non-existent registration. 3509 * 3510 * @see org.apache.river.fiddler.proxy.FiddlerRegistration#getRegistrars 3511 * @see net.jini.discovery.LookupDiscoveryRegistration#getRegistrars 3512 */ 3513 public MarshalledObject[] getRegistrars(Uuid registrationID) 3514 throws NoSuchObjectException, RemoteException, ThrowThis 3515 { 3516 readyState.check(); 3517 concurrentObj.readLock(); 3518 try { 3519 RegistrationInfo regInfo 3520 = (RegistrationInfo)(registrationByID.get(registrationID)); 3521 if(regInfo == null) { 3522 throw new ThrowThis 3523 (new NoSuchObjectException( 3524 "Invalid registration ID on call to getRegistrars() method")); 3525 }//endif 3526 Collection mVals = (regInfo.discoveredRegsMap).values(); 3527 return ( (MarshalledObject[])(mVals).toArray 3528 (new MarshalledObject[mVals.size()]) ); 3529 } finally { 3530 concurrentObj.readUnlock(); 3531 } 3532 }//end getRegistrars 3533 3534 /** 3535 * This method is the "backend" server counterpart to the method of 3536 * the same name provided by the <code>LookupDiscoveryRegistration</code> 3537 * proxy (an instance of <code>FiddlerRegistration</code>) that is 3538 * returned by this service when a client requests a registration. 3539 * <p> 3540 * This method returns an array consisting of the names of the groups 3541 * whose members are lookup services the lookup discovery service will 3542 * attempt to discover for the registration corresponding to the current 3543 * instance of this class. This set of group names is referred to as the 3544 * registration's 'managed set of groups'. 3545 * <p> 3546 * If the registration's managed set of groups is currently empty, then 3547 * the empty array is returned. If the lookup discovery service currently 3548 * has no managed set of groups for the registration through which the 3549 * request is being made, then null will be returned. 3550 * 3551 * @param registrationID unique identifier assigned to the registration 3552 * from which the set of groups is being retrieved 3553 * 3554 * @return a String array containing the elements of the managed set of 3555 * groups for the registration. 3556 * 3557 * @throws java.rmi.NoSuchObjectException if this method is called during 3558 * service initialization or shutdown processing 3559 * 3560 * @throws java.rmi.RemoteException typically, this exception occurs when 3561 * there is a communication failure between the client and the 3562 * lookup discovery service. 3563 * 3564 * @throws java.rmi.NoSuchObjectException wrapped in an instance of 3565 * org.apache.river.proxy.ThrowThis exception whenever the 3566 * <code>registrationID</code> parameter references an invalid 3567 * or non-existent registration. Refer to the description of the 3568 * <code>getRegistrars</code> method for more information on 3569 * this exception. 3570 * 3571 * @see org.apache.river.fiddler.proxy.FiddlerRegistration#getGroups 3572 * @see net.jini.discovery.LookupDiscoveryRegistration#getGroups 3573 */ 3574 public String[] getGroups(Uuid registrationID) 3575 throws NoSuchObjectException, RemoteException, ThrowThis 3576 { 3577 readyState.check(); 3578 concurrentObj.readLock(); 3579 try { 3580 RegistrationInfo regInfo 3581 = (RegistrationInfo)(registrationByID.get(registrationID)); 3582 if(regInfo == null) { 3583 throw new ThrowThis( 3584 new NoSuchObjectException( 3585 "Invalid registration ID on call to getGroups() method" 3586 ) 3587 ); 3588 }//endif 3589 String[] groups = null; 3590 if(regInfo.groups == null) { 3591 groups = DiscoveryGroupManagement.ALL_GROUPS; 3592 } else { 3593 groups = (String[])(regInfo.groups).toArray 3594 (new String[regInfo.groups.size()]); 3595 }//endif (regInfo.groups == null) 3596 return groups; 3597 } finally { 3598 concurrentObj.readUnlock(); 3599 } 3600 }//end getGroups 3601 3602 /** 3603 * This method is the "backend" server counterpart to the method of 3604 * the same name provided by the <code>LookupDiscoveryRegistration</code> 3605 * proxy (an instance of <code>FiddlerRegistration</code>) that is 3606 * returned by this service when a client requests a registration. 3607 * <p> 3608 * This method returns an array consisting of the the LookupLocator 3609 * objects corresponding to specific lookup services the lookup discovery 3610 * service will attempt to discover for for the registration 3611 * corresponding to the current instance of this class. This set of 3612 * locators is referred to as the registration's 'managed set of locators'. 3613 * <p> 3614 * If the registration's managed set of locators is currently empty, then 3615 * the empty array is returned. If the lookup discovery service currently 3616 * has no managed set of locators for the registration through which the 3617 * request is being made, then null will be returned. 3618 * 3619 * @param registrationID unique identifier assigned to the registration 3620 * from which the set of locators is being retrieved 3621 * 3622 * @return array consisting of net.jini.core.discovery.LookupLocator 3623 * objects corresponding to the elements of the managed set of 3624 * locators for the registration. 3625 * 3626 * @throws java.rmi.NoSuchObjectException if this method is called during 3627 * service initialization or shutdown processing 3628 * 3629 * @throws java.rmi.RemoteException typically, this exception occurs when 3630 * there is a communication failure between the client and the 3631 * lookup discovery service. 3632 * 3633 * @throws java.rmi.NoSuchObjectException wrapped in an instance of 3634 * org.apache.river.proxy.ThrowThis exception whenever the 3635 * <code>registrationID</code> parameter references an invalid 3636 * or non-existent registration. Refer to the description of the 3637 * <code>getRegistrars</code> method for more information on 3638 * this exception. 3639 * 3640 * @see org.apache.river.fiddler.proxy.FiddlerRegistration#getLocators 3641 * @see net.jini.discovery.LookupDiscoveryRegistration#getLocators 3642 */ 3643 public LookupLocator[] getLocators(Uuid registrationID) 3644 throws NoSuchObjectException, RemoteException, ThrowThis 3645 { 3646 readyState.check(); 3647 concurrentObj.readLock(); 3648 try { 3649 RegistrationInfo regInfo 3650 = (RegistrationInfo)(registrationByID.get(registrationID)); 3651 if(regInfo == null) { 3652 throw new ThrowThis( 3653 new NoSuchObjectException( 3654 "Invalid registration ID on call to getLocators() method" 3655 ) 3656 ); 3657 }//endif 3658 return (LookupLocator[])(regInfo.locators).toArray 3659 (new LookupLocator[regInfo.locators.size()]); 3660 } finally { 3661 concurrentObj.readUnlock(); 3662 } 3663 }//end getLocators 3664 3665 /** 3666 * This method is the "backend" server counterpart to the method of 3667 * the same name provided by the <code>LookupDiscoveryRegistration</code> 3668 * proxy (an instance of <code>FiddlerRegistration</code>) that is 3669 * returned by this service when a client requests a registration. 3670 * <p> 3671 * This method first tests the input set of group names for validity and 3672 * throws the appropriate exception should any irregularities be found. 3673 * It then adds the input set of group names to the managed set of groups 3674 * associated with the registration. 3675 * 3676 * @param registrationID unique identifier assigned to the registration 3677 * to which the set of groups being augmented 3678 * corresponds 3679 * @param groups a String array, none of whose elements may be 3680 * null, consisting of the group names with which to 3681 * augment the registration's managed set of groups. 3682 * <p> 3683 * If any element of this parameter duplicates any 3684 * other element of this parameter, the duplicate 3685 * will be ignored. If any element of this parameter 3686 * duplicates any element of the registration's 3687 * current managed set of groups, the duplicate will 3688 * be ignored. 3689 * <p> 3690 * If the empty set is input, then the registration's 3691 * managed set of groups will not change. If null is 3692 * input, this method will throw a 3693 * <code>NullPointerException</code>. 3694 * 3695 * @throws java.lang.IllegalStateException this exception occurs when 3696 * the <code>addGroups</code> method of the discovery 3697 * manager is invoked after the <code>terminate</code> method 3698 * of that manager is called. When this happens, in addition to 3699 * propagating this exception, this method also registers an 3700 * ERROR status attribute (along with a Comment attribute 3701 * describing the nature of the problem) with all lookup services 3702 * with which this service is registered. Administrative clients, 3703 * as well as clients that use this service should register 3704 * for notification of the existence of this attribute. 3705 * 3706 * @throws java.lang.UnsupportedOperationException this exception 3707 * occurs when the registration corresponding to the 3708 * <code>registrationID</code> parameter has no managed set of 3709 * groups to which to add the elements of the input parameter. 3710 * That is, the registration's current managed set of groups is 3711 * null. When a registration's managed set of groups is null, 3712 * it means that all groups are being discovered for that 3713 * registration; thus, requesting that a set of groups be added 3714 * to the set of all groups makes no sense. 3715 * 3716 * @throws java.lang.NullPointerException this exception occurs when 3717 * either null is input to the <code>groups</code> parameter, 3718 * or one or more of the elements of the <code>groups</code> 3719 * parameter is null. If a null <code>groups</code> parameter 3720 * is input, the registration is requesting that all groups be 3721 * added to its current managed set of groups; which is not 3722 * allowed. (Note that if a registration wishes to change its 3723 * managed set of groups from a finite set of names to "all 3724 * groups", it should invoke setGroups with a null input.) 3725 * 3726 * @throws java.rmi.NoSuchObjectException if this method is called during 3727 * service initialization or shutdown processing 3728 * 3729 * @throws java.rmi.RemoteException typically, this exception occurs when 3730 * there is a communication failure between the client and the 3731 * lookup discovery service. When this exception does occur, the 3732 * registration's managed set of groups may or may not have been 3733 * successfully augmented. 3734 * 3735 * @throws java.rmi.NoSuchObjectException wrapped in an instance of 3736 * org.apache.river.proxy.ThrowThis exception whenever the 3737 * <code>registrationID</code> parameter references an invalid 3738 * or non-existent registration. Refer to the description of the 3739 * <code>getRegistrars</code> method for more information on 3740 * this exception. 3741 * 3742 * @see org.apache.river.fiddler.proxy.FiddlerRegistration#addGroups 3743 * @see net.jini.discovery.LookupDiscoveryRegistration#addGroups 3744 */ 3745 public void addGroups(Uuid registrationID, String[] groups) 3746 throws NoSuchObjectException, RemoteException, ThrowThis 3747 { 3748 readyState.check(); 3749 concurrentObj.writeLock(); 3750 try { 3751 RegistrationInfo regInfo 3752 = (RegistrationInfo)(registrationByID.get(registrationID)); 3753 if(regInfo == null) { 3754 throw new ThrowThis( 3755 new NoSuchObjectException( 3756 "Invalid registration ID on call to addGroups() method" 3757 ) 3758 ); 3759 }//endif 3760 /* Check the input for validity */ 3761 if(groups == null) { // asking that all groups be added 3762 throw new NullPointerException( 3763 " on call to addGroups() method, cannot add 'ALL_GROUPS' (the null set) to a registration's set of groups to discover" 3764 ); 3765 } else if(containsNullElement(groups)) { // null element 3766 throw new NullPointerException( 3767 " on call to addGroups() method, at least one null element in groups parameter" 3768 ); 3769 } else if (regInfo.groups == null) { // all groups being discovered 3770 throw new UnsupportedOperationException 3771 (" on call to addGroups() " 3772 +"method, cannot add a set of" 3773 +"groups to a set already " 3774 +"configured for 'ALL_GROUPS' " 3775 +"(the null set)"); 3776 }//endif 3777 /* Augment the current set of groups with the input set */ 3778 addGroupsDo(regInfo, groups); 3779 addLogRecord(new GroupsAddedToRegistrationLogObj 3780 (regInfo.registrationID,groups)); 3781 } finally { 3782 concurrentObj.writeUnlock(); 3783 } 3784 }//end addGroups 3785 3786 /** 3787 * This method is the "backend" server counterpart to the method of 3788 * the same name provided by the <code>LookupDiscoveryRegistration</code> 3789 * proxy (an instance of <code>FiddlerRegistration</code>) that is 3790 * returned by this service when a client requests a registration. 3791 * <p> 3792 * This method first tests the input set of group names for validity and 3793 * throws the appropriate exception should any irregularities be found. 3794 * It then queues a <code>SetGroupsTask</code> which performs the 3795 * actual replacement. 3796 * <p> 3797 * 3798 * @param registrationID unique identifier assigned to the registration 3799 * to which the set of groups being replaced 3800 * corresponds 3801 * @param groups a String array, none of whose elements may be 3802 * null, consisting of the group names with which to 3803 * replace the names in this registration's managed 3804 * set of groups. 3805 * <p> 3806 * If any element of this parameter duplicates any 3807 * other element of this parameter, the duplicate 3808 * will be ignored. 3809 * <p> 3810 * If the empty set is input, then group discovery 3811 * for the registration will cease. If null is input, 3812 * the lookup discovery service will attempt to 3813 * discover all as yet undiscovered lookup services 3814 * located within its multicast radius and, upon 3815 * discovery of any such lookup service, will send 3816 * to the registration's listener an event signaling 3817 * that discovery. 3818 * 3819 * @throws java.lang.NullPointerException this exception occurs when one 3820 * or more of the elements of the groups parameter is null. 3821 * 3822 * @throws java.rmi.NoSuchObjectException if this method is called during 3823 * service initialization or shutdown processing 3824 * 3825 * @throws java.rmi.RemoteException typically, this exception occurs when 3826 * there is a communication failure between the client and the 3827 * lookup discovery service. When this exception does occur, the 3828 * registration's managed set of groups may or may not have been 3829 * successfully replaced. 3830 * 3831 * @throws java.rmi.NoSuchObjectException wrapped in an instance of 3832 * org.apache.river.proxy.ThrowThis exception whenever the 3833 * <code>registrationID</code> parameter references an invalid 3834 * or non-existent registration. Refer to the description of the 3835 * <code>getRegistrars</code> method for more information on 3836 * this exception. 3837 * 3838 * @see org.apache.river.fiddler.proxy.FiddlerRegistration#setGroups 3839 * @see net.jini.discovery.LookupDiscoveryRegistration#setGroups 3840 */ 3841 public void setGroups(Uuid registrationID, String[] groups) 3842 throws NoSuchObjectException, RemoteException, ThrowThis 3843 { 3844 readyState.check(); 3845 concurrentObj.writeLock(); 3846 try { 3847 RegistrationInfo regInfo 3848 = (RegistrationInfo)(registrationByID.get(registrationID)); 3849 if(regInfo == null) { 3850 throw new ThrowThis( 3851 new NoSuchObjectException( 3852 "Invalid registration ID on call to setGroups() method" 3853 ) 3854 ); 3855 }//endif 3856 /* Check the input for validity */ 3857 if(containsNullElement(groups)) { // null element 3858 throw new NullPointerException( 3859 " on call to setGroups() method, at least one null element in groups parameter" 3860 ); 3861 } else if ((groups == null) && (regInfo.groups == null)) { 3862 /* null input, but already set to ALL groups; do nothing */ 3863 return; 3864 }//endif 3865 /* Replace the current groups with the current groups */ 3866 setGroupsDo(regInfo, groups); 3867 addLogRecord(new GroupsSetInRegistrationLogObj 3868 (regInfo.registrationID,groups)); 3869 } finally { 3870 concurrentObj.writeUnlock(); 3871 } 3872 }//end setGroups 3873 3874 /** 3875 * This method is the "backend" server counterpart to the method of 3876 * the same name provided by the <code>LookupDiscoveryRegistration</code> 3877 * proxy (an instance of <code>FiddlerRegistration</code>) that is 3878 * returned by this service when a client requests a registration. 3879 * <p> 3880 * This method first tests the input set of group names for validity and 3881 * throws the appropriate exception should any irregularities be found. 3882 * It then queues a <code>RemoveGroupsTask</code> which performs the 3883 * actual removal. 3884 * 3885 * @param registrationID unique identifier assigned to the registration 3886 * to which the set of groups being removed 3887 * corresponds 3888 * @param groups a String array, none of whose elements may be 3889 * null, consisting of the group names to delete 3890 * from the registration's managed set of groups. 3891 * <p> 3892 * If any element of this parameter duplicates any 3893 * other element of this parameter, the duplicate 3894 * will be ignored. If any element of this parameter 3895 * is not currently contained in the registration's 3896 * managed set, no action is taken with respect to 3897 * that element. 3898 * <p> 3899 * If the empty set is input, the registration's 3900 * managed set of groups will not change. If null is 3901 * input, this method will throw a 3902 * <code>NullPointerException</code>. 3903 * 3904 * @throws java.lang.UnsupportedOperationException this exception 3905 * occurs when the registration corresponding to the 3906 * <code>registrationID</code> parameter has no managed set 3907 * of groups from which to remove elements of the input parameter. 3908 * That is, the registration's current managed set of groups is 3909 * null. Thus, requesting that a set of groups be removed from 3910 * null set makes no sense. 3911 * 3912 * @throws java.lang.NullPointerException this exception occurs when 3913 * either null is input to the <code>groups</code> parameter, 3914 * or one or more of the elements of the <code>groups</code> 3915 * parameter is null. If a null <code>groups</code> parameter 3916 * is input, the registration is requesting that all groups be 3917 * removed from its current managed set of groups; which is not 3918 * allowed. (Note that if a registration wishes to change its 3919 * managed set of groups from "all groups" to "no groups", it 3920 * it should invoke setGroups with a zero length 3921 * <code>String</code> input.) 3922 * 3923 * @throws java.rmi.NoSuchObjectException if this method is called during 3924 * service initialization or shutdown processing 3925 * 3926 * @throws java.rmi.RemoteException typically, this exception occurs when 3927 * there is a communication failure between the client and the 3928 * lookup discovery service. When this exception does occur, the 3929 * registration's managed set of groups may or may not have been 3930 * successfully modified. 3931 * 3932 * @throws java.rmi.NoSuchObjectException wrapped in an instance of 3933 * org.apache.river.proxy.ThrowThis exception whenever the 3934 * <code>registrationID</code> parameter references an invalid 3935 * or non-existent registration. Refer to the description of the 3936 * <code>getRegistrars</code> method for more information on 3937 * this exception. 3938 * 3939 * @see org.apache.river.fiddler.proxy.FiddlerRegistration#removeGroups 3940 * @see net.jini.discovery.LookupDiscoveryRegistration#removeGroups 3941 */ 3942 public void removeGroups(Uuid registrationID, String[] groups) 3943 throws NoSuchObjectException, RemoteException, ThrowThis 3944 { 3945 readyState.check(); 3946 concurrentObj.writeLock(); 3947 try { 3948 RegistrationInfo regInfo 3949 = (RegistrationInfo)(registrationByID.get(registrationID)); 3950 if(regInfo == null) { 3951 throw new ThrowThis( 3952 new NoSuchObjectException( 3953 "Invalid registration ID on call to removeGroups() method" 3954 ) 3955 ); 3956 }//endif 3957 /* Check the input for validity */ 3958 if(groups == null) { // asking that all groups be removed 3959 throw new NullPointerException( 3960 " on call to removeGroups() method, cannot remove 'ALL_GROUPS' (the null set) from a registration's set of groups to discover" 3961 ); 3962 } else if(containsNullElement(groups)) { // null element 3963 throw new NullPointerException( 3964 " on call to removeGroups() method, at least one null element in groups parameter" 3965 ); 3966 } else if (regInfo.groups == null) { // all groups being discovered 3967 throw new UnsupportedOperationException( 3968 " on call to removeGroups() method, cannot remove a set of groups from a set already configured for 'ALL_GROUPS' (the null set)" 3969 ); 3970 }//endif 3971 /* Remove the requested groups */ 3972 removeGroupsDo(regInfo, groups); 3973 logInfoGroups("\nAfter Group Removal --"); 3974 addLogRecord(new GroupsRemovedFromRegistrationLogObj 3975 (regInfo.registrationID,groups)); 3976 } finally { 3977 concurrentObj.writeUnlock(); 3978 } 3979 }//end removeGroups 3980 3981 /** 3982 * This method is the "backend" server counterpart to the method of 3983 * the same name provided by the <code>LookupDiscoveryRegistration</code> 3984 * proxy (an instance of <code>FiddlerRegistration</code>) that is 3985 * returned by this service when a client requests a registration. 3986 * <p> 3987 * This method first tests the input set of group names for validity and 3988 * throws the appropriate exception should any irregularities be found. 3989 * It then adds the input set of LookupLocator objects to the managed set 3990 * of locators associated with the registration. 3991 * 3992 * @param registrationID unique identifier assigned to the registration 3993 * to which the set of locators being augmented 3994 * corresponds 3995 * @param locators an array, none of whose elements may be null, 3996 * consisting of the LookupLocator objects with 3997 * which to augment the registration's managed set 3998 * of locators. 3999 * <p> 4000 * If any element of this parameter duplicates any 4001 * other element of this parameter, the duplicate 4002 * will be ignored. If any element of this parameter 4003 * duplicates any element of the registration's 4004 * managed set of locators, the duplicate will be 4005 * ignored. 4006 * <p> 4007 * If the empty set is input, then the registration's 4008 * managed set of locators will not change. If null 4009 * is input, this method will throw a 4010 * <code>NullPointerException</code>. 4011 * 4012 * @throws java.lang.IllegalStateException this exception occurs when 4013 * the <code>addLocators</code> method of the discovery 4014 * manager is invoked after the <code>terminate</code> method 4015 * of that manager is called. When this happens, in addition to 4016 * propagating this exception, this method also registers an 4017 * ERROR status attribute (along with a Comment attribute 4018 * describing the nature of the problem) with all lookup services 4019 * with which this service is registered. Administrative clients, 4020 * as well as clients that use this service should register 4021 * for notification of the existence of this attribute. 4022 * 4023 * @throws java.lang.NullPointerException this exception occurs when 4024 * either null is input to the <code>locators</code> parameter, 4025 * or one or more of the elements of the <code>locators</code> 4026 * parameter is null. 4027 * 4028 * @throws java.rmi.NoSuchObjectException if this method is called during 4029 * service initialization or shutdown processing 4030 * 4031 * @throws java.rmi.RemoteException typically, this exception occurs when 4032 * there is a communication failure between the client and the 4033 * lookup discovery service. When this exception does occur, the 4034 * registration's managed set of locators may or may not have 4035 * been successfully augmented. 4036 * 4037 * @throws java.rmi.NoSuchObjectException wrapped in an instance of 4038 * org.apache.river.proxy.ThrowThis exception whenever the 4039 * <code>registrationID</code> parameter references an invalid 4040 * or non-existent registration. Refer to the description of the 4041 * <code>getRegistrars</code> method for more information on 4042 * this exception. 4043 * 4044 * @see org.apache.river.fiddler.proxy.FiddlerRegistration#addLocators 4045 * @see net.jini.discovery.LookupDiscoveryRegistration#addLocators 4046 */ 4047 public void addLocators(Uuid registrationID, LookupLocator[] locators) 4048 throws NoSuchObjectException, RemoteException, ThrowThis 4049 4050 { 4051 readyState.check(); 4052 /* Prepare outside of sync block because of possible remote call */ 4053 prepareNewLocators(locatorToDiscoverPreparer,locators); 4054 concurrentObj.writeLock(); 4055 try { 4056 RegistrationInfo regInfo 4057 = (RegistrationInfo)(registrationByID.get(registrationID)); 4058 if(regInfo == null) { 4059 throw new ThrowThis( 4060 new NoSuchObjectException( 4061 "Invalid registration ID on call to addLocators() method" 4062 ) 4063 ); 4064 }//endif 4065 /* Check the input for validity */ 4066 if(locators == null) { 4067 throw new NullPointerException( 4068 " on call to addLocators() method, cannot add null to a registration's set of locators to discover" 4069 ); 4070 } else if(containsNullElement(locators)) { // null element 4071 throw new NullPointerException( 4072 " on call to addLocators() method, at least one null element in locators parameter" 4073 ); 4074 }//endif(locators == null) 4075 /* Augment the current set of locators with the input set */ 4076 addLocatorsDo(regInfo, locators); 4077 addLogRecord(new LocsAddedToRegistrationLogObj 4078 (regInfo.registrationID,locators)); 4079 } finally { 4080 concurrentObj.writeUnlock(); 4081 } 4082 }//end addLocators 4083 4084 /** 4085 * This method is the "backend" server counterpart to the method of 4086 * the same name provided by the <code>LookupDiscoveryRegistration</code> 4087 * proxy (an instance of <code>FiddlerRegistration</code>) that is 4088 * returned by this service when a client requests a registration. 4089 * <p> 4090 * This method first tests the input set of locators for validity and 4091 * throws the appropriate exception should any irregularities be found. 4092 * It then queues a <code>SetLocatorsTask</code> which performs the 4093 * actual replacement. 4094 * 4095 * @param registrationID unique identifier assigned to the registration 4096 * to which the set of locators being replaced 4097 * corresponds 4098 * @param locators an array, none of whose elements may be null, 4099 * consisting of the LookupLocator objects with 4100 * which to replace the locators in the 4101 * registration's managed set of locators. 4102 * <p> 4103 * If any element of this parameter duplicates any 4104 * other element of this parameter, the duplicate 4105 * will be ignored. 4106 * <p> 4107 * If the empty array is input, then locator 4108 * discovery for the registration will cease. If 4109 * null is input, this method will throw a 4110 * <code>NullPointerException</code>. 4111 * 4112 * @throws java.lang.NullPointerException this exception occurs when 4113 * either null is input to the <code>locators</code> parameter, 4114 * or one or more of the elements of the <code>locators</code> 4115 * parameter is null. 4116 * 4117 * @throws java.rmi.NoSuchObjectException if this method is called during 4118 * service initialization or shutdown processing 4119 * 4120 * @throws java.rmi.RemoteException typically, this exception occurs when 4121 * there is a communication failure between the client and the 4122 * lookup discovery service. When this exception does occur, the 4123 * registration's managed set of locators may or may not have 4124 * been successfully replaced. 4125 * 4126 * @throws java.rmi.NoSuchObjectException wrapped in an instance of 4127 * org.apache.river.proxy.ThrowThis exception whenever the 4128 * <code>registrationID</code> parameter references an invalid 4129 * or non-existent registration. Refer to the description of the 4130 * <code>getRegistrars</code> method for more information on 4131 * this exception. 4132 * 4133 * @see org.apache.river.fiddler.proxy.FiddlerRegistration#setLocators 4134 * @see net.jini.discovery.LookupDiscoveryRegistration#setLocators 4135 */ 4136 public void setLocators(Uuid registrationID, LookupLocator[] locators) 4137 throws NoSuchObjectException, RemoteException, ThrowThis 4138 { 4139 readyState.check(); 4140 /* Prepare outside of sync block because of possible remote call */ 4141 prepareNewLocators(locatorToDiscoverPreparer,locators); 4142 concurrentObj.writeLock(); 4143 try { 4144 RegistrationInfo regInfo 4145 = (RegistrationInfo)(registrationByID.get(registrationID)); 4146 if(regInfo == null) { 4147 throw new ThrowThis( 4148 new NoSuchObjectException( 4149 "Invalid registration ID on call to setLocators() method" 4150 ) 4151 ); 4152 }//endif 4153 /* Check the input for validity */ 4154 if(locators == null) { 4155 throw new NullPointerException( 4156 " on call to setLocators() method, cannot replace a registration's current set of locators with null" 4157 ); 4158 } else if(containsNullElement(locators)) { // null element 4159 throw new NullPointerException( 4160 " on call to setLocators() method, at least one null element in locators parameter" 4161 ); 4162 }//endif(locators == null) 4163 setLocatorsDo(regInfo, locators); 4164 addLogRecord(new LocsSetInRegistrationLogObj 4165 (regInfo.registrationID,locators)); 4166 } finally { 4167 concurrentObj.writeUnlock(); 4168 } 4169 }//end setLocators 4170 4171 /** 4172 * This method is the "backend" server counterpart to the method of 4173 * the same name provided by the <code>LookupDiscoveryRegistration</code> 4174 * proxy (an instance of <code>FiddlerRegistration</code>) that is 4175 * returned by this service when a client requests a registration. 4176 * <p> 4177 * This method first tests the input set of locators for validity and 4178 * throws the appropriate exception should any irregularities be found. 4179 * It then queues a <code>RemoveLocatorsTask</code> which performs the 4180 * actual removal. 4181 * 4182 * @param registrationID unique identifier assigned to the registration 4183 * to which the set of locators being removed 4184 * corresponds 4185 * @param locators an array, none of whose elements may be null, 4186 * consisting of the LookupLocator objects to remove 4187 * from the registration's managed set of locators. 4188 * <p> 4189 * If any element of this parameter duplicates any 4190 * other element of this parameter, the duplicate 4191 * will be ignored. 4192 * <p> 4193 * If the empty set is input, the managed set of 4194 * locators will not change. If null is input, 4195 * this method will throw a 4196 * <code>NullPointerException</code>. 4197 * 4198 * @throws java.lang.NullPointerException this exception occurs when 4199 * either null is input to the <code>locators</code> parameter, 4200 * or one or more of the elements of the <code>locators</code> 4201 * parameter is null. 4202 * 4203 * @throws java.rmi.NoSuchObjectException if this method is called during 4204 * service initialization or shutdown processing 4205 * 4206 * @throws java.rmi.RemoteException typically, this exception occurs when 4207 * there is a communication failure between the client and the 4208 * lookup discovery service. When this exception does occur, the 4209 * registration's managed set of locators may or may not have 4210 * been successfully modified. 4211 * 4212 * @throws java.rmi.NoSuchObjectException wrapped in an instance of 4213 * org.apache.river.proxy.ThrowThis exception whenever the 4214 * <code>registrationID</code> parameter references an invalid 4215 * or non-existent registration. Refer to the description of the 4216 * <code>getRegistrars</code> method for more information on 4217 * this exception. 4218 * 4219 * @see org.apache.river.fiddler.proxy.FiddlerRegistration#removeLocators 4220 * @see net.jini.discovery.LookupDiscoveryRegistration#removeLocators 4221 */ 4222 public void removeLocators(Uuid registrationID, LookupLocator[] locators) 4223 throws NoSuchObjectException, RemoteException, ThrowThis 4224 { 4225 readyState.check(); 4226 /* Prepare outside of sync block because of possible remote call */ 4227 prepareNewLocators(locatorToDiscoverPreparer,locators); 4228 concurrentObj.writeLock(); 4229 try { 4230 RegistrationInfo regInfo 4231 = (RegistrationInfo)(registrationByID.get(registrationID)); 4232 if(regInfo == null) { 4233 throw new ThrowThis( 4234 new NoSuchObjectException( 4235 "Invalid registration ID on call to removeLocators() method" 4236 ) 4237 ); 4238 }//endif 4239 /* Check the input for validity */ 4240 if(locators == null) { 4241 throw new NullPointerException( 4242 " on call to removeLocators() method, cannot remove null from a registration's set of locators to discover" 4243 ); 4244 } else if(containsNullElement(locators)) { // null element 4245 throw new NullPointerException( 4246 " on call to removeLocators() method, at least one null element in locators parameter" 4247 ); 4248 }//endif(locators == null) 4249 /* Remove the requested set of locators from the current set */ 4250 removeLocatorsDo(regInfo, locators); 4251 addLogRecord(new LocsRemovedFromRegistrationLogObj 4252 (regInfo.registrationID,locators)); 4253 } finally { 4254 concurrentObj.writeUnlock(); 4255 } 4256 }//end removeLocators 4257 4258 /** 4259 * This method is the "backend" server counterpart to the method of 4260 * the same name provided by the <code>LookupDiscoveryRegistration</code> 4261 * proxy (an instance of <code>FiddlerRegistration</code>) that is 4262 * returned by this service when a client requests a registration. 4263 * <p> 4264 * This method informs the lookup discovery service of the existence of 4265 * an unavailable lookup service and requests that the lookup discovery 4266 * service discard the unavailable lookup service and make it eligible 4267 * to be re-discovered. 4268 * 4269 * @param registrationID unique identifier assigned to the registration 4270 * making the current discard request 4271 * @param registrar a reference to the lookup service that the lookup 4272 * discovery service is being asked to discard. 4273 * <p> 4274 * If this parameter equals none of the lookup 4275 * services contained in the managed set of lookup 4276 * services for this registration, no action will 4277 * be taken. 4278 * 4279 * @throws java.lang.NullPointerException this exception occurs when 4280 * null is input to the registrar parameter. 4281 * 4282 * @throws java.rmi.NoSuchObjectException if this method is called during 4283 * service initialization or shutdown processing 4284 * 4285 * @throws java.rmi.RemoteException typically, this exception occurs when 4286 * there is a communication failure between the client and the 4287 * lookup discovery service. When this exception does occur, 4288 * the lookup service may or may not have been successfully 4289 * discarded. 4290 * 4291 * @throws java.rmi.NoSuchObjectException wrapped in an instance of 4292 * org.apache.river.proxy.ThrowThis exception whenever the 4293 * <code>registrationID</code> parameter references an invalid 4294 * or non-existent registration. Refer to the description of the 4295 * <code>getRegistrars</code> method for more information on 4296 * this exception. 4297 * 4298 * @see org.apache.river.fiddler.proxy.FiddlerRegistration#discard 4299 * @see net.jini.discovery.LookupDiscoveryRegistration#discard 4300 */ 4301 public void discard(Uuid registrationID, ServiceRegistrar registrar) 4302 throws NoSuchObjectException, RemoteException, ThrowThis 4303 { 4304 readyState.check(); 4305 concurrentObj.writeLock(); 4306 try { 4307 logInfoDiscard("\ndiscard: ",registrationID); 4308 RegistrationInfo regInfo 4309 = (RegistrationInfo)(registrationByID.get(registrationID)); 4310 if(regInfo == null) { 4311 throw new ThrowThis( 4312 new NoSuchObjectException( 4313 "Invalid registration ID on call to discard() method" 4314 ) 4315 ); 4316 }//endif 4317 if(registrar == null) { 4318 throw new NullPointerException( 4319 " on call to discard() method, null input for registrar to discard" 4320 ); 4321 }//endif 4322 if( regIsElementOfRegSet(registrar,discoveryMgr.getRegistrars()) ){ 4323 /* This must be the first discard request for this registrar 4324 * because the discovery manager has not discarded it yet. 4325 * When the discovery manager discards the registrar, a 4326 * local discarded event is sent to the listener.discarded 4327 * method which queues a DiscardedEventTask which will 4328 * remove the discarded registrar from the registration's 4329 * set of discovered registrars and then send a remote 4330 * discarded event to the registration's listener. 4331 */ 4332 logInfoDiscard(" Registrar IS an element of Mgr's " 4333 +"discovered registrars ... discarding " 4334 +"from discovery manager"); 4335 regInfo.discardFlag = true; //discard due to external request 4336 discoveryMgr.discard(registrar); 4337 } else { 4338 logInfoDiscard(" Registrar NOT an element of Mgr's " 4339 +"discovered registrars ... queuing " 4340 +"new DiscardRegistrarTask"); 4341 /* For all subsequent discard requests, remove the registrar 4342 * from the registration's set of discovered registrars and 4343 * send a remote discarded event, but don't ask the discovery 4344 * manager to discard the registrar. 4345 */ 4346 executorService.execute(new DiscardRegistrarTask(regInfo,registrar)); 4347 }//endif 4348 } finally { 4349 concurrentObj.writeUnlock(); 4350 } 4351 }//end discard 4352 4353 /** 4354 * This method is the "backend" server counterpart to the 4355 * <code>renew</code> method specified by the <code>Lease</code> interface, 4356 * implemented in the <code>org.apache.river.lease.AbstractLease</code> class, 4357 * and invoked by way of the <code>doRenew</code> method of the 4358 * <code>FiddlerLease</code> class; an instance of which is 4359 * returned by the <code>getLease</code> method of the 4360 * <code>LookupDiscoveryRegistration</code> proxy (an instance of 4361 * <code>FiddlerRegistration</code>) that is returned by this service 4362 * when a client requests a registration. 4363 * <p> 4364 * This method renews the lease corresponding to the given 4365 * <code>registrationID</code> and <code>leaseID</code> parameters, 4366 * granting a new duration that is less than or equal to the requested 4367 * duration value contained in the <code>duration</code> parameter. 4368 * 4369 * @param registrationID unique identifier assigned to the registration 4370 * to which the lease being renewed corresponds 4371 * @param leaseID identifier assigned by the lease grantor to the 4372 * lease being renewed 4373 * @param duration the requested duration for the lease being renewed 4374 * 4375 * @return <code>long</code> value representing the actual duration that 4376 * was granted for the renewed lease. Note that the actual 4377 * duration granted and returned by this method may be less than 4378 * the duration requested. 4379 * 4380 * @throws net.jini.core.lease.UnknownLeaseException this exception occurs 4381 * when the lease being renewed does not exist, or is unknown 4382 * to the lease grantor; typically because the lease has expired. 4383 * 4384 * @throws java.rmi.NoSuchObjectException if this method is called during 4385 * service initialization or shutdown processing 4386 * 4387 * @throws java.rmi.RemoteException typically, this exception occurs when 4388 * there is a communication failure between the client and the 4389 * server. When this exception does occur, the lease may or may 4390 * not have been renewed successfully. 4391 * 4392 * @see net.jini.core.lease.Lease#renew 4393 * @see org.apache.river.lease.AbstractLease#renew 4394 * @see org.apache.river.lease.AbstractLease#doRenew 4395 * @see org.apache.river.fiddler.proxy.FiddlerLease#doRenew 4396 */ 4397 public long renewLease(Uuid registrationID, 4398 Uuid leaseID, 4399 long duration) 4400 throws UnknownLeaseException, NoSuchObjectException, RemoteException 4401 { 4402 readyState.check(); 4403 concurrentObj.priorityWriteLock(); 4404 try { 4405 RegistrationInfo regInfo 4406 = (RegistrationInfo)(registrationByID.get(registrationID)); 4407 if(regInfo == null) { 4408 throw new UnknownLeaseException 4409 ("\n Invalid registration ID "+ registrationID + " on call to " 4410 +"renewLease() method" 4411 +"\n The lease may have expired or been " 4412 +"cancelled"); 4413 }//endif 4414 /* Renew the lease */ 4415 long newDuration = 0; 4416 newDuration = renewLeaseDo(regInfo, leaseID, duration); 4417 logInfoLease("Renewed lease: ",registrationID,leaseID); 4418 /* The call to addLogRecord is in renewLeaseDo */ 4419 return newDuration; 4420 } finally { 4421 concurrentObj.writeUnlock(); 4422 } 4423 }//end renewLease 4424 4425 /** 4426 * This methods renews all leases from a <code>LeaseMap</code>, 4427 * where each element of the map is a lease on a registration with 4428 * ID corresponding to an element of the <code>registrationIDs</code> 4429 * parameter. 4430 * <p> 4431 * This method is the "backend" server counterpart to the 4432 * <code>renewAll</code> method specified by the 4433 * <code>LeaseMap</code> interface, implemented in the 4434 * <code>org.apache.river.lease.AbstractLeaseMap</code> class, and 4435 * invoked by way of the <code>renewAll</code> method of the 4436 * <code>FiddlerLease</code> class; an instance of which is 4437 * returned by the <code>getLease</code> method of the 4438 * <code>LookupDiscoveryRegistration</code> proxy (an instance of 4439 * <code>FiddlerRegistration</code>) that is returned by this service 4440 * when a client requests a registration. 4441 * 4442 * @param registrationIDs array containing the unique identifiers assigned 4443 * to the each registration to which each lease 4444 * to be renewed corresponds 4445 * @param leaseIDs array containing the identifiers assigned by the 4446 * lease grantor to each lease being renewed 4447 * @param durations array containing the requested durations for 4448 * each lease being renewed 4449 * 4450 * @return an instance of FiddlerRenewResults containing data corresponding 4451 * to the results (granted durations or exceptions) of each 4452 * renewal attempt 4453 * 4454 * @throws java.rmi.NoSuchObjectException if this method is called during 4455 * service initialization or shutdown processing 4456 * 4457 * @throws java.rmi.RemoteException typically, this exception occurs when 4458 * there is a communication failure between the client and the 4459 * server. When this exception does occur, this method may or 4460 * may not have complete its processing successfully. 4461 * 4462 * @see net.jini.core.lease.LeaseMap#renewAll 4463 */ 4464 public FiddlerRenewResults renewLeases(Uuid[] registrationIDs, 4465 Uuid[] leaseIDs, 4466 long[] durations) 4467 throws NoSuchObjectException, RemoteException 4468 { 4469 readyState.check(); 4470 concurrentObj.priorityWriteLock(); 4471 try { 4472 return renewLeasesDo(registrationIDs, leaseIDs, durations); 4473 /* The call to addLogRecord is in renewLeasesDo */ 4474 } finally { 4475 concurrentObj.writeUnlock(); 4476 } 4477 }//end renewLeases 4478 4479 /** 4480 * This method is the "backend" server counterpart to the 4481 * <code>cancel</code> method specified by the <code>Lease</code> 4482 * interface and implemented in the <code>FiddlerLease</code> class; an 4483 * instance of which is returned by the <code>getLease</code> method 4484 * of the <code>LookupDiscoveryRegistration</code> proxy (an instance of 4485 * <code>FiddlerRegistration</code>) that is returned by this service 4486 * when a client requests a registration. 4487 * <p> 4488 * This method cancels the lease corresponding to the given 4489 * <code>registrationID</code> and <code>leaseID</code> parameters. 4490 * 4491 * The cancellation of a lease typically involves the modification of the 4492 * managed sets in the discovery manager, which usually involves starting 4493 * the discovery protocol. An IOException can occur when the discovery 4494 * protocol fails to start. When such an exception does occur, this 4495 * method registers an ERROR status attribute (along with a Comment 4496 * attribute describing the nature of the problem) to all lookup services 4497 * with which this service is registered. 4498 * 4499 * Administrative clients, as well as clients that use this service should 4500 * have registered for notification of the existence of this attribute. 4501 * 4502 * @param registrationID unique identifier assigned to the registration 4503 * to which the lease being cancelled corresponds 4504 * @param leaseID identifier assigned by the lease grantor to the 4505 * lease that is to be cancelled 4506 * 4507 * @throws net.jini.core.lease.UnknownLeaseException this exception occurs 4508 * when the lease being cancelled is unknown to the lease grantor. 4509 * 4510 * @throws java.rmi.NoSuchObjectException if this method is called during 4511 * service initialization or shutdown processing 4512 * 4513 * @throws java.rmi.RemoteException typically, this exception occurs when 4514 * there is a communication failure between the client and the 4515 * server. When this exception does occur, the lease may or may 4516 * not have been cancelled successfully. 4517 * 4518 * @see net.jini.core.lease.Lease#cancel 4519 */ 4520 public void cancelLease(Uuid registrationID, 4521 Uuid leaseID) 4522 throws UnknownLeaseException, NoSuchObjectException, RemoteException 4523 { 4524 readyState.check(); 4525 concurrentObj.writeLock(); 4526 try { 4527 RegistrationInfo regInfo 4528 = (RegistrationInfo)(registrationByID.get(registrationID)); 4529 if(regInfo == null) { 4530 throw new UnknownLeaseException 4531 ("\n Invalid registration ID on call to " 4532 +"cancelLease() method" 4533 +"\n The lease may have expired or been " 4534 +"cancelled"); 4535 }//endif 4536 /* Cancel the lease */ 4537 try { 4538 cancelLeaseDo(regInfo, leaseID); 4539 logInfoLease("Cancelled lease: ",registrationID,leaseID); 4540 } catch(IOException e) { 4541 String eStr = "Failure while cancelling the lease on " 4542 +"registration with ID = "+registrationID; 4543 if( problemLogger.isLoggable(Level.INFO) ) { 4544 problemLogger.log(Level.INFO, eStr, e); 4545 }//endif 4546 Entry[] errorAttrs = 4547 new Entry[] { new FiddlerStatus(StatusType.ERROR), 4548 new Comment(eStr) 4549 }; 4550 joinMgr.addAttributes(errorAttrs,true); 4551 } 4552 addLogRecord(new LeaseCancelledLogObj 4553 (regInfo.registrationID, leaseID)); 4554 } finally { 4555 concurrentObj.writeUnlock(); 4556 } 4557 }//end cancelLease 4558 4559 /** 4560 * Cancels all leases from a <code>LeaseMap</code>. 4561 * <p> 4562 * For each element in the <code>registrationIDs</code> parameter, 4563 * this method will cancel the corresponding element in the 4564 * <code>leaseIDs</code> parameter. 4565 * 4566 * @param registrationIDs array containing the unique identifiers assigned 4567 * to the each registration to which each lease 4568 * to be cancelled corresponds 4569 * @param leaseIDs array containing the identifiers assigned by the 4570 * lease grantor to each lease being cancelled 4571 * 4572 * @throws java.rmi.NoSuchObjectException if this method is called during 4573 * service initialization or shutdown processing 4574 * 4575 * @throws java.rmi.RemoteException typically, this exception occurs when 4576 * there is a communication failure between the client and the 4577 * server. When this exception does occur, this method may or 4578 * may not have complete its processing successfully. 4579 * 4580 * @return array consisting of any exceptions that may have occurred 4581 * while attempting to cancel one of the leases in the map. 4582 * 4583 * @see net.jini.core.lease.LeaseMap#cancelAll 4584 */ 4585 public Exception[] cancelLeases(Uuid[] registrationIDs, 4586 Uuid[] leaseIDs) 4587 throws NoSuchObjectException, RemoteException 4588 { 4589 readyState.check(); 4590 concurrentObj.writeLock(); 4591 try { 4592 /* don't bother to weed out unknown leases, so log first */ 4593 addLogRecord( new LeasesCancelledLogObj(registrationIDs,leaseIDs)); 4594 return cancelLeasesDo(registrationIDs, leaseIDs); 4595 } finally { 4596 concurrentObj.writeUnlock(); 4597 } 4598 }//end cancelLeases 4599 /* END org.apache.river.fiddler.proxy.Fiddler ----------------------------------- */ 4600 /* ************************* END Public Methods *********************** */ 4601 4602 /* **************** BEGIN Private Static Utility Methods ************** */ 4603 /** Return a new array containing the elements of the input array parameter 4604 * with the input element parameter appended to the end of the array. 4605 */ 4606 private static Object[] appendArray(Object[] array, Object elt) { 4607 int len = array.length; 4608 Object[] newArray = 4609 (Object[])Array.newInstance(array.getClass().getComponentType(), 4610 len + 1); 4611 System.arraycopy(array, 0, newArray, 0, len); 4612 newArray[len] = elt; 4613 return newArray; 4614 }//end appendArray 4615 4616 /** Bounds the duration by the value of the <code>bound</code> parameter, 4617 * and checks for negative value. 4618 */ 4619 private static long applyBoundToLeaseDuration(long leaseDuration, 4620 long bound) 4621 { 4622 long newLeaseDuration = leaseDuration; 4623 if ( (leaseDuration == Lease.ANY) || (leaseDuration > bound) ) { 4624 newLeaseDuration = bound; 4625 } else if (leaseDuration < 0) { 4626 throw new IllegalArgumentException("negative lease duration"); 4627 }//endif 4628 return newLeaseDuration; 4629 }//end applyBoundToLeaseDuration 4630 4631 /** Determines if any element in the input array is null. 4632 * @param arr Object array to examine for null elements 4633 * @return true if any element is found to be null, false otherwise. 4634 * Note that this means that if the array itself is null 4635 * or has a non-positive length, false is returned (because 4636 * the input parameter still does not contain a null element). 4637 */ 4638 private static boolean containsNullElement(Object[] arr) { 4639 if( (arr == null) || (arr.length == 0) ) return false; 4640 for(int i=0;i<arr.length;i++) { 4641 if(arr[i] == null) return true; 4642 }//end loop 4643 return false; 4644 }//end containsNullElement 4645 4646 /** This method determines if a particular registration (regInfo) is 4647 * interested in discovering, through group discovery, the registrar 4648 * belonging to a given set of member groups. 4649 * 4650 * @param regGroups array of the member groups from the registrar 4651 * (cannot be null) 4652 * @param desiredGroups groups the registration wishes to discover 4653 * (can be null = ALL_GROUPS) 4654 * 4655 * @return <code>true</code> if at least one of the registrar's member 4656 * groups is contained in the registration's set of groups to 4657 * discover; <code>false</code> otherwise 4658 */ 4659 private static boolean interested(String[] regGroups, Set desiredGroups) { 4660 if(desiredGroups == null) return true; 4661 if(desiredGroups.size() == 0) return false; 4662 for(int i=0;i<regGroups.length;i++) { 4663 if( desiredGroups.contains(regGroups[i]) ) return true; 4664 }//end loop 4665 return false; 4666 }//end interested 4667 4668 /** This method determines if a particular registration (regInfo) is 4669 * interested in discovering, through either locator discovery 4670 * or group discovery, the registrar having a given locator and 4671 * belonging to a given set of member groups. 4672 * 4673 * @param regLoc locator of the registrar (cannot be null) 4674 * @param regGroups array of the member groups from the registrar 4675 * (cannot be null) 4676 * @param desiredLocators locators the registration wishes to discover 4677 * @param desiredGroups groups the registration wishes to discover 4678 * (can be null = ALL_GROUPS) 4679 * 4680 * @return <code>true</code> if either the registrar's locator is 4681 * contained in the registration's set of locators to discover, 4682 * or at least one of the registrar's member groups is contained 4683 * in the registration's set of groups to discover; 4684 * <code>false</code> otherwise 4685 */ 4686 private static boolean interested(LookupLocator regLoc, 4687 String[] regGroups, 4688 Set desiredLocators, 4689 Set desiredGroups) 4690 { 4691 if(locSetContainsLoc(desiredLocators,regLoc)) return true; 4692 return interested(regGroups,desiredGroups); 4693 }//end interested 4694 4695 /** This method returns a mapping in which the key values are registrars, 4696 * and the map values are the member groups of the corresponding 4697 * registrar key. The registrar and member groups from the input map 4698 * are selected to be included in the returned mapping if and only if 4699 * the key value under consideration is a registrar that belongs to none 4700 * of the desired groups of the given registration (<code>regInfo</code>). 4701 * That is, the registrars referenced in the returned mapping are the 4702 * registrars that are no longer of interest - through group discovery 4703 * - to the given registration. 4704 * 4705 * @param regMap map whose key values are registrars, and whose map 4706 * values are data structures of type 4707 * <code>LocatorGroupsStruct</code> that contain the 4708 * associated locator and member groups of the 4709 * corresponding registrar key; the elements of the 4710 * return map are selected from this mapping 4711 * @param regInfo the data structure record corresponding to the 4712 * registration whose groups-to-discover will be used 4713 * to select the elements from <code>regMap</code> to 4714 * include in the return mapping 4715 * 4716 * @return a registrar-to-groups map in which each registrar in the map 4717 * is from the <code>regMap</code> parameter, and belongs to none 4718 * of the desired groups referenced in the <code>regInfo</code> 4719 * parameter 4720 */ 4721 private static Map getUndesiredRegsByGroup(Map regMap, 4722 RegistrationInfo regInfo) 4723 { 4724 Set<String> desiredGroups = regInfo.groups; 4725 HashMap undesiredRegMap = new HashMap(regMap.size()); 4726 Set eSet = regMap.entrySet(); 4727 for(Iterator itr = eSet.iterator(); itr.hasNext(); ) { 4728 Map.Entry pair = (Map.Entry)itr.next(); 4729 String[] regGroups = ((LocatorGroupsStruct)pair.getValue()).groups; 4730 if( !interested(regGroups,desiredGroups) ) { 4731 undesiredRegMap.put((ServiceRegistrar)pair.getKey(),regGroups); 4732 }//endif 4733 }//end loop 4734 return undesiredRegMap; 4735 }//end getUndesiredRegsByGroup 4736 4737 /** This method returns a subset of the given registrar-to-locators 4738 * mapping (<code>regMap</code>). An element of the given mapping is 4739 * selected to be included in the returned mapping if and only if 4740 * the key value of the element is a registrar whose locator equals 4741 * none of the desired locators of the given registration 4742 * (<code>regInfo</code>). That is, the registrars referenced in 4743 * the returned mapping are the registrars that are no longer of 4744 * interest - through locator discovery - to the given registration. 4745 * 4746 * This method returns a mapping in which the key values are registrars, 4747 * and the map values are the locators of the corresponding registrar 4748 * key. The registrar and locators from the input map are selected to 4749 * be included in the returned mapping if and only if the key value 4750 * under consideration is a registrar whose locator equals none of the 4751 * desired locators of the given registration (<code>regInfo</code>). 4752 * That is, the registrars referenced in the returned mapping are the 4753 * registrars that are no longer of interest - through locator discovery 4754 * - to the given registration. 4755 * 4756 * @param regMap map whose key values are registrars, and whose map 4757 * values are data structures of type 4758 * <code>LocatorGroupsStruct</code> that contain the 4759 * associated locator and member groups of the 4760 * corresponding registrar key; the elements of the 4761 * return map are selected from this mapping 4762 * @param regInfo the data structure record corresponding to the 4763 * registration whose locators-to-discover will be used 4764 * to select the elements from <code>regMap</code> to 4765 * include in the return mapping 4766 * 4767 * @return a registrars-to-locators map in which each registrar key in 4768 * the map is from the <code>regMap</code> parameter, and has 4769 * a locator equal to none of the desired locators referenced 4770 * in the <code>regInfo</code> parameter 4771 */ 4772 private static Map getUndesiredRegsByLocator(Map regMap, 4773 RegistrationInfo regInfo) 4774 { 4775 Set<LookupLocator> desiredLocators = regInfo.locators; 4776 HashMap undesiredRegMap = new HashMap(regMap.size()); 4777 Set eSet = regMap.entrySet(); 4778 for(Iterator itr = eSet.iterator(); itr.hasNext(); ) { 4779 Map.Entry pair = (Map.Entry)itr.next(); 4780 LookupLocator regLocator 4781 = ((LocatorGroupsStruct)pair.getValue()).locator; 4782 if(!locSetContainsLoc(desiredLocators,regLocator)) { 4783 undesiredRegMap.put((ServiceRegistrar)pair.getKey(), 4784 regLocator); 4785 }//endif 4786 }//end loop 4787 return undesiredRegMap; 4788 }//end getUndesiredRegsByLocator 4789 4790 /** 4791 * Marshals each element of the <code>Entry[]</code> array parameter. 4792 * This method is <code>static</code> so that it may called from 4793 * the <code>static</code> <code>LogRecord</code> classes when a set 4794 * of attributes is being logged to persistent storage. 4795 * 4796 * @param fiddlerImpl reference to the current instance of this service 4797 * @param attrs <code>Entry[]</code> array consisting of the 4798 * attributes to marshal 4799 * @return array of <code>MarshalledObject[]</code>, where each element 4800 * corresponds to an attribute in marshalled form 4801 */ 4802 private static MarshalledObject[] marshalAttributes 4803 (FiddlerImpl fiddlerImpl, 4804 Entry[] attrs) 4805 { 4806 if(attrs == null) return new MarshalledObject[0]; 4807 List<MarshalledObject> marshalledAttrs = new ArrayList<MarshalledObject>(); 4808 for(int i=0;i<attrs.length;i++) { 4809 /* Do not let an attribute problem prevent the service from 4810 * continuing to operate 4811 */ 4812 try { 4813 marshalledAttrs.add( 4814 new MarshalledInstance(attrs[i]).convertToMarshalledObject()); 4815 } catch(Throwable e) { 4816 if( problemLogger.isLoggable(Level.INFO) ) { 4817 problemLogger.log(Level.INFO, 4818 "Error while marshalling attribute["+i 4819 +"] ("+attrs[i]+")", e); 4820 }//endif 4821 } 4822 }//end loop 4823 return ((MarshalledObject[])(marshalledAttrs.toArray 4824 (new MarshalledObject[marshalledAttrs.size()]))); 4825 }//end marshalAttributes 4826 4827 /** 4828 * Unmarshals each element of the <code>MarshalledObject[]</code> array 4829 * parameter. This method is <code>static</code> so that it may called 4830 * from the <code>static</code> <code>LogRecord</code> classes when a 4831 * set of attributes is being recovered from persistent storage. 4832 * 4833 * @param fiddlerImpl reference to the current instance of this service 4834 * @param marshalledAttrs <code>MarshalledObject[]</code> array consisting 4835 * of the attributes to unmarshal 4836 * @return array of <code>Entry[]</code>, where each element corresponds 4837 * to an attribute that was successfully unmarshalled 4838 */ 4839 private static Entry[] unmarshalAttributes 4840 (FiddlerImpl fiddlerImpl, 4841 MarshalledObject[] marshalledAttrs) 4842 { 4843 if(marshalledAttrs == null) return new Entry[0]; 4844 ArrayList attrs = new ArrayList(); 4845 for(int i=0;i<marshalledAttrs.length;i++) { 4846 /* Do not let an attribute problem prevent the service from 4847 * continuing to operate 4848 */ 4849 try { 4850 attrs.add( (Entry)( new MarshalledInstance(marshalledAttrs[i]).get(false) ) ); 4851 } catch(Throwable e) { 4852 if( problemLogger.isLoggable(Level.INFO) ) { 4853 problemLogger.log(Level.INFO, 4854 "Error while unmarshalling attribute["+i 4855 +"]", e); 4856 }//endif 4857 } 4858 }//end loop 4859 return ((Entry[])(attrs.toArray(new Entry[attrs.size()]))); 4860 }//end unmarshalAttributes 4861 4862 /** Using the given <code>ProxyPreparer</code>, attempts to prepare each 4863 * element of the given <code>LookupLocator</code> array; replacing the 4864 * original element of the array with the result of the call to the 4865 * method <code>ProxyPreparer.prepareProxy</code>. If any attempt to 4866 * prepare an element of the given array fails due to an exception, 4867 * this method will propagate that exception. 4868 * 4869 * This method is a convenience method that is typically used to 4870 * prepare new locators the service should discover and join that 4871 * are inserted into, or removed from, the service's state through 4872 * the use of one of the following methods: 4873 * <ul><li> <code>addLookupLocators</code> 4874 * <li> <code>setLookupLocators</code> 4875 * <li> <code>removeLookupLocators</code> 4876 * <li> <code>addLocators</code> 4877 * <li> <code>setLocators</code> 4878 * <li> <code>removeLocators</code> 4879 * </ul> 4880 * 4881 * @param preparer the preparer to use to prepare each element of the 4882 * input array 4883 * @param locators array of <code>LookupLocator</code> instances in which 4884 * each element will be prepared. 4885 * 4886 * @throws RemoteException when preparation of any of the elements 4887 * of the input array fails because of a 4888 * <code>RemoteException</code> 4889 * @throws SecurityException when preparation of any of the elements 4890 * of the input array fails because of a 4891 * <code>SecurityException</code> 4892 */ 4893 private static void prepareNewLocators(ProxyPreparer preparer, 4894 LookupLocator[] locators) 4895 throws RemoteException 4896 { 4897 for (int i=0; i<locators.length; i++) { 4898 locators[i] = (LookupLocator)preparer.prepareProxy(locators[i]); 4899 }//end loop 4900 }//end prepareNewLocators 4901 4902 /** Using the given <code>ProxyPreparer</code>, attempts to prepare each 4903 * element of the given <code>LookupLocator</code> array; and returns 4904 * a new array containing the prepared locators. If any attempt to 4905 * prepare an element of the given array fails due to an exception, 4906 * this method will skip to the next locator in that input array. 4907 * 4908 * This method is a convenience method that is typically used to 4909 * re-prepare the previously prepared locators that are retrieved 4910 * from the service's persisted state during recovery. 4911 * 4912 * @param preparer the preparer to use to prepare each element of the 4913 * input array 4914 * @param locators array of <code>LookupLocator</code> instances in which 4915 * each element will be prepared. 4916 * 4917 * @return array of <code>LookupLocator</code> instances in which each 4918 * element of the returned array is the result of successful proxy 4919 * preparation of the corresponding element of the input array 4920 */ 4921 private static LookupLocator[] prepareOldLocators(ProxyPreparer preparer, 4922 LookupLocator[] locators) 4923 { 4924 ArrayList locsList = new ArrayList(locators.length); 4925 for(int i=0; i<locators.length; i++) { 4926 try { 4927 locsList.add(preparer.prepareProxy(locators[i]) ); 4928 } catch(Throwable e) { 4929 if( problemLogger.isLoggable(Level.INFO) ) { 4930 problemLogger.log(Level.INFO,"failure preparing recovered " 4931 +"lookup locator["+i+"]", e); 4932 }//endif 4933 } 4934 }//end loop 4935 if(locators.length != locsList.size()) { 4936 if( problemLogger.isLoggable(Levels.HANDLED) ) { 4937 problemLogger.log(Levels.HANDLED, 4938 "number of requested recovered " 4939 +"lookup locators = "+locators.length); 4940 problemLogger.log(Levels.HANDLED, "number of successfully " 4941 +"prepared recovered lookup locators = " 4942 +locsList.size()); 4943 for(int i=0; i<locsList.size(); i++) { 4944 problemLogger.log(Levels.HANDLED, "successfully prepared " 4945 +"recovered lookup locator = " 4946 +locsList.get(i)); 4947 }//end loop 4948 }//endif 4949 }//endif 4950 return ( (LookupLocator[])locsList.toArray 4951 (new LookupLocator[locsList.size()]) ); 4952 }//end prepareOldLocators 4953 4954 /** Using the given <code>ProxyPreparer</code>, attempts to prepare each 4955 * element of the given <code>Set</code> of <code>LookupLocator</code> 4956 * instances; and returns a new <code>Set</code> containing the prepared 4957 * locators. If any attempt to prepare an element of the given 4958 * <code>Set</code> fails due to an exception, this method will skip 4959 * to the next locator in that input <code>Set</code>. 4960 * 4961 * This method is a convenience method that is typically used to 4962 * re-prepare the previously prepared locators that are retrieved 4963 * from the service's persisted state during recovery. 4964 * 4965 * @param preparer the preparer to use to prepare each element of the 4966 * input array 4967 * @param locators <code>Set</code> of <code>LookupLocator</code> 4968 * instances in which each element will be prepared. 4969 * 4970 * @return <code>Set</code> of <code>LookupLocator</code> instances in 4971 * which each element of the returned <code>Set</code> is the 4972 * result of successful proxy preparation of the corresponding 4973 * element of the input <code>Set</code> 4974 */ 4975 private static Set prepareOldLocators(ProxyPreparer preparer, 4976 Set locators) 4977 { 4978 Set locSet = new HashSet(locators.size()); 4979 LookupLocator[] locsArray = 4980 prepareOldLocators( preparer, 4981 (LookupLocator[])locators.toArray 4982 (new LookupLocator[locators.size()]) ); 4983 for(int i=0; i<locsArray.length; i++) { 4984 locSet.add(locsArray[i]); 4985 }//end loop 4986 return locSet; 4987 }//end prepareOldLocators 4988 4989 /** Searches the given set of locators for the given individual locator, 4990 * returning <code>true</code> if the indicated locator is found in the 4991 * set; <code>false</code> otherwise. 4992 * 4993 * This method is a convenience method that is called instead of calling 4994 * only the <code>contains</code> method on the <code>Set</code> 4995 * parameter. This is necessary because the <code>equals</code> method 4996 * on <code>LookupLocator</code> performs a simple <code>String</code> 4997 * compare of the host names referenced by the locators being compared. 4998 * Such a comparison can result in a "false negative" when the hostname 4999 * returned by a remote system provides a fully-qualified hostname 5000 * (ex. "myhost.subdomain.mycompany.com"), but clients of this service 5001 * indicate interest in a locator using only the unqualified hostname 5002 * (ex. "myhost"). In this case, both host names are legal and 5003 * functionally equivalent, but the <code>equals</code> method on 5004 * <code>LookupLocator</code> will interpret them as unequal; resulting 5005 * in failure to discover locators that actually should be discovered. 5006 * 5007 * To address the problem described above, this method will do the 5008 * following when attempting to determine whether the given locator 5009 * is contained in the given set of locators: 5010 * 5011 * 1. Apply <code>Set</code>.<code>contains</code> which uses 5012 * <code>LookupLocator</code>.<code>equals</code> to determine 5013 * if the given locator is an element of the given set of locators. 5014 * 2. If the <code>Set</code>.<code>contains</code> method returns 5015 * <code>false</code>, then iterate through the elements of the 5016 * given set, retrieving and comparing the port and 5017 * <code>InetAddress</code> of each element to the port and 5018 * <code>InetAddress</code> of the given locator. 5019 * 5020 * @param locSet this method will determine whether or not the given 5021 * locator is contained in this <code>Set</code> of 5022 * <code>LookupLocator</code>s. 5023 * @param loc this method will determine whether or not this 5024 * <code>LookupLocator</code> is contained in the given set. 5025 * 5026 * @return <code>true</code> if the given set of locators contains the 5027 * given locator; <code>false</code> otherwise. 5028 */ 5029 private static boolean locSetContainsLoc(Set locSet, LookupLocator loc) { 5030 if( locSet.contains(loc) ) return true;//try LookupLocator.equals first 5031 /* Set containment test failed. Iterate through the set. */ 5032 int port0 = loc.getPort(); 5033 InetAddress addr0 = null; 5034 for(Iterator itr = locSet.iterator(); itr.hasNext(); ) { 5035 LookupLocator nextLoc = (LookupLocator)itr.next(); 5036 if(nextLoc.getPort() != port0) continue;//try next port in set 5037 if(addr0 == null) {//only need to retrieve addr0 once 5038 try { 5039 addr0 = InetAddress.getByName(loc.getHost()); 5040 } catch(Exception e) { 5041 problemLogger.log(Levels.HANDLED, 5042 "problem retrieving address by name", e); 5043 return false; 5044 } 5045 }//endif 5046 InetAddress addr1 = null; 5047 try { 5048 addr1 = InetAddress.getByName(nextLoc.getHost()); 5049 } catch(Exception e) { 5050 problemLogger.log(Level.FINEST, 5051 "problem retrieving address by name", e); 5052 continue;//try next address in set 5053 } 5054 if( addr1.equals(addr0) ) return true; 5055 }//end loop 5056 return false; 5057 }//end locSetContainsLoc 5058 5059 5060 /** Common entry point for initialization of the service in any of its 5061 * possible modes: transient, non-activatable-persistent, or 5062 * activatable-persistent; with or without performing a JAAS login. 5063 */ 5064 private static FiddlerInit init(String[] configArgs, boolean persistent) 5065 throws IOException, ConfigurationException, LoginException{ 5066 try { 5067 return init(configArgs, persistent, null); 5068 } catch (ActivationException e){ 5069 // swallow will never happen because it's null. 5070 return null; 5071 } 5072 } 5073 5074 private static FiddlerInit init(String[] configArgs, 5075 boolean persistent, 5076 ActivationID activeID) 5077 throws IOException, 5078 ConfigurationException, 5079 LoginException, 5080 ActivationException 5081 { 5082 5083 Configuration config = ConfigurationProvider.getInstance 5084 ( configArgs, 5085 (FiddlerImpl.class).getClassLoader() ); 5086 5087 LoginContext loginContext = (LoginContext)config.getEntry(COMPONENT_NAME, 5088 "loginContext", 5089 LoginContext.class, 5090 null); 5091 if(loginContext != null) { 5092 return initWithLogin(config, persistent, loginContext, activeID); 5093 } else { 5094 return new FiddlerInit(config, persistent, activeID, null); 5095 }//endif 5096 5097 }//end init 5098 5099 /** Initialization with JAAS login as the <code>Subject</code> referenced 5100 * in the given <code>loginContext</code>. 5101 */ 5102 private static FiddlerInit initWithLogin( final Configuration config, 5103 final boolean persistent, 5104 final LoginContext loginContext, 5105 final ActivationID activeID) 5106 throws IOException, 5107 ConfigurationException, 5108 LoginException, 5109 ActivationException 5110 { 5111 loginContext.login(); 5112 try { 5113 return Subject.doAsPrivileged( loginContext.getSubject(), 5114 new PrivilegedExceptionAction<FiddlerInit>() { 5115 public FiddlerInit run() throws Exception { 5116 return new FiddlerInit(config, persistent, activeID, loginContext); 5117 }//end run 5118 }, 5119 null );//end doAsPrivileged 5120 } catch (Throwable e) { 5121 if(e instanceof PrivilegedExceptionAction) e = e.getCause(); 5122 if(e instanceof IOException) throw (IOException)e; 5123 if(e instanceof ConfigurationException) 5124 throw (ConfigurationException)e; 5125 if (e instanceof ActivationException) throw (ActivationException) e; 5126 throw new RuntimeException(e); 5127 } 5128 }//end initWithLogin 5129 5130 /* **************** END Private Static Utility Methods ***************** */ 5131 5132 /* BEGIN public start method*/ 5133 public void start() throws IOException, ActivationException, ConfigurationException, LoginException, ClassNotFoundException 5134 { 5135 synchronized (this){ 5136 if (started) return; 5137 started = true; 5138 } 5139 concurrentObj.writeLock(); 5140 try { 5141 AccessController.doPrivileged(new PrivilegedExceptionAction(){ 5142 5143 @Override 5144 public Object run() throws Exception { 5145 if (persistent){ 5146 logHandler.setFiddler(FiddlerImpl.this); 5147 inRecovery = true; 5148 log.recover(); 5149 inRecovery = false; 5150 } 5151 5152 /* For the two persistent versions of this service (activatable and 5153 * non-activatable), state recovery is complete. For the non-persistent 5154 * version of this service, no state recovery occurred (because it 5155 * wasn't necessary). 5156 * 5157 * For the two persistent versions, there is a circumstance in which 5158 * 'one time', initial items must be retrieved from the configuration: 5159 * when the service is started for the very first time. For the 5160 * non-persistent version, those items will be retrieved every time 5161 * the service is started. 5162 * 5163 * The flag 'initialStartup' is used below to determine whether 5164 * or not to retrieve the initial configuration items. This is the 5165 * only purpose for that flag. 5166 * 5167 * For either persistent version of the service, the flag's value 5168 * will be changed to false during the startup process only when 5169 * there already exists a 'snapshot' of the service's state from 5170 * a previous run. This is because the flag's value is only 5171 * changed during the recovery of the snapshot (see the method 5172 * recoverSnapshot()). Note that the only time such a snapshot 5173 * should NOT already exist at startup, is when the service is 5174 * being started for the very first time. Thus, when either 5175 * persistent version of the service is started for the first 5176 * time, the service's configuration is consulted for the initial 5177 * values of the items below; otherwise, when the service is being 5178 * re-started (after a crash for example), the values used for 5179 * those items will be the values retrieved above during recovery 5180 * of the service's persistent state. 5181 * 5182 * With respect to the non-persistent version of the service, the 5183 * values of the items below will always be retrieved at startup. 5184 * This is because the non-persistent version of the service never 5185 * attempts to recover previously stored state; thus, the flag's 5186 * value will never change. Note that this will be true even if a 5187 * snapshot exists from a previous run of one of the persistent 5188 * versions of the service. 5189 * 5190 * The service's Uuid is also handled here. 5191 */ 5192 if(initialStartup) { 5193 if(log != null) { 5194 snapshotWt = ((Float)config.getEntry 5195 (FiddlerImpl.COMPONENT_NAME, 5196 "initialPersistenceSnapshotWeight", 5197 float.class, 5198 new Float(snapshotWt))).floatValue(); 5199 snapshotThresh = 5200 Config.getIntEntry 5201 (config, 5202 FiddlerImpl.COMPONENT_NAME, 5203 "initialPersistenceSnapshotThreshold", 5204 snapshotThresh, 0, Integer.MAX_VALUE); 5205 }//endif(log != null) 5206 leaseBound = Config.getLongEntry(config, 5207 FiddlerImpl.COMPONENT_NAME, 5208 "initialLeaseBound", 5209 leaseBound, 0, Long.MAX_VALUE); 5210 /* Get any additional attributes with which to associate this 5211 * service when registering it with any lookup services. 5212 */ 5213 Entry[] initAttrs = (Entry[])config.getEntry 5214 (FiddlerImpl.COMPONENT_NAME, 5215 "initialLookupAttributes", 5216 Entry[].class, 5217 null ); 5218 if(initAttrs != null) { 5219 ArrayList attrsList 5220 = new ArrayList(thisServicesAttrs.length+initAttrs.length); 5221 for(int i=0;i<thisServicesAttrs.length;i++) { 5222 attrsList.add(thisServicesAttrs[i]); 5223 }//end loop 5224 for(int i=0;i<initAttrs.length;i++) { 5225 attrsList.add(initAttrs[i]); 5226 }//end loop 5227 thisServicesAttrs = (Entry[])attrsList.toArray 5228 (new Entry[attrsList.size()]); 5229 }//endif(initAttrs != null) 5230 5231 /* Get the initial groups this service should join. */ 5232 thisServicesGroups = 5233 (String[])config.getEntry(FiddlerImpl.COMPONENT_NAME, 5234 "initialLookupGroups", 5235 String[].class, 5236 thisServicesGroups); 5237 /* Get the initial locators this service should join. */ 5238 thisServicesLocators = 5239 (LookupLocator[])config.getEntry(FiddlerImpl.COMPONENT_NAME, 5240 "initialLookupLocators", 5241 LookupLocator[].class, 5242 new LookupLocator[0]); 5243 if(thisServicesLocators == null) { 5244 thisServicesLocators = new LookupLocator[0]; 5245 }//endif 5246 5247 /* Generate the private, universally unique (over space and time) 5248 * ID that will be used by the outer proxy to test for equality 5249 * with other proxies. 5250 */ 5251 proxyID = UuidFactory.generate(); 5252 }//endif(initialStartup) 5253 5254 /* The proxyID should never be null at this point. It should have 5255 * been either recovered from the persisted state, or generated above. 5256 */ 5257 if(proxyID == null) throw new NullPointerException("proxyID == null"); 5258 /* Take a snapshot of the current state to "clean up" the log file, 5259 * and to record the items set above. 5260 */ 5261 if(log != null) log.snapshot(); 5262 /* The service ID used to register this service with lookup services 5263 * is always derived from the proxyID that is associated with the 5264 * service for the lifetime of the service. 5265 */ 5266 serviceID = new ServiceID(proxyID.getMostSignificantBits(), 5267 proxyID.getLeastSignificantBits()); 5268 5269 /* Export this service */ 5270 innerProxy = (Fiddler)serverExporter.export(FiddlerImpl.this); 5271 5272 /* Create the outer (smart) proxy that is registered with lookups */ 5273 outerProxy = FiddlerProxy.createServiceProxy(innerProxy, proxyID); 5274 /* Create the proxy that can be used to administer this service */ 5275 adminProxy = FiddlerAdminProxy.createAdminProxy(innerProxy, proxyID); 5276 5277 /* Start the discovery mechanism for all recovered registrations */ 5278 discoveryMgr.addDiscoveryListener(discoveryListener); 5279 5280 /* Advertise the services provided by this entity */ 5281 joinMgr = new JoinManager(outerProxy, thisServicesAttrs, 5282 serviceID, joinMgrLDM, null, 5283 config); 5284 ((DiscoveryLocatorManagement)joinMgrLDM).setLocators 5285 (thisServicesLocators); 5286 ((DiscoveryGroupManagement)joinMgrLDM).setGroups(thisServicesGroups); 5287 5288 /* start up all the daemon threads */ 5289 leaseExpireThread.start(); 5290 if(log != null) { 5291 snapshotThread.start(); 5292 } 5293 logInfoStartup(); 5294 readyState.ready(); 5295 return null; 5296 } 5297 5298 } , context); 5299 } catch (PrivilegedActionException e) { 5300 Throwable t = e.getCause(); 5301 cleanupInitFailure(); 5302 handleActivatableInitThrowable(t); 5303 } finally { 5304 logHandler = null; 5305 concurrentObj.writeUnlock(); 5306 } 5307 } 5308 /* END public start method */ 5309 5310 /* BEGIN Private Shutdown Methods -------------------------------------- */ 5311 /* Called in the constructor when failure occurs during the initialization 5312 * process. Un-does any work that may have already been completed; for 5313 * example, un-exports the service if it has already been exported, 5314 * terminates any threads that may have been started, etc. 5315 */ 5316 private void cleanupInitFailure() { 5317 if(innerProxy != null) { 5318 try { 5319 serverExporter.unexport(true); 5320 } catch(Throwable t) { } 5321 }//endif 5322 5323 if(executorService != null) { 5324 try { 5325 executorService.shutdown(); 5326 } catch(Throwable t) { } 5327 }//endif 5328 5329 if(joinMgr != null) { 5330 try { 5331 joinMgr.terminate(); 5332 } catch(Throwable t) { } 5333 }//endif 5334 5335 if(joinMgrLDM != null) { 5336 try { 5337 joinMgrLDM.terminate(); 5338 } catch(Throwable t) { } 5339 }//endif 5340 5341 if(discoveryMgr != null) { 5342 try { 5343 discoveryMgr.terminate(); 5344 } catch(Throwable t) { } 5345 }//endif 5346 5347 if(leaseExpireThread != null) { 5348 try { 5349 leaseExpireThread.interrupt(); 5350 leaseExpireThread.join(); 5351 } catch(Throwable t) { } 5352 }//endif 5353 5354 if(snapshotThread != null) { 5355 try { 5356 snapshotThread.interrupt(); 5357 snapshotThread.join(); 5358 } catch(Throwable t) { } 5359 }//endif 5360 }//end cleanupInitFailure 5361 5362 /* Convenience method called in the constructor or the activatable version 5363 * of this service when failure occurs during the initialization process. 5364 * Logs and rethrows the given <code>Throwable</code> so the constructor 5365 * doesn't have to. 5366 */ 5367 private void handleActivatableInitThrowable(Throwable t) 5368 throws IOException, 5369 ActivationException, 5370 ConfigurationException, 5371 LoginException, 5372 ClassNotFoundException 5373 { 5374 handleInitThrowable(t); 5375 if (t instanceof ActivationException) { 5376 throw (ActivationException)t; 5377 } else if (t instanceof ClassNotFoundException) { 5378 /* instanceof LoginException would have already been rethown so wasn't 5379 * reachable I suspect ClassNotFoundException is what the implementer wanted. 5380 */ 5381 throw (ClassNotFoundException)t; 5382 } else { 5383 throw new AssertionError(t); 5384 }//endif 5385 }//end handleInitThrowable 5386 5387 /* Convenience method called in the constructor or the non-activatable 5388 * version of this service when failure occurs during the initialization 5389 * process. Logs and rethrows the given <code>Throwable</code> so the 5390 * constructor doesn't have to. 5391 */ 5392 private void handleInitThrowable(Throwable t) 5393 throws IOException, 5394 ConfigurationException, 5395 LoginException 5396 { 5397 problemLogger.log(Level.SEVERE, "cannot initialize the service", t); 5398 if (t instanceof IOException) { 5399 throw (IOException)t; 5400 } else if (t instanceof ConfigurationException) { 5401 throw (ConfigurationException)t; 5402 } else if (t instanceof LoginException) { 5403 throw (LoginException)t; 5404 } else if (t instanceof RuntimeException) { 5405 throw (RuntimeException)t; 5406 } else if (t instanceof Error) { 5407 throw (Error)t; 5408 }//endif 5409 }//end handleInitThrowable 5410 5411 /** 5412 * Called by the public method <code>destroy</code> as well as by the 5413 * <code>apply</code> method in the various LogObj classes that, 5414 * during recovery, modify the managed sets of the discovery manager; 5415 * and, while doing so, experience an IOException when the multicast 5416 * request protocol fails to start during recovery (an un-recoverable 5417 * exception). 5418 * 5419 * This method destroys the lookup discovery service, if possible, 5420 * including its persistent storage. This method spawns a separate 5421 * thread to do the actual work asynchronously, so a successful 5422 * return from this method usually does not mean that the service 5423 * has been destroyed. 5424 * 5425 * @see org.apache.river.fiddler.proxy.FiddlerImpl#destroy 5426 */ 5427 private void destroyDo() { 5428 (new DestroyThread()).start(); 5429 }//end destroyDo 5430 /* END Private Shutdown Methods ---------------------------------------- */ 5431 5432 /* BEGIN Private Registration Methods ---------------------------------- */ 5433 /** 5434 * This method is called by the public method <code>register</code>. 5435 * This method creates a registration object that is an instance of 5436 * <code>FiddlerRegistration</code> which implements the interface 5437 * <code>LookupDiscoveryRegistration</code>, and acts as a proxy to the 5438 * registration-related methods of the backend server of the Fiddler 5439 * implementation of the lookup discovery service. 5440 * <p> 5441 * This method also associates with the registration all information 5442 * needed by the registration to participate in the lookup discovery 5443 * service, information such as: IDs, lease information, event information. 5444 * 5445 * @param groups names of groups whose members are the lookup 5446 * services to discover. 5447 * @param locators instances of LookupLocator, each corresponding to 5448 * a specific lookup service to discover. 5449 * @param listener the entity that will receive events notifying the 5450 * registration that a lookup service of interest has 5451 * been discovered. 5452 * @param handback the object that will be included in every 5453 * notification event sent to the registered listener. 5454 * @param leaseDuration long value representing the amount of time (in 5455 * milliseconds) for which the resources of the 5456 * lookup discovery service are being requested. 5457 * 5458 * @return an instance of FiddlerRegistration which implements the 5459 * LookupDiscoveryRegistration interface, and acts as a proxy 5460 * to the registration-related methods of the backend server 5461 * of the Fiddler implementation of the lookup discovery service 5462 * 5463 * @throws java.io.IOException this exception occurs when the multicast 5464 * request protocol fails to start. 5465 * 5466 * @throws java.rmi.RemoteException this exception occurs when the 5467 * attempt to prepare the listener fails due to a 5468 * <code>RemoteException</code> 5469 * 5470 * @throws java.lang.SecurityException this exception occurs when the 5471 * attempt to prepare the listener fails due to a 5472 * <code>SecurityException</code> 5473 * 5474 * @see org.apache.river.fiddler.proxy.FiddlerImpl#register 5475 */ 5476 private LookupDiscoveryRegistration registerDo 5477 (String[] groups, 5478 LookupLocator[] locators, 5479 RemoteEventListener listener, 5480 MarshalledObject handback, 5481 long leaseDuration) 5482 throws RemoteException, 5483 IOException 5484 { 5485 /* Input okay. Create the registration and associated information */ 5486 long curTime = System.currentTimeMillis(); 5487 leaseDuration = applyBoundToLeaseDuration(leaseDuration, 5488 leaseBound); 5489 Uuid regID = UuidFactory.generate(); 5490 Uuid leaseID = regID;//use same ID since Reg "wraps" the lease 5491 long expiration = curTime + leaseDuration; 5492 5493 /* Prepare the new listener */ 5494 listener = (RemoteEventListener)listenerPreparer.prepareProxy 5495 (listener); 5496 RegistrationInfo regInfo = new RegistrationInfo( regID, 5497 groups,locators, 5498 leaseID,expiration, 5499 curEventID,handback, 5500 listener ); 5501 curEventID++; 5502 addRegistration(regInfo); 5503 logInfoRegistration("\nadded registration: registrationID = ",regID); 5504 addLogRecord(new RegistrationGrantedLogObj(regInfo)); 5505 /* Queue task for sending a discovered event */ 5506 executorService.execute(new NewRegistrationTask(regInfo)); 5507 /* See if the expire thread needs to wake up earlier */ 5508 if (expiration < minExpiration) { 5509 minExpiration = expiration; 5510 leaseExpireThreadSyncObj.signal(); 5511 // concurrentObj.waiterNotify(leaseExpireThreadSyncObj); 5512 } 5513 FiddlerLease regLease = 5514 FiddlerLease.createLease 5515 (innerProxy, proxyID, regID, leaseID, expiration); 5516 EventRegistration eventReg = new EventRegistration( regInfo.eventID, 5517 outerProxy, 5518 regLease, 5519 regInfo.seqNum ); 5520 logInfoGroups(); 5521 logInfoLocators(); 5522 FiddlerRegistration regObj = FiddlerRegistration.createRegistration 5523 (innerProxy, regID, eventReg); 5524 logInfoRegistration("\ncreated registration: registrationID = ", 5525 regObj); 5526 return regObj; 5527 }//end registerDo 5528 5529 /** 5530 * Places the registration corresponding to the <code>regInfo</code> 5531 * parameter in both the <code>registrationByID</code> map and the 5532 * <code>registrationByTime</code> map. This method also updates the 5533 * managed sets in the discovery manager in the appropriate way. This 5534 * should be called whenever a new registration has been created 5535 * and needs to be added to the data base (for example, the methods 5536 * <code>registerDo</code>, <code>recoverSnapshot</code> and the 5537 * <code>apply</code> method of the <code>RegistrationGrantedLogObj</code> 5538 * class all call this method). 5539 * 5540 * @param regInfo the data structure record corresponding to the 5541 * registration that is to be added to the data base 5542 * 5543 * @throws java.io.IOException this exception occurs when the multicast 5544 * request protocol fails to start. 5545 * 5546 * @see org.apache.river.fiddler.proxy.FiddlerImpl#registerDo 5547 * @see org.apache.river.fiddler.proxy.FiddlerImpl#recoverSnapshot 5548 */ 5549 private void addRegistration(RegistrationInfo regInfo) throws IOException { 5550 if (regInfo.listener == null) { 5551 /* failed to recover from log */ 5552 if( problemLogger.isLoggable(Level.INFO) ) { 5553 problemLogger.log(Level.INFO, "cannot add registration (ID = " 5554 +regInfo.registrationID+"); failed to " 5555 +"unmarshal listener during recovery"); 5556 }//endif 5557 return; 5558 }//endif 5559 /* First add the indicated registration */ 5560 registrationByID.put(regInfo.registrationID, regInfo); 5561 registrationByTime.put(regInfo,regInfo); 5562 /* Update the set of groups managed by the discovery manager */ 5563 updateDiscoveryMgrGroups(); 5564 /* Update the set of locators managed by the discovery manager */ 5565 updateDiscoveryMgrLocators(); 5566 }//end addRegistration 5567 5568 /** 5569 * Removes the registration corresponding to the <code>regInfo</code> 5570 * parameter from this service's state. Removes the registration from 5571 * both the <code>registrationByID</code> map and the 5572 * <code>registrationByTime</code> map. This method also updates the 5573 * managed sets in the discovery manager in the appropriate way. This 5574 * should be called whenever a current registration needs to be removed 5575 * from the data base (for example, when the registration's lease is 5576 * is expired in the <code>LeaseExpireThread</code>, and when the 5577 * registration's lease is cancelled in the <code>cancelLeaseDo</code> 5578 * method). 5579 * 5580 * @param regInfo the data structure record corresponding to the 5581 * registration that is to be removed from the data base 5582 * 5583 * @throws java.io.IOException this exception occurs when the multicast 5584 * request protocol fails to start. 5585 * 5586 * @see org.apache.river.fiddler.proxy.FiddlerImpl#cancelLeaseDo 5587 */ 5588 private void removeRegistration(RegistrationInfo regInfo) 5589 throws IOException 5590 { 5591 /* First remove the current registration */ 5592 registrationByID.remove(regInfo.registrationID); 5593 registrationByTime.remove(regInfo); 5594 logInfoRegistration("\nremoved registration: registrationID = ", 5595 regInfo.registrationID); 5596 /* Update the set of groups managed by the discovery manager */ 5597 updateDiscoveryMgrGroups(); 5598 /* Update the set of locators managed by the discovery manager */ 5599 updateDiscoveryMgrLocators(); 5600 logInfoGroups(); 5601 logInfoLocators(); 5602 }//end removeRegistration 5603 /* END Private Registration Methods ------------------------------------ */ 5604 5605 /* BEGIN Private Group Management Methods ------------------------------ */ 5606 /** 5607 * Called by the public method <code>addGroups</code>. This method 5608 * queues an <code>AddGroupsTask</code> which performs the actual 5609 * augmentation of the given registration's desired groups. 5610 * 5611 * @param regInfo the data structure record corresponding to the 5612 * registration whose managed set of groups is to be 5613 * augmented 5614 * @param groups a String array, none of whose elements may be null, 5615 * consisting of the group names with which to augment the 5616 * registration's managed set of groups. 5617 * 5618 * @see org.apache.river.fiddler.proxy.FiddlerImpl#addGroups 5619 * @see org.apache.river.fiddler.proxy.FiddlerRegistration#addGroups 5620 * @see net.jini.discovery.LookupDiscoveryRegistration#addGroups 5621 */ 5622 private void addGroupsDo(RegistrationInfo regInfo, String[] groups) { 5623 executorService.execute(new AddGroupsTask(regInfo,groups)); 5624 }//end addGroupsDo 5625 5626 /** 5627 * Called by the <code>apply</code> method of the class 5628 * <code>GroupsAddedToRegistrationLogObj</code> (which is invoked 5629 * during state recovery). This method queues an 5630 * <code>AddGroupsTask</code> which performs the actual augmentation 5631 * of the given registration's desired groups. 5632 * <p> 5633 * @param registrationID the ID of the data structure record 5634 * corresponding to the registration whose 5635 * managed set of groups is to be augmented 5636 * @param registrationByID the map containing all active registrations 5637 * managed by this service 5638 * @param groups a <code>String</code> array, none of whose 5639 * elements may be null, consisting of the group 5640 * names with which to augment the registration's 5641 * managed set of groups. 5642 * 5643 * @see org.apache.river.fiddler.proxy.FiddlerImpl#addGroupsDo 5644 * @see org.apache.river.fiddler.proxy.FiddlerImpl#addGroups 5645 * @see org.apache.river.fiddler.proxy.FiddlerRegistration#addGroups 5646 * @see net.jini.discovery.LookupDiscoveryRegistration#addGroups 5647 */ 5648 private void addGroupsDo(Uuid registrationID, 5649 HashMap registrationByID, 5650 String[] groups) 5651 { 5652 addGroupsDo((RegistrationInfo)(registrationByID.get(registrationID)), 5653 groups); 5654 }//end addGroupsDo 5655 5656 /** 5657 * Called by the public method <code>setGroups</code>. This method 5658 * queues a <code>SetGroupsTask</code> which performs the actual 5659 * replacement. 5660 * 5661 * @param regInfo the data structure record corresponding to the 5662 * registration whose managed set of groups is to be 5663 * replaced 5664 * @param groups a String array, none of whose elements may be null, 5665 * consisting of the group names with which to replace the 5666 * registration's managed set of groups. 5667 * 5668 * @see org.apache.river.fiddler.proxy.FiddlerImpl#setGroups 5669 * @see org.apache.river.fiddler.proxy.FiddlerRegistration#setGroups 5670 * @see net.jini.discovery.LookupDiscoveryRegistration#setGroups 5671 */ 5672 private void setGroupsDo(RegistrationInfo regInfo, String[] groups) { 5673 executorService.execute(new SetGroupsTask(regInfo,groups)); 5674 }//end setGroupsDo 5675 5676 /** 5677 * Called by the <code>apply</code> method of the class 5678 * <code>GroupsSetInRegistrationLogObj</code> (which is invoked 5679 * during state recovery). This method queues a 5680 * <code>SetGroupsTask</code> which performs the actual replacement. 5681 * <p> 5682 * @param registrationID the ID of the data structure record 5683 * corresponding to the registration whose 5684 * managed set of groups is to be replaced 5685 * @param registrationByID the map containing all active registrations 5686 * managed by this service 5687 * @param groups a <code>String</code> array, none of whose 5688 * elements may be null, consisting of the group 5689 * names with which to replace the registration's 5690 * managed set of groups. 5691 * 5692 * @see org.apache.river.fiddler.proxy.FiddlerImpl#setGroupsDo 5693 * @see org.apache.river.fiddler.proxy.FiddlerImpl#setGroups 5694 * @see org.apache.river.fiddler.proxy.FiddlerRegistration#setGroups 5695 * @see net.jini.discovery.LookupDiscoveryRegistration#setGroups 5696 */ 5697 private void setGroupsDo(Uuid registrationID, 5698 HashMap registrationByID, 5699 String[] groups) 5700 { 5701 setGroupsDo((RegistrationInfo)(registrationByID.get(registrationID)), 5702 groups); 5703 }//end setGroupsDo 5704 5705 /** 5706 * Called by the public method <code>removeGroups</code>. This method 5707 * queues a <code>RemoveGroupsTask</code> which performs the actual 5708 * removal. 5709 * 5710 * @param regInfo the data structure record corresponding to the 5711 * registration from whose managed set of groups the input 5712 * set of groups is to be removed 5713 * @param groups a String array, none of whose elements may be null, 5714 * consisting of the group names to remove from the 5715 * registration's managed set of groups 5716 * 5717 * @see org.apache.river.fiddler.proxy.FiddlerImpl#removeGroups 5718 * @see org.apache.river.fiddler.proxy.FiddlerRegistration#removeGroups 5719 * @see net.jini.discovery.LookupDiscoveryRegistration#removeGroups 5720 */ 5721 private void removeGroupsDo(RegistrationInfo regInfo, String[] groups) { 5722 executorService.execute(new RemoveGroupsTask(regInfo,groups)); 5723 }//end removeGroupsDo 5724 5725 /** 5726 * Called by the <code>apply</code> method of the class 5727 * <code>GroupsRemovedFromRegistrationLogObj</code> (which is 5728 * invoked during state recovery). This method queues a 5729 * <code>RemoveGroupsTask</code> which performs the actual removal. 5730 * <p> 5731 * @param registrationID the ID of the data structure record 5732 * corresponding to the registration from whose 5733 * managed set of groups the input set of groups 5734 * is to be removed 5735 * @param registrationByID the map containing all active registrations 5736 * managed by this service 5737 * @param groups a <code>String</code> array, none of whose 5738 * elements may be null, consisting of the group 5739 * names to remove from the registration's managed 5740 * set of groups 5741 * 5742 * @see org.apache.river.fiddler.proxy.FiddlerImpl#removeGroupsDo 5743 * @see org.apache.river.fiddler.proxy.FiddlerImpl#removeGroups 5744 * @see org.apache.river.fiddler.proxy.FiddlerRegistration#removeGroups 5745 * @see net.jini.discovery.LookupDiscoveryRegistration#removeGroups 5746 */ 5747 private void removeGroupsDo(Uuid registrationID, 5748 HashMap registrationByID, 5749 String[] groups) 5750 { 5751 removeGroupsDo 5752 ((RegistrationInfo)(registrationByID.get(registrationID)), 5753 groups); 5754 }//end removeGroupsDo 5755 5756 /** Builds a set containing the groups from all registrations. 5757 * 5758 * Iterates through all the active registrations, retrieving the groups 5759 * to discover for each registration (minus duplicates). If at least one 5760 * registration has requested that all groups be discovered, stops 5761 * iterating (because the set must be ALL_GROUPS) and returns null. 5762 */ 5763 private String[] getGroupsFromAllRegs() { 5764 HashSet groupSet = new HashSet(); 5765 for(Iterator itr=registrationByID.values().iterator();itr.hasNext();) { 5766 RegistrationInfo rInfo = (RegistrationInfo)itr.next(); 5767 if(rInfo.groups == null) { 5768 return DiscoveryGroupManagement.ALL_GROUPS; 5769 } else { 5770 groupSet.addAll(rInfo.groups); 5771 }//end if 5772 }//end loop 5773 return (String[])groupSet.toArray(new String[groupSet.size()]); 5774 }//end getGroupsFromAllRegs 5775 5776 /** This method returns a registrar-to-data-structure map in which each 5777 * registrar key in the returned map is one of the keys from the 5778 * the global map <code>allDiscoveredRegs</code>, and the corresponding 5779 * value is the (locator,groups) pair that corresponds to that registrar 5780 * key in <code>allDiscoveredRegs</code> 5781 * 5782 * An element of <code>allDiscoveredRegs</code> is selected to have 5783 * its registrar and associated (locator,groups) pair be included in the 5784 * returned mapping if and only if the key value of the element is a 5785 * registrar that belongs to at least one of the desired groups of the 5786 * given registration (<code>regInfo</code> parameter). That is, the 5787 * registrars referenced in the returned mapping are the registrars that 5788 * are of interest - through group discovery - to the given registration. 5789 * 5790 * Note that this method must be called from within a synchronization 5791 * block. 5792 * 5793 * @param regInfo the data structure record corresponding to the 5794 * registration whose groups-to-discover will be used to 5795 * select the elements from <code>allDiscoveredRegs</code> 5796 * to include in the return mapping 5797 * 5798 * @return a mapping in which the key values are registrars that, 5799 * in addition to being elements of the global map 5800 * <code>allDiscoveredRegs</code>, also belong to at least one 5801 * of the desired groups referenced in the <code>regInfo</code> 5802 * parameter; and whose map values are data structures of type 5803 * <code>LocatorGroupsStruct</code> that contain the associated 5804 * locator and member groups of the corresponding registrar key 5805 */ 5806 private Map getDesiredRegsByGroup(RegistrationInfo regInfo) { 5807 Set<String> desiredGroups = regInfo.groups; 5808 HashMap desiredRegMap = new HashMap(allDiscoveredRegs.size()); 5809 Set eSet = allDiscoveredRegs.entrySet(); 5810 for(Iterator itr = eSet.iterator(); itr.hasNext(); ) { 5811 Map.Entry pair = (Map.Entry)itr.next(); 5812 LocatorGroupsStruct locGroupsStruct 5813 = (LocatorGroupsStruct)pair.getValue(); 5814 if( interested(locGroupsStruct.groups,desiredGroups) ) { 5815 desiredRegMap.put((ServiceRegistrar)pair.getKey(), 5816 locGroupsStruct); 5817 }//endif 5818 }//end loop 5819 return desiredRegMap; 5820 }//end getDesiredRegsByGroup 5821 5822 /** Modifies the discovery manager's managed set of groups in the 5823 * appropriate way; that is, adds to the discovery manager's managed 5824 * set of groups, any new groups-of-interest, across all registrations, 5825 * and removes any groups that are no longer of interest to any of the 5826 * registrations. This method is typically called after the groups of 5827 * a particular registration have been modified. 5828 * 5829 * Note that this method must be called from within a synchronization 5830 * block. 5831 */ 5832 private void updateDiscoveryMgrGroups() { 5833 /* Build the set containing the groups from all registrations. */ 5834 String[] groupsAcrossAllRegs = getGroupsFromAllRegs(); 5835 /* Update the discovery manager's set of groups to discover. Let 5836 * the manager sort out duplicates and any already-discovered groups. 5837 */ 5838 try { 5839 discoveryMgr.setGroups( groupsAcrossAllRegs ); 5840 } catch (IOException e) { 5841 String warnStr = "IOException: on call to setGroups() " 5842 +"method of discovery manager"; 5843 problemLogger.log(Level.INFO, warnStr, e); 5844 Entry[] warnAttrs = new Entry[] 5845 { new FiddlerStatus(StatusType.WARNING), 5846 new Comment(warnStr) 5847 }; 5848 joinMgr.addAttributes(warnAttrs,true); 5849 } catch(IllegalStateException e) { 5850 String errStr = "IllegalStateException: discovery " 5851 +"manager's setGroups() method was called " 5852 +"after the manager was terminated"; 5853 problemLogger.log(Level.INFO, errStr, e); 5854 Entry[] errorAttrs = new Entry[] 5855 { new FiddlerStatus(StatusType.ERROR), 5856 new Comment(errStr) 5857 }; 5858 joinMgr.addAttributes(errorAttrs,true); 5859 throw new IllegalStateException(" discovery manager's " 5860 +"setGroups() method was " 5861 +"called after the manager " 5862 +"was terminated"); 5863 }//end try 5864 }//end updateDiscoveryMgrGroups 5865 /* END Private Group Management Methods -------------------------------- */ 5866 5867 /* BEGIN Private Locator Management Methods ---------------------------- */ 5868 /** 5869 * Called by the public method <code>addLocators</code>. This method 5870 * queues an <code>AddLocatorsTask</code> which performs the actual 5871 * augmentation of the given registration's desired locators. 5872 * 5873 * @param regInfo the data structure record corresponding to the 5874 * registration whose managed set of locators is to be 5875 * augmented 5876 * @param locators an array, none of whose elements may be null, 5877 * consisting of the <code>LookupLocator</code> objects 5878 * with which to augment the registration's managed set 5879 * of locators. 5880 * 5881 * @see org.apache.river.fiddler.proxy.FiddlerImpl#addLocators 5882 * @see org.apache.river.fiddler.proxy.FiddlerRegistration#addLocators 5883 * @see net.jini.discovery.LookupDiscoveryRegistration#addLocators 5884 */ 5885 private void addLocatorsDo(RegistrationInfo regInfo, 5886 LookupLocator[] locators) 5887 { 5888 executorService.execute(new AddLocatorsTask(regInfo,locators)); 5889 }//end addLocatorsDo 5890 5891 /** 5892 * Called by the <code>apply</code> method of the class 5893 * <code>LocsAddedToRegistrationLogObj</code> (which is invoked 5894 * during state recovery). This method queues an 5895 * <code>AddLocatorsTask</code> which performs the actual augmentation 5896 * of the given registration's desired locators. 5897 * <p> 5898 * @param registrationID the ID of the data structure record 5899 * corresponding to the registration whose 5900 * managed set of locators is to be augmented 5901 * @param registrationByID the map containing all active registrations 5902 * managed by this service 5903 * @param locators an array, none of whose elements may be null, 5904 * consisting of the <code>LookupLocator</code> 5905 * objects with which to augment the 5906 * registration's managed set of locators. 5907 * 5908 * @see org.apache.river.fiddler.proxy.FiddlerImpl#addLocatorsDo 5909 * @see org.apache.river.fiddler.proxy.FiddlerImpl#addLocators 5910 * @see org.apache.river.fiddler.proxy.FiddlerRegistration#addLocators 5911 * @see net.jini.discovery.LookupDiscoveryRegistration#addLocators 5912 */ 5913 private void addLocatorsDo(Uuid registrationID, 5914 HashMap registrationByID, 5915 LookupLocator[] locators) 5916 { 5917 addLocatorsDo((RegistrationInfo)(registrationByID.get(registrationID)), 5918 locators); 5919 }//end addLocatorsDo 5920 5921 /** 5922 * Called by the public method <code>setLocators</code>. This method 5923 * queues a <code>SetLocatorsTask</code> which performs the 5924 * actual replacement. 5925 * 5926 * @param regInfo the data structure record corresponding to the 5927 * registration whose managed set of locators is to be 5928 * replaced 5929 * @param locators an array, none of whose elements may be null, 5930 * consisting of the <code>LookupLocator</code> objects 5931 * with which to replace the registration's managed set 5932 * of locators. 5933 * 5934 * @see org.apache.river.fiddler.proxy.FiddlerImpl#setLocators 5935 * @see org.apache.river.fiddler.proxy.FiddlerRegistration#setLocators 5936 * @see net.jini.discovery.LookupDiscoveryRegistration#setLocators 5937 */ 5938 private void setLocatorsDo(RegistrationInfo regInfo, 5939 LookupLocator[] locators) 5940 { 5941 executorService.execute(new SetLocatorsTask(regInfo,locators)); 5942 }//end setLocatorsDo 5943 5944 /** 5945 * Called by the <code>apply</code> method of the class 5946 * <code>LocsSetInRegistrationLogObj</code> (which is invoked 5947 * during state recovery). This method queues a 5948 * <code>SetLocatorsTask</code> which performs the actual replacement. 5949 * <p> 5950 * @param registrationID the ID of the data structure record 5951 * corresponding to the registration whose 5952 * managed set of locators is to be replaced 5953 * @param registrationByID the map containing all active registrations 5954 * managed by this service 5955 * @param locators an array, none of whose elements may be null, 5956 * consisting of the <code>LookupLocator</code> 5957 * objects with which to replace the 5958 * registration's managed set of locators. 5959 * 5960 * @see org.apache.river.fiddler.proxy.FiddlerImpl#setLocatorsDo 5961 * @see org.apache.river.fiddler.proxy.FiddlerImpl#setLocators 5962 * @see org.apache.river.fiddler.proxy.FiddlerRegistration#setLocators 5963 * @see net.jini.discovery.LookupDiscoveryRegistration#setLocators 5964 */ 5965 private void setLocatorsDo(Uuid registrationID, 5966 HashMap registrationByID, 5967 LookupLocator[] locators) 5968 { 5969 setLocatorsDo((RegistrationInfo)(registrationByID.get(registrationID)), 5970 locators); 5971 }//end setLocatorsDo 5972 5973 /** 5974 * Called by the public method <code>removeLocators</code>. This method 5975 * queues a <code>RemoveLocatorsTask</code> which performs the 5976 * actual removal. 5977 * 5978 * @param regInfo the data structure record corresponding to the 5979 * registration from whose managed set of locators the 5980 * input set of locators is to be removed 5981 * @param locators an array, none of whose elements may be null, 5982 * consisting of the <code>LookupLocator</code> objects 5983 * to remove from the registration's managed set of 5984 * locators. 5985 * 5986 * @see org.apache.river.fiddler.proxy.FiddlerImpl#removeLocators 5987 * @see org.apache.river.fiddler.proxy.FiddlerRegistration#removeLocators 5988 * @see net.jini.discovery.LookupDiscoveryRegistration#removeLocators 5989 */ 5990 private void removeLocatorsDo(RegistrationInfo regInfo, 5991 LookupLocator[] locators) 5992 { 5993 executorService.execute(new RemoveLocatorsTask(regInfo,locators)); 5994 }//end removeLocatorsDo 5995 5996 /** 5997 * Called by the <code>apply</code> method of the class 5998 * <code>LocsRemovedFromRegistrationLogObj</code> (which is 5999 * invoked during state recovery). This method queues a 6000 * <code>RemoveLocatorsTask</code> which performs the actual removal. 6001 * <p> 6002 * @param registrationID the ID of the data structure record 6003 * corresponding to the registration from whose 6004 * managed set of groups the input set of locators 6005 * is to be removed 6006 * @param registrationByID the map containing all active registrations 6007 * managed by this service 6008 * @param locators an array, none of whose elements may be null, 6009 * consisting of the <code>LookupLocator</code> 6010 * objects to remove from the registration's 6011 * managed set of locators. 6012 * 6013 * @see org.apache.river.fiddler.proxy.FiddlerImpl#removeLocatorsDo 6014 * @see org.apache.river.fiddler.proxy.FiddlerImpl#removeLocators 6015 * @see org.apache.river.fiddler.proxy.FiddlerRegistration#removeLocators 6016 * @see net.jini.discovery.LookupDiscoveryRegistration#removeLocators 6017 */ 6018 private void removeLocatorsDo(Uuid registrationID, 6019 HashMap registrationByID, 6020 LookupLocator[] locators) 6021 { 6022 removeLocatorsDo 6023 ((RegistrationInfo)(registrationByID.get(registrationID)), 6024 locators); 6025 }//end removeLocatorsDo 6026 6027 /** Builds a set containing the locators from all registrations. 6028 * 6029 * Iterates through all the active registrations, retrieving the locators 6030 * to discover for each registration (minus duplicates). 6031 */ 6032 private LookupLocator[] getLocatorsFromAllRegs() { 6033 HashSet locatorSet = new HashSet(); 6034 for(Iterator itr=registrationByID.values().iterator();itr.hasNext();) { 6035 RegistrationInfo rInfo = (RegistrationInfo)itr.next(); 6036 if(rInfo.locators == null) { 6037 throw new AssertionError 6038 ("registration contains a null set of locators"); 6039 } else { 6040 locatorSet.addAll(rInfo.locators); 6041 }//end if 6042 }//end loop 6043 return (LookupLocator[])locatorSet.toArray 6044 (new LookupLocator[locatorSet.size()]); 6045 }//end getLocatorsFromAllRegs 6046 6047 /** This method returns a registrar-to-data-structure map in which each 6048 * registrar key in the returned map is one of the keys from the 6049 * the global map <code>allDiscoveredRegs</code>, and the corresponding 6050 * value is the (locator,groups) pair that corresponds to that registrar 6051 * key in <code>allDiscoveredRegs</code> 6052 * 6053 * An element of <code>allDiscoveredRegs</code> is selected to have 6054 * its registrar and associated (locator,groups) pair be included in the 6055 * returned mapping if and only if the key value under consideration is 6056 * a registrar whose locator equals one of the desired locators of the 6057 * given registration (<code>regInfo</code> parameter). That is, the 6058 * registrars referenced in the returned mapping are the registrars that 6059 * are of interest - through locator discovery - to the given 6060 * registration. 6061 * 6062 * @param regInfo the data structure record corresponding to the 6063 * registration whose locators-to-discover will be used to 6064 * select the elements from <code>allDiscoveredRegs</code> 6065 * to include in the return mapping 6066 * 6067 * @return a mapping in which the key values are registrars that, 6068 * in addition to being elements of the global map 6069 * <code>allDiscoveredRegs</code>, have locators that are 6070 * elements of the set of desired locators referenced in the 6071 * <code>regInfo</code> parameter; and whose map values are 6072 * data structures of type <code>LocatorGroupsStruct</code> that 6073 * contain the associated locator and member groups of the 6074 * corresponding registrar key 6075 */ 6076 private Map getDesiredRegsByLocator(RegistrationInfo regInfo) { 6077 Set<LookupLocator> desiredLocators = regInfo.locators; 6078 HashMap desiredRegMap = new HashMap(allDiscoveredRegs.size()); 6079 Set eSet = allDiscoveredRegs.entrySet(); 6080 for(Iterator itr = eSet.iterator(); itr.hasNext(); ) { 6081 Map.Entry pair = (Map.Entry)itr.next(); 6082 LocatorGroupsStruct locGroupsStruct 6083 = (LocatorGroupsStruct)pair.getValue(); 6084 if(locSetContainsLoc(desiredLocators,locGroupsStruct.locator)) { 6085 desiredRegMap.put((ServiceRegistrar)pair.getKey(), 6086 locGroupsStruct); 6087 }//endif 6088 }//end loop 6089 return desiredRegMap; 6090 }//end getDesiredRegsByLocator 6091 6092 /** Modifies the discovery manager's managed set of locators in the 6093 * appropriate way; that is, adds to the discovery manager's managed 6094 * set of locators, any new locators-of-interest, across all 6095 * registrations, and removes any locators that are no longer of 6096 * interest to any of the registrations. This method is typically 6097 * called after the locators of a particular registration have been 6098 * modified. 6099 * 6100 * Note that this method must be called from within a synchronization 6101 * block. 6102 */ 6103 private void updateDiscoveryMgrLocators() { 6104 /* Build the set containing the locators from all registrations. */ 6105 LookupLocator[] locsAcrossAllRegs = getLocatorsFromAllRegs(); 6106 /* Update the discovery manager's set of locators to discover. Let 6107 * the manager sort out duplicates and any already-discovered locators. 6108 */ 6109 try { 6110 discoveryMgr.setLocators( locsAcrossAllRegs ); 6111 } catch(IllegalStateException e) { 6112 String errStr = "IllegalStateException: discovery " 6113 +"manager's setLocators() method was called " 6114 +"after the manager was terminated"; 6115 problemLogger.log(Level.INFO, errStr, e); 6116 Entry[] errorAttrs = new Entry[] 6117 { new FiddlerStatus(StatusType.ERROR), 6118 new Comment(errStr) 6119 }; 6120 joinMgr.addAttributes(errorAttrs,true); 6121 throw new IllegalStateException(" discovery manager's " 6122 +"setLocators() method was " 6123 +"called after the manager " 6124 +"was terminated"); 6125 }//end try 6126 }//end updateDiscoveryMgrLocators 6127 /* END Private Locator Management Methods ------------------------------ */ 6128 6129 /* BEGIN Private Lease Renewal Methods --------------------------------- */ 6130 /** 6131 * Called by the public method <code>renewLease</code>. This method renews 6132 * the lease corresponding to the <code>registrationID</code> and 6133 * <code>leaseID</code> parameters, granting a new duration that is 6134 * less than or equal to the requested duration value contained in 6135 * the <code>duration</code> parameter. 6136 * 6137 * @param regInfo the data structure record corresponding to the 6138 * registration whose lease is to be renewed 6139 * @param leaseID identifier assigned by the lease grantor to the lease 6140 * that is to be renewed 6141 * @param duration the requested duration for the lease being renewed 6142 * 6143 * @throws net.jini.core.lease.UnknownLeaseException this exception occurs 6144 * when the lease being renewed is unknown to the lease grantor. 6145 * 6146 * @return <code>long</code> value representing the actual duration that 6147 * was granted for the renewed lease. Note that the actual 6148 * duration granted and returned by this method may be less than 6149 * the duration requested. 6150 * 6151 * @see org.apache.river.fiddler.proxy.FiddlerImpl#renewLease 6152 */ 6153 private long renewLeaseDo(RegistrationInfo regInfo, 6154 Uuid leaseID, 6155 long duration) throws UnknownLeaseException 6156 { 6157 long curTime = System.currentTimeMillis(); 6158 long newExpiration = renewLeaseInt(regInfo,leaseID,duration,curTime); 6159 addLogRecord(new LeaseRenewedLogObj 6160 (regInfo.registrationID, leaseID, newExpiration)); 6161 return (newExpiration - curTime); 6162 }//end renewLeaseDo 6163 6164 /** 6165 * Called by the method <code>renewLeaseDo</code>. This method takes 6166 * a requested duration for the lease corresponding to the 6167 * <code>registrationID</code> and <code>leaseID</code> parameters, 6168 * converts that duration to an absolute expiration (based on the local 6169 * clock) with the appropriate bound applied, and attempts to renew 6170 * the lease, granting the new expiration time on the lease. 6171 * 6172 * @param regInfo the data structure record corresponding to the 6173 * registration whose lease is to be renewed 6174 * @param leaseID identifier assigned by the lease grantor to the lease 6175 * that is to be renewed 6176 * @param duration the requested duration for the lease being renewed 6177 * 6178 * @return <code>long</code> value representing the new absolute 6179 * expiration time granted for the renewed lease. 6180 * 6181 * @throws net.jini.core.lease.UnknownLeaseException this exception occurs 6182 * when the lease being renewed is unknown to the lease grantor. 6183 * 6184 * @see org.apache.river.fiddler.proxy.FiddlerImpl#renewLeaseDo 6185 */ 6186 private long renewLeaseInt(RegistrationInfo regInfo, 6187 Uuid leaseID, 6188 long duration, 6189 long curTime) throws UnknownLeaseException 6190 { 6191 if(duration == Lease.ANY) { 6192 duration = leaseBound; 6193 } else if(duration <= 0) { 6194 throw new IllegalArgumentException("non-positive lease duration"); 6195 }//endif 6196 if ( (regInfo == null) 6197 || ( !(regInfo.leaseID).equals(leaseID) ) 6198 || (regInfo.leaseExpiration <= curTime) ) { 6199 throw new UnknownLeaseException(); 6200 }//endif 6201 if( (duration > leaseBound) 6202 && (duration > (regInfo.leaseExpiration - curTime)) ) { 6203 duration = Math.max( (regInfo.leaseExpiration - curTime), 6204 leaseBound ); 6205 }//endif 6206 long newExpiration = curTime + duration; 6207 /* Force a re-sort in the registrationByTime map */ 6208 registrationByTime.remove(regInfo); // force first re-sort 6209 regInfo.leaseExpiration = newExpiration; // modify outside of map 6210 registrationByTime.put(regInfo, regInfo); // insert & force new sort 6211 /* see if the expire thread needs to wake up earlier */ 6212 if (newExpiration < minExpiration) { 6213 minExpiration = newExpiration; 6214 leaseExpireThreadSyncObj.signal(); 6215 }//endif 6216 return newExpiration; 6217 }//end renewLeaseInt 6218 6219 /** 6220 * This method performs the final steps in the process of renewing the 6221 * lease on the registration corresponding to the <code>regInfo</code> 6222 * and <code>leaseID</code> parameters, granting a requested absolute 6223 * expiration time for that lease. 6224 * 6225 * @param regInfo the data structure record corresponding to the 6226 * registration whose lease is to be renewed 6227 * @param leaseID identifier assigned by the lease grantor to the lease 6228 * that is to be renewed 6229 * @param expiration the requested absolute expiration time for the lease 6230 * being renewed 6231 */ 6232 private void renewLeaseAbs(RegistrationInfo regInfo, 6233 Uuid leaseID, 6234 long expiration) 6235 { 6236 if ( (regInfo == null) || (regInfo.leaseID != leaseID) ) return; 6237 /* The act of renewing a registration's lease simply involves 6238 * changing the expiration time stored in the registration's 6239 * data structure. But because the registrationByTime sorts its 6240 * elements by time, changing the value of the leaseExpiration field 6241 * of the regInfo parameter "in place" would typically result in 6242 * the registrationByTime map being out of order. Contrast this with 6243 * the modification of the registration's non-time-dependent fields 6244 * (for example, adding, replacing or removing groups or locators), 6245 * where modifying the input regInfo parameter will modify the 6246 * appropriate field of the corresponding element of both the 6247 * registrationByID and registrationByTime maps; and the order 6248 * will still be valid in the registrationByTime map because the 6249 * time-dependent data has not changed. 6250 * 6251 * Thus, in order to maintain a valid ordering in the 6252 * registrationByTime map, a re-sort is forced by first removing 6253 * from that map the element corresponding to regInfo, resetting 6254 * the leaseExpiration field of that object, and then re-inserting 6255 * the modified regInfo into the map, which forces another sort. 6256 */ 6257 registrationByTime.remove(regInfo); // force first re-sort 6258 regInfo.leaseExpiration = expiration; // modify outside of map 6259 registrationByTime.put(regInfo, regInfo); // insert & force new sort 6260 }//end renewLeaseAbs 6261 6262 /** 6263 * Called by the <code>apply</code> method of the class 6264 * <code>LeaseRenewedLogObj</code> (which is invoked during state 6265 * recovery). This method performs the final steps in the process 6266 * of renewing the lease on the registration corresponding to the 6267 * <code>registrationID</code> and <code>leaseID</code> parameters, 6268 * granting a requested absolute expiration time for that lease. 6269 * 6270 * @param registrationID the ID of the data structure record 6271 * corresponding to the registration whose 6272 * lease is to be renewed 6273 * @param registrationByID the map containing all active registrations 6274 * managed by this service 6275 * @param leaseID identifier assigned by the lease grantor to 6276 * the lease that is to be renewed 6277 * @param expiration the requested absolute expiration time for the 6278 * lease being renewed 6279 * 6280 * @see org.apache.river.fiddler.proxy.FiddlerImpl#renewLeaseDo 6281 */ 6282 private void renewLeaseAbs(Uuid registrationID, 6283 HashMap registrationByID, 6284 Uuid leaseID, 6285 long expiration) 6286 { 6287 renewLeaseAbs((RegistrationInfo)(registrationByID.get(registrationID)), 6288 leaseID,expiration); 6289 }//end renewLeaseAbs 6290 6291 /** 6292 * Called by the public method renewLeases to renew all of 6293 * the leases from a <code>LeaseMap</code> that correspond to the 6294 * elements of the <code>registrationIDs</code> and <code>leaseIDs</code> 6295 * parameters, granting as new durations the corresponding elements 6296 * of the <code>duration</code> parameter. 6297 * <p> 6298 * Note that all of the input parameters must be the same length. 6299 * 6300 * @param registrationIDs array containing the unique identifiers assigned 6301 * to the each registration to which each lease 6302 * to be renewed corresponds 6303 * @param leaseIDs array containing the identifiers assigned by the 6304 * lease grantor to each lease being renewed 6305 * @param durations array containing the requested durations for 6306 * each lease being renewed 6307 * 6308 * @return an instance of FiddlerRenewResults containing data corresponding 6309 * to the results (granted durations or exceptions) of each 6310 * renewal attempt 6311 * 6312 * @see org.apache.river.fiddler.proxy.FiddlerImpl#renewLeases 6313 */ 6314 private FiddlerRenewResults renewLeasesDo(Uuid[] registrationIDs, 6315 Uuid[] leaseIDs, 6316 long[] durations) 6317 { 6318 long curTime = System.currentTimeMillis(); 6319 Exception[] exceptions = null; 6320 for (int i = 0; i < registrationIDs.length; i++) { 6321 RegistrationInfo regInfo 6322 = (RegistrationInfo)(registrationByID.get(registrationIDs[i])); 6323 try { 6324 durations[i] = renewLeaseInt(regInfo, leaseIDs[i], 6325 durations[i], curTime); 6326 } catch (Exception e) { 6327 durations[i] = -1; 6328 if (exceptions == null) { 6329 exceptions = new Exception[]{e}; 6330 } else { 6331 exceptions = (Exception[])appendArray(exceptions, e); 6332 }//endif 6333 } 6334 }//end loop 6335 /* don't bother to weed out problem leases */ 6336 addLogRecord 6337 ( new LeasesRenewedLogObj(registrationIDs,leaseIDs,durations) ); 6338 for (int i = registrationIDs.length; --i >= 0; ) { 6339 if (durations[i] >= 0) { 6340 durations[i] -= curTime; 6341 }//endif 6342 }//end loop 6343 return new FiddlerRenewResults(durations, exceptions); 6344 }//end renewLeasesDo 6345 6346 /** 6347 * Using the absolute expiration times contained in the 6348 * <code>expirations</code> parameter, renews all of the leases 6349 * from a <code>LeaseMap</code> that correspond to the elements 6350 * of the <code>registrationIDs</code> and <code>leaseIDs</code> 6351 * parameters; skipping any negative expiration times. 6352 * <p> 6353 * Note that all of the input parameters must be the same length. 6354 * 6355 * @param registrationIDs array containing the unique identifiers assigned 6356 * to the each registration to which each lease 6357 * to be renewed corresponds 6358 * @param leaseIDs array containing the identifiers assigned by the 6359 * lease grantor to each lease being renewed 6360 * @param expirations array containing the absolute expiration times 6361 * to which to renew each lease 6362 * 6363 * @see org.apache.river.fiddler.proxy.FiddlerImpl#renewLeases 6364 * @see org.apache.river.fiddler.proxy.FiddlerImpl#renewLeaseAbs 6365 */ 6366 private void renewLeasesAbs(Uuid[] registrationIDs, 6367 Uuid[] leaseIDs, 6368 long[] expirations) 6369 { 6370 for (int i = registrationIDs.length; --i >= 0; ) { 6371 long expiration = expirations[i]; 6372 if (expiration < 0) continue; 6373 RegistrationInfo regInfo 6374 = (RegistrationInfo)(registrationByID.get(registrationIDs[i])); 6375 renewLeaseAbs(regInfo, leaseIDs[i], expiration); 6376 }//end loop 6377 }//end renewLeasesAbs 6378 /* END Private Lease Renewal Methods ----------------------------------- */ 6379 6380 /* BEGIN Private Lease Cancellation Methods ---------------------------- */ 6381 /** 6382 * Called by the public method <code>cancelLease</code>. This method 6383 * cancels the lease on the registration corresponding to the 6384 * <code>regInfo</code> and <code>leaseID</code> parameters. 6385 * 6386 * @param regInfo the data structure record corresponding to the 6387 * registration whose lease is to be cancelled 6388 * @param leaseID identifier assigned by the lease grantor to the lease 6389 * that is to be cancelled 6390 * 6391 * @throws net.jini.core.lease.UnknownLeaseException this exception occurs 6392 * when the lease being cancelled is unknown to the lease grantor. 6393 * 6394 * @throws java.io.IOException this exception occurs when the multicast 6395 * request protocol experiences a failure. 6396 * 6397 * @see org.apache.river.fiddler.proxy.FiddlerImpl#cancelLease 6398 */ 6399 private void cancelLeaseDo(RegistrationInfo regInfo, Uuid leaseID) 6400 throws UnknownLeaseException, IOException 6401 { 6402 long curTime = System.currentTimeMillis(); 6403 if ( (regInfo == null) || (regInfo.leaseExpiration <= curTime) ) { 6404 throw new UnknownLeaseException(); 6405 }//endif 6406 removeRegistration(regInfo); 6407 /* wake up thread if this might be the (only) earliest time */ 6408 if (regInfo.leaseExpiration == minExpiration) { 6409 leaseExpireThreadSyncObj.signal(); 6410 }//endif 6411 }//end cancelLeaseDo 6412 6413 /** 6414 * Called by the <code>apply</code> method of the class 6415 * <code>LeaseCancelledLogObj</code> (which is invoked during state 6416 * recovery). This method cancels the lease on the registration 6417 * corresponding to the <code>registrationID</code> and 6418 * <code>leaseID</code> parameters. 6419 * 6420 * @param registrationID the ID of the data structure record 6421 * corresponding to the registration whose 6422 * lease is to be cancelled 6423 * @param registrationByID the map containing all active registrations 6424 * managed by this service 6425 * @param leaseID identifier assigned by the lease grantor to 6426 * the lease that is to be cancelled 6427 * 6428 * @throws net.jini.core.lease.UnknownLeaseException this exception occurs 6429 * when the lease being cancelled is unknown to the lease grantor. 6430 * 6431 * @throws java.io.IOException this exception occurs when the multicast 6432 * request protocol experiences a failure. 6433 * 6434 * @see org.apache.river.fiddler.proxy.FiddlerImpl#cancelLeaseDo 6435 * @see org.apache.river.fiddler.proxy.FiddlerImpl#cancelLease 6436 */ 6437 private void cancelLeaseDo(Uuid registrationID, 6438 HashMap registrationByID, 6439 Uuid leaseID) 6440 throws UnknownLeaseException, IOException 6441 { 6442 cancelLeaseDo((RegistrationInfo)(registrationByID.get(registrationID)), 6443 leaseID); 6444 }//end cancelLeaseDo 6445 6446 /** 6447 * Called by the public method cancelLeases to the cancel all of 6448 * the leases from a <code>LeaseMap</code> that correspond to the 6449 * elements of the <code>registrationIDs</code> and <code>leaseIDs</code> 6450 * parameters. 6451 * <p> 6452 * The two input arrays must be the same length. If there are no 6453 * exceptions, the return value is null. Otherwise, the return value 6454 * has the same length as the <code>registrationIDs</code> parameter, 6455 * and has nulls for the leases that were successfully renewed. 6456 * 6457 * @return an array containing the instances of Exception (or null for 6458 * successfully renewed leases), each corresponding to the 6459 * exception that occurred upon attempting renewal. 6460 * 6461 * @see org.apache.river.fiddler.proxy.FiddlerImpl#cancelLeases 6462 */ 6463 private Exception[] cancelLeasesDo(Uuid[] registrationIDs, 6464 Uuid[] leaseIDs) 6465 { 6466 Exception[] exceptions = null; 6467 for (int i = registrationIDs.length; --i >= 0; ) { 6468 try { 6469 RegistrationInfo regInfo = 6470 (RegistrationInfo)(registrationByID.get 6471 (registrationIDs[i])); 6472 cancelLeaseDo(regInfo, leaseIDs[i]); 6473 } catch (Exception e) { 6474 if (exceptions == null) { 6475 exceptions = new Exception[registrationIDs.length]; 6476 }//endif 6477 exceptions[i] = e; 6478 } 6479 }//end loop 6480 return exceptions; 6481 }//end cancelLeasesDo 6482 /* END Private Lease Cancellation Methods ------------------------------ */ 6483 6484 /* BEGIN Private Event-Related Methods --------------------------------- */ 6485 /** Returns the set of registrars common to both input parameters */ 6486 private ServiceRegistrar[] intersectRegSets(ServiceRegistrar[] regs0, 6487 ServiceRegistrar[] regs1) 6488 { 6489 HashSet regSet = new HashSet(); //no duplicates 6490 /* Compare each input element of regs0 with each element of regs1, 6491 * storing matches along the way 6492 */ 6493 nextRegistrar: 6494 for(int i=0;i<regs0.length;i++) { 6495 for(int j=0;j<regs1.length;j++) { 6496 if( (regs0[i]).equals(regs1[j]) ) { 6497 regSet.add(regs0[i]); 6498 continue nextRegistrar; // match found, next reg 6499 }//endif 6500 }//end loop(j) 6501 }//end loop(i) 6502 return ( (ServiceRegistrar[])(regSet).toArray 6503 (new ServiceRegistrar[regSet.size()]) ); 6504 }//end intersectRegSets 6505 6506 /** Returns true if the input registrar is an element of the given array */ 6507 private boolean regIsElementOfRegSet(ServiceRegistrar reg, 6508 ServiceRegistrar[] regSet) 6509 { 6510 for(int i=0;i<regSet.length;i++) { 6511 if( (regSet[i]).equals(reg) ) return true; 6512 }//end loop 6513 return false; 6514 }//end regIsElementOfRegSet 6515 6516 /** 6517 * This method determines which of the registrars in the 6518 * <code>regsMap</code> parameter belong to the set of registrars 6519 * the given <code>regInfo</code> parameter wishes to discover. It 6520 * then adds those registrars to the regInfo's map of discovered 6521 * registrars (including only those registrars that can be successfully 6522 * serialized). Finally, a discovered event containing the discovery 6523 * information that is of interest to the regInfo is built and sent 6524 * to the regInfo's listener. 6525 * 6526 * @param regInfo the data structure record corresponding to the 6527 * registration whose listener will receive the event 6528 * @param regsMap mapping in which the key values are previously discovered 6529 * registrars, and the map values are data structures of 6530 * type <code>LocatorGroupsStruct</code> that contain the 6531 * locator and member groups of the corresponding 6532 * registrar key 6533 */ 6534 private void maybeSendDiscoveredEvent(RegistrationInfo regInfo, 6535 Map regsMap) 6536 { 6537 /* Determine the registrars that are common to both the input set of 6538 * registrars (the currently or newly discovered registrars) and the 6539 * registration's set of desired registrars. These are the registrars 6540 * to send in the event. 6541 */ 6542 HashMap regsToAdd = new HashMap(regsMap.size()); 6543 Set eSet = regsMap.entrySet(); 6544 for(Iterator itr = eSet.iterator(); itr.hasNext(); ) { 6545 Map.Entry pair = (Map.Entry)itr.next(); 6546 ServiceRegistrar reg = (ServiceRegistrar)pair.getKey(); 6547 LocatorGroupsStruct curStructVal 6548 = (LocatorGroupsStruct)pair.getValue(); 6549 /* If regInfo wants ALL_GROUPS, then every registrar is desired */ 6550 if(regInfo.groups == null) { // ALL_GROUPS 6551 regsToAdd.put(reg,curStructVal); 6552 } else {//not ALL_GROUPS, reg's locator/groups desired by regInfo? 6553 if( interested(curStructVal.locator,curStructVal.groups, 6554 regInfo.locators,regInfo.groups) ) 6555 { 6556 regsToAdd.put(reg,curStructVal); 6557 }//endif 6558 }//endif 6559 }//end loop 6560 /* Add the registrars that are both desired and discovered to the 6561 * registration's map of discovered registrars. If any registrars 6562 * cannot be serialized, drop them. 6563 */ 6564 Map regsAdded = regInfo.addToDiscoveredRegs(regsToAdd); 6565 /* Build and send a "discovered event" */ 6566 RemoteDiscoveryEvent event = buildEvent(regInfo,regsAdded,false); 6567 if(event != null) { 6568 queueEvent(regInfo,event); 6569 logInfoEvents("NewReg/Discovered EventTask.run(): " 6570 +"DISCOVERED Event was SENT\n"); 6571 }//endif 6572 }//end maybeSendDiscoveredEvent 6573 6574 /** 6575 * Examines the <code>discardFlag</code> for each active registration 6576 * until a value of <code>true</code> is encountered or the set of 6577 * registrations is exhausted. If that flag is <code>false</code> for 6578 * all registrations, this method will return <code>null</code>; 6579 * otherwise, it will return the registration found, but with the 6580 * the value of the flag set back to <code>false</code>. 6581 * 6582 * @return the first instance of <code>RegistrationInfo</code> whose 6583 * <code>discardFlag</code> is set to <code>true</code>; 6584 * returns <code>null</code> if no such registration exists. 6585 */ 6586 private RegistrationInfo externalDiscardRequest() { 6587 /* Loop thru regInfo's, until one is found with a true flag*/ 6588 for(Iterator itr=registrationByID.values().iterator();itr.hasNext();) { 6589 RegistrationInfo regInfo = (RegistrationInfo)itr.next(); 6590 if(regInfo.discardFlag == true) { 6591 logInfoDiscard("\nexternalDiscardRequest: " 6592 +"discardFlag == true\n"); 6593 regInfo.discardFlag = false; 6594 return regInfo; 6595 }//endif 6596 }//end loop 6597 return null; 6598 }//end externalDiscardRequest 6599 6600 /** 6601 * Convenience method that creates and returns a mapping of a single 6602 * <code>ServiceRegistrar</code> instance to a set of groups. 6603 * 6604 * @param reg instance of <code>ServiceRegistrar</code> 6605 * corresponding to the registrar to use as the key 6606 * to the mapping 6607 * @param groups <code>String</code> array containing the current 6608 * member groups of the registrar referenced by the 6609 * <code>reg</code> parameter; and which is used 6610 * as the value of the mapping 6611 * 6612 * @return <code>Map</code> instance containing a single mapping from 6613 * a given registrar to its current member groups 6614 */ 6615 private HashMap mapRegToGroups(ServiceRegistrar reg, String[] groups) { 6616 HashMap groupsMap = new HashMap(1); 6617 groupsMap.put(reg,groups); 6618 return groupsMap; 6619 }//end mapRegToGroups 6620 6621 /** Given a set of registrars that have just been discarded, this method 6622 * determines which of those registrars are contained in none of the 6623 * discovered sets of the active registrations; and then removes 6624 * those registrars from the global maps of registrars that are 6625 * maintained across all registrations. 6626 * 6627 * Note that this method must be called from within a synchronization 6628 * block. 6629 * 6630 * @param discardedRegs set of registrars that were just discarded 6631 */ 6632 private void maybeRemoveDiscardedRegsFromGlobalSet(Set discardedRegs) { 6633 for(Iterator itr = discardedRegs.iterator();itr.hasNext(); ) { 6634 maybeRemoveDiscardedRegFromGlobalSet(itr.next()); 6635 }//end loop(itr) 6636 }//end maybeRemoveDiscardedRegsFromGlobalSet 6637 6638 /** Given a registrar that has just been discarded, this method 6639 * determines if that registrar is contained in none of the discovered 6640 * sets of the active registrations; and then removes that registrar 6641 * from the global maps of registrars that are maintained across all 6642 * registrations. 6643 * 6644 * Note that this method must be called from within a synchronization 6645 * block. 6646 * 6647 * @param dReg set of registrars that were just discarded 6648 */ 6649 private void maybeRemoveDiscardedRegFromGlobalSet(Object dReg) { 6650 for(Iterator jtr=registrationByID.values().iterator();jtr.hasNext();){ 6651 RegistrationInfo regInfo = (RegistrationInfo)jtr.next(); 6652 if( (regInfo.discoveredRegsMap).containsKey(dReg) ) { 6653 return; // this dReg is in at least 1 regInfo, goto next reg 6654 }//endif 6655 }//end loop(jtr) 6656 /* discarded reg contained in no regInfo, remove it from map */ 6657 allDiscoveredRegs.remove(dReg); 6658 }//end maybeRemoveDiscardedRegFromGlobalSet 6659 6660 /** For each registrar referenced in the global map allDiscoveredRegs, 6661 * this method replaces the associated set of member groups with the 6662 * corresponding set in the given registrars-to-groups map. This 6663 * method should be called only after a changed event is received 6664 * from the discovery manager. 6665 * 6666 * Note that this method must be called from within a synchronization 6667 * block. 6668 * 6669 * @param groupsMap map containing the registrars and their new groups 6670 */ 6671 private void updateGroupsInGlobalSet(Map groupsMap) { 6672 Set eSet = groupsMap.entrySet(); 6673 for(Iterator itr = eSet.iterator(); itr.hasNext(); ) { 6674 Map.Entry pair = (Map.Entry)itr.next(); 6675 ServiceRegistrar reg = (ServiceRegistrar)pair.getKey(); 6676 if(allDiscoveredRegs.containsKey(reg)) { 6677 LookupLocator loc 6678 = ((LocatorGroupsStruct)allDiscoveredRegs.get(reg)).locator; 6679 String[] newGroups = (String[])pair.getValue(); 6680 LocatorGroupsStruct locGroups 6681 = new LocatorGroupsStruct(loc,newGroups); 6682 allDiscoveredRegs.put(reg,locGroups); 6683 }//endif 6684 }//end loop 6685 }//end updateGroupsInGlobalSet 6686 6687 /** 6688 * This method constructs the appropriate remote discovery event from the 6689 * information contained in the input parameters. This method encapsulates 6690 * common exception-handling functionality. If the remote discovery 6691 * event cannot be successfully constructed, null will be returned. 6692 * 6693 * @param regInfo the data structure record corresponding to the 6694 * registration whose listener will receive the event 6695 * @param groupsMap map containing the registrars, and their corresponding 6696 * member groups, to include in the event 6697 * @param discarded flag indicating whether the registrars included in 6698 * the event have been discarded or discovered 6699 * 6700 * @return instance of <code>RemoteDiscoveryEvent</code> containing the 6701 * appropriate information corresponding to the input registration 6702 * record 6703 */ 6704 private RemoteDiscoveryEvent buildEvent(RegistrationInfo regInfo, 6705 Map<ServiceRegistrar,String[]> groupsMap, 6706 boolean discarded) 6707 { 6708 RemoteDiscoveryEvent newEvent = null; 6709 if(groupsMap.size() > 0) { 6710 try { 6711 newEvent = new RemoteDiscoveryEvent(outerProxy, 6712 regInfo.eventID, 6713 ++regInfo.seqNum, 6714 regInfo.handback, 6715 discarded, 6716 groupsMap); 6717 logInfoEvents(groupsMap,regInfo.eventID,regInfo.seqNum, 6718 regInfo.handback,discarded, 6719 eventsLogger, Level.FINE); 6720 } catch (IOException e) { 6721 /* The constructor for <code>RemoteDiscoveryEvent</code> 6722 * throws an <code>IOException</code> if the constructor 6723 * fails to successfully serialize even one registrar from 6724 * the input set (which means there is no need to send the 6725 * event since there are no marshalled registrars to send). 6726 * When such a situation occurs, register an ERROR status 6727 * attribute (along with a Comment attribute describing the 6728 * nature of the problem) to all lookup services with which 6729 * this service is registered. 6730 * 6731 * Administrative clients, as well as clients that use this 6732 * service should have registered for notification of the 6733 * existence of this attribute. 6734 */ 6735 String eStr = "Failed to serialize ALL registrars during " 6736 +"event construction ... could not send event"; 6737 problemLogger.log(Level.INFO, eStr, e); 6738 Entry[] errorAttrs = 6739 new Entry[] { new FiddlerStatus(StatusType.WARNING), 6740 new Comment(eStr) 6741 }; 6742 joinMgr.addAttributes(errorAttrs,true); 6743 }//end try 6744 }//endif 6745 return newEvent; 6746 }//end buildEvent 6747 6748 /** 6749 * This method simply queues a new <code>SendEventTask</code> instance 6750 * that will send the given remote event to the given registration's 6751 * listener. 6752 * 6753 * @param regInfo the data structure record corresponding to the 6754 * registration whose listener will receive the event 6755 * 6756 * @param event the instance of <code>RemoteDiscoveryEvent</code> to 6757 * send to the registration's listener 6758 */ 6759 private void queueEvent(RegistrationInfo regInfo, 6760 RemoteDiscoveryEvent event) 6761 { 6762 executorService.execute( 6763 Security.withContext(new SendEventTask(regInfo,event), context) 6764 ); 6765 }//end queueEvent 6766 /* END Private Event-Related Methods ----------------------------------- */ 6767 6768 /* BEGIN Persistent State Logging Interfaces & Classes ----------------- */ 6769 /** 6770 * Writes the current state of this service to persistent storage. 6771 * <p> 6772 * A 'snapshot' of the service's current state is represented by 6773 * the data contained in certain fields defined in the service. 6774 * That data represents many changes -- over time -- to the service's 6775 * state. This method will record that data to a file referred to as 6776 * the snapshot file. 6777 * <p> 6778 * The data written by this method to the snapshot file -- as well as 6779 * the format of the file -- is shown below: 6780 * <ul> 6781 * <li> the service's class name 6782 * <li> log format version number 6783 * <li> the unique ID of the proxy to the current instance of this service 6784 * <li> the current event ID 6785 * <li> the current join state of this service 6786 * <li> the current configuration parameters of this service 6787 * <li> contents of the container holding the current set of registrations 6788 * <li> null (termination 'marker' for the set of registrations) 6789 * </ul> 6790 * Each data item is written to the snapshot file in serialized form. 6791 * 6792 * @see FiddlerImpl.LocalLogHandler 6793 */ 6794 private void takeSnapshot(OutputStream out) throws IOException { 6795 ObjectOutputStream stream = new ObjectOutputStream(out); 6796 /* Stable information about the current instance of this service */ 6797 stream.writeUTF(FiddlerImpl.class.getName()); 6798 stream.writeInt(LOG_VERSION); 6799 stream.writeObject(proxyID); 6800 /* The current event ID assigned to the discovery events being sent */ 6801 stream.writeLong(curEventID); 6802 /* The current join state of this service */ 6803 stream.writeObject(thisServicesGroups); 6804 stream.writeObject(thisServicesLocators); 6805 stream.writeObject( marshalAttributes(this,thisServicesAttrs) ); 6806 /* The current configuration parameters of this service */ 6807 stream.writeLong(leaseBound); 6808 stream.writeInt(snapshotThresh); 6809 stream.writeFloat(snapshotWt); 6810 /* The current set of registrations */ 6811 for(Iterator iter=registrationByID.values().iterator();iter.hasNext();) 6812 { 6813 stream.writeObject(iter.next()); 6814 }//end loop 6815 stream.writeObject(null); //termination marker 6816 stream.flush(); 6817 }//end takeSnapshot 6818 6819 /** 6820 * Retrieve the contents of the snapshot file and reconstitute the 'base' 6821 * state of this service from the retrieved data. 6822 * <p> 6823 * Refer to <code>takeSnapshot</code> for a description of the data 6824 * retrieved by this method from the snapshot file. 6825 * <p> 6826 * During recovery, the state of the service at the time of a crash 6827 * or outage is re-constructed by first reconstituting the 'base state' 6828 * from the snapshot file; and then modifying that base state according 6829 * to the records retrieved from the log file. This method is invoked to 6830 * perform the first step in that reconstruction. As each registered 6831 * service or event is retrieved, it is inserted into its appropriate 6832 * container object. 6833 * <p> 6834 * Because events can be generated before the next snapshot is taken, 6835 * the event sequence numbers must be incremented. This is because the 6836 * event specification requires that a set of event sequence numbers 6837 * corresponding to an particular event type (a particular event ID) 6838 * be monotonically increasing. Since the number of events that might 6839 * have been sent is arbitrary, each sequence number will be incremented 6840 * by a 'large' number so as to guarantee adherence to the specification. 6841 * 6842 * @see FiddlerImpl.LocalLogHandler#takeSnapshot 6843 * @see FiddlerImpl.LocalLogHandler 6844 */ 6845 private void recoverSnapshot(InputStream in) 6846 throws IOException, ClassNotFoundException 6847 { 6848 ObjectInputStream stream = new ObjectInputStream(in); 6849 /* Retrieve the service's stable information */ 6850 if (!FiddlerImpl.class.getName().equals(stream.readUTF())) { 6851 throw new IOException("log from wrong implementation"); 6852 }//endif 6853 if (stream.readInt() != LOG_VERSION) { 6854 throw new IOException("wrong log format version"); 6855 }//endif 6856 proxyID = (Uuid)stream.readObject(); 6857 /* Retrieve the current event ID */ 6858 curEventID = stream.readLong(); 6859 /* Retrieve the current join state of this service. Groups first. */ 6860 thisServicesGroups = (String[])stream.readObject(); 6861 /* Retrieve and re-prepare the locators to join (drop bad locs) */ 6862 thisServicesLocators = prepareOldLocators 6863 ( recoveredLocatorToJoinPreparer, 6864 (LookupLocator[])stream.readObject() ); 6865 /* Retrieve the attributes to register with each lookup service. */ 6866 MarshalledObject[] marshalledAttrs 6867 = (MarshalledObject[])stream.readObject(); 6868 thisServicesAttrs = unmarshalAttributes(this, marshalledAttrs); 6869 /* Retrieve the current configuration parameters of this service */ 6870 leaseBound = stream.readLong(); 6871 snapshotThresh = stream.readInt(); 6872 snapshotWt = stream.readFloat(); 6873 RegistrationInfo regInfo; 6874 while ((regInfo = (RegistrationInfo)stream.readObject()) != null) { 6875 regInfo.prepare(recoveredListenerPreparer, recoveredLocatorToDiscoverPreparer); 6876 regInfo.seqNum += Integer.MAX_VALUE; 6877 addRegistration(regInfo); 6878 }//end loop 6879 initialStartup = false; 6880 }//end recoverSnapshot 6881 6882 /** 6883 * Add a state-change record to persistent storage. 6884 * <p> 6885 * Whenever a significant change occurs to Fiddler's state, this 6886 * method is invoked to record that change in a file called a log file. 6887 * Each record written to the log file is an object reflecting both 6888 * the data used and the ACTIONS taken to make one change to that 6889 * state at a particular point in time. If the number of records 6890 * contained in the log file exceeds the pre-defined threshold, 6891 * a snapshot of Fiddler's current state will be recorded. 6892 * <p> 6893 * Whenever one of the following state changes occurs, this method 6894 * will be invoked with the appropriate implementation of the 6895 * LogRecord interface as the input argument. 6896 * <ul> 6897 * <li> new attributes were added to Fiddler's attributes with lookup 6898 * <li> Fiddler's existing attributes with lookup were modified 6899 * 6900 * <li> new groups were added to the set of groups Fiddler should join 6901 * <li> Fiddler's existing groups to join were replaced with a new set 6902 * <li> Fiddler's existing groups to join were removed 6903 * 6904 * <li> new locators were added to the set of locators Fiddler should join 6905 * <li> Fiddler's existing locators to join were replaced with a new set 6906 * <li> Fiddler's existing locators to join were removed 6907 * 6908 * <li> the bound on granted lease durations was set to a new value 6909 * <li> weight factor used to determine when to take a snapshot was changed 6910 * <li> threshold used to determine when to take a snapshot was changed 6911 * 6912 * <li> a registration request for use of Fiddler's resources was granted 6913 * 6914 * <li> groups were added to a registration's set of groups to discover 6915 * <li> the set of groups to discover for a registration was replaced 6916 * <li> the set of groups to discover for a registration was removed 6917 * 6918 * <li> locators were added to a registration's set of locators to discover 6919 * <li> the set of locators to discover for a registration was replaced 6920 * <li> the set of locators to discover for a registration was removed 6921 * 6922 * <li> a lease on a registration with Fiddler was renewed 6923 * <li> a set of registration leases with Fiddler were renewed 6924 * <li> a lease on a registration with Fiddler was cancelled 6925 * <li> a set of registration leases with Fiddler were cancelled 6926 * 6927 * </ul> 6928 * 6929 * @see org.apache.river.reggie.RegistrarImpl.LocalLogHandler 6930 */ 6931 private void addLogRecord(LogRecord rec) { 6932 if(log == null) return;//not persistent, don't log 6933 6934 logInfoAddLogRecord(rec); 6935 try { 6936 log.update(rec, true); 6937 if (++logFileSize >= snapshotThresh) { 6938 int snapshotSize = registrationByID.size(); 6939 if ((float)logFileSize >= snapshotWt*((float)snapshotSize)) { 6940 /* take snapshot */ 6941 snapshotThreadSyncObj.signal(); 6942 // concurrentObj.waiterNotify(snapshotThreadSyncObj); 6943 }//endif 6944 }//endif 6945 } catch (Exception e) { 6946 if (!Thread.currentThread().isInterrupted()) { 6947 /* If log updating fails, then register an ERROR status 6948 * attribute (along with a Comment attribute describing the 6949 * nature of the problem) to all lookup services with which 6950 * this service is registered. 6951 * 6952 * Administrative clients, as well as clients that use this 6953 * service should have registered for notification of the 6954 * existence of this attribute. 6955 */ 6956 String eStr = "Failure while updating the persistent log " 6957 +"containing the service state"; 6958 problemLogger.log(Level.INFO, eStr, e); 6959 Entry[] errorAttrs = new Entry[] 6960 { new FiddlerStatus(StatusType.ERROR), 6961 new Comment(eStr) 6962 }; 6963 joinMgr.addAttributes(errorAttrs,true); 6964 }//endif 6965 } 6966 }//end addLogRecord 6967 6968 /** 6969 * Interface defining the method(s) that must be implemented by each of 6970 * the concrete LogObj classes. This allows for the definition of 6971 * object-dependent invocations of the appropriate implementation of 6972 * the method(s) declared in this interface. 6973 */ 6974 private static interface LogRecord extends Serializable { 6975 void apply(FiddlerImpl fiddlerImpl); 6976 } 6977 6978 /* 1. Definitions related to state changes generated by JoinAdmin */ 6979 6980 /** 6981 * LogObj class whose instances are recorded to the log file whenever 6982 * new attributes are added to this service's existing set of attributes. 6983 * 6984 * @see FiddlerImpl.LocalLogHandler 6985 */ 6986 private static class LookupAttrsAddedLogObj implements LogRecord { 6987 private static final long serialVersionUID = 4983778026976938585L; 6988 /** The attributes that were added to each lookup service with which 6989 * this service is registered, written out in marshalled form. 6990 * @serial 6991 */ 6992 private MarshalledObject[] marshalledAttrs; 6993 /** Constructs this class and stores the attributes that were added */ 6994 public LookupAttrsAddedLogObj(FiddlerImpl fiddlerImpl, Entry[] attrs) { 6995 this.marshalledAttrs = marshalAttributes(fiddlerImpl,attrs); 6996 } 6997 /** Modifies this service's state by adding (after unmarshalling) the 6998 * elements of marshalledAttrs to the service's existing set of 6999 * attributes. 7000 * @see FiddlerImpl.LocalLogHandler#applyUpdate 7001 */ 7002 public void apply(FiddlerImpl fiddlerImpl) { 7003 logInfoPersist("Log recovery: apply adding lookup attributes"); 7004 Entry[] attrs = unmarshalAttributes(fiddlerImpl, marshalledAttrs); 7005 fiddlerImpl.thisServicesAttrs 7006 = LookupAttributes.add(fiddlerImpl.thisServicesAttrs,attrs); 7007 } 7008 }//end LookupAttrsAddedLogObj 7009 7010 /** 7011 * LogObj class whose instances are recorded to the log file whenever 7012 * the attributes currently associated with this service in the lookup 7013 * services with which it is registered are modified. 7014 * 7015 * @see FiddlerImpl.LocalLogHandler 7016 */ 7017 private static class LookupAttrsModifiedLogObj implements LogRecord { 7018 private static final long serialVersionUID = 2671139518188470469L; 7019 /** The attribute set templates used to select the attributes (from 7020 * the service's existing set of attributes) that were modified, 7021 * written out in marshalled form. 7022 * @serial 7023 */ 7024 private MarshalledObject[] marshalledAttrTmpls; 7025 /** The attributes with which this service's existing attributes 7026 * were modified, written out in marshalled form. 7027 * @serial 7028 */ 7029 private MarshalledObject[] marshalledModAttrs; 7030 /** Constructs this class and stores the modified attributes */ 7031 public LookupAttrsModifiedLogObj(FiddlerImpl fiddlerImpl, 7032 Entry[] attrTmpls, 7033 Entry[] modAttrs) 7034 { 7035 this.marshalledAttrTmpls = marshalAttributes 7036 (fiddlerImpl,attrTmpls); 7037 this.marshalledModAttrs = marshalAttributes(fiddlerImpl,modAttrs); 7038 } 7039 /** Modifies this service's state by modifying (after unmarshalling) 7040 * the service's existing attributes according to the contents of 7041 * marshalledAttrTmpls and marshalledModAttrs. 7042 * @see FiddlerImpl.LocalLogHandler#applyUpdate 7043 */ 7044 public void apply(FiddlerImpl fiddlerImpl) { 7045 logInfoPersist("Log recovery: apply modifying lookup attributes"); 7046 Entry[] attrTmpls = unmarshalAttributes 7047 (fiddlerImpl, marshalledAttrTmpls); 7048 Entry[] modAttrs = unmarshalAttributes 7049 (fiddlerImpl, marshalledModAttrs); 7050 fiddlerImpl.thisServicesAttrs 7051 = LookupAttributes.modify(fiddlerImpl.thisServicesAttrs, 7052 attrTmpls, modAttrs); 7053 } 7054 }//end LookupAttrsModifiedLogObj 7055 7056 /** 7057 * LogObj class whose instances are recorded to the log file whenever 7058 * the set containing the names of the groups whose members are lookup 7059 * services the lookup discovery service wishes to register with (join) 7060 * is modified in some way; for example, through the invocation of: 7061 * <code>JoinAdmin.addLookupGroups</code>, 7062 * <code>JoinAdmin.removeLookupGroups</code> or 7063 * <code>JoinAdmin.setLookupGroups</code>. 7064 * 7065 * @see FiddlerImpl.LocalLogHandler 7066 */ 7067 private static class LookupGroupsChangedLogObj implements LogRecord { 7068 private static final long serialVersionUID = -6973676200404539919L; 7069 /** The new groups whose members are the lookup services this 7070 * service should join. 7071 * @serial 7072 */ 7073 private String[] groups; 7074 /** Constructs this class and stores the new groups */ 7075 public LookupGroupsChangedLogObj(String[] groups) { 7076 this.groups = groups; 7077 } 7078 /** Modifies this service's state by modifying this service's existing 7079 * set of 'groups to join'. 7080 * @see FiddlerImpl.LocalLogHandler#applyUpdate 7081 */ 7082 public void apply(FiddlerImpl fiddlerImpl) { 7083 logInfoPersist 7084 ("Log recovery: apply changing lookup groups to join"); 7085 fiddlerImpl.thisServicesGroups = groups; 7086 } 7087 }//end LookupGroupsChangedLogObj 7088 7089 /** 7090 * LogObj class whose instances are recorded to the log file whenever 7091 * the set containing the instances of <code>LookupLocator</code> that 7092 * correspond to specific lookup services the lookup discovery service 7093 * wishes to register with (join) is modified in some way; for example, 7094 * through the invocation of: 7095 * <code>JoinAdmin.addLookupLocators</code>, 7096 * <code>JoinAdmin.removeLookupLocators</code> or 7097 * <code>JoinAdmin.setLookupLocators</code>. 7098 * 7099 * @see FiddlerImpl.LocalLogHandler 7100 */ 7101 private static class LookupLocatorsChangedLogObj implements LogRecord { 7102 private static final long serialVersionUID = 6448427261140043291L; 7103 /** The locators that correspond to the new lookup services this 7104 * service should join. 7105 * @serial 7106 */ 7107 private LookupLocator[] locators; 7108 /** Constructs this class and stores the new locators */ 7109 public LookupLocatorsChangedLogObj(LookupLocator[] locators) { 7110 this.locators = locators; 7111 } 7112 /** Modifies this service's state by modifying this service's existing 7113 * set of 'locators to join'. 7114 * @see FiddlerImpl.LocalLogHandler#applyUpdate 7115 */ 7116 public void apply(FiddlerImpl fiddlerImpl) { 7117 logInfoPersist 7118 ("Log recovery: apply changing lookup locators to join"); 7119 fiddlerImpl.thisServicesLocators = 7120 prepareOldLocators(fiddlerImpl.recoveredLocatorToJoinPreparer,locators); 7121 } 7122 }//end LookupLocatorsChangedLogObj 7123 7124 /* 2. Definitions related to state changes generated by FiddlerAdmin */ 7125 7126 /** 7127 * LogObj class whose instances are recorded to the log file whenever a 7128 * new value is assigned to the least upper bound applied during the 7129 * determination of the duration of the lease on a requested registration. 7130 * 7131 * @see FiddlerImpl.LocalLogHandler 7132 */ 7133 private static class LeaseBoundSetLogObj implements LogRecord { 7134 private static final long serialVersionUID = 6084059678114714281L; 7135 /** The new least upper bound used to determine a lease's duration. 7136 * @serial 7137 */ 7138 private long newLeaseBound; 7139 /** Constructs this class and stores the new lease duration bound */ 7140 public LeaseBoundSetLogObj(long newLeaseBound) { 7141 this.newLeaseBound = newLeaseBound; 7142 } 7143 /** Modifies this service's state by setting the value of the private 7144 * leaseBound field to the value of the new bound. 7145 * @see FiddlerImpl.LocalLogHandler#applyUpdate 7146 */ 7147 public void apply(FiddlerImpl fiddlerImpl) { 7148 logInfoPersist 7149 ("Log recovery: apply changing lease duration bound"); 7150 fiddlerImpl.leaseBound = newLeaseBound; 7151 } 7152 }//end LeaseBoundSetLogObj 7153 7154 /** 7155 * LogObj class whose instances are recorded to the log file whenever a 7156 * new value is assigned to the Weight Factor applied to the Snapshot File 7157 * size used in the "time-to-take-a-snapshot determination" expression. 7158 * 7159 * @see FiddlerImpl.LocalLogHandler 7160 */ 7161 private static class SnapshotWeightSetLogObj implements LogRecord { 7162 private static final long serialVersionUID = -4079318959709953285L; 7163 /** The new snapshot weight factor. 7164 * @serial 7165 */ 7166 private float newWeight; 7167 /** Constructs this class and stores the new weight factor */ 7168 public SnapshotWeightSetLogObj(float newWeight) { 7169 this.newWeight = newWeight; 7170 } 7171 /** Modifies this service's state by setting the value of the private 7172 * snapshotWt field to the value of the new weight factor. 7173 * @see FiddlerImpl.LocalLogHandler#applyUpdate 7174 */ 7175 public void apply(FiddlerImpl fiddlerImpl) { 7176 logInfoPersist 7177 ("Log recovery: apply changing snapshot weight factor"); 7178 fiddlerImpl.snapshotWt = newWeight; 7179 } 7180 }//end SnapshotWeightSetLogObj 7181 7182 /** 7183 * LogObj class whose instances are recorded to the log file 7184 * whenever a new value is assigned to the Threshold used in the 7185 * "time-to-take-a-snapshot determination" expression. 7186 * 7187 * @see FiddlerImpl.LocalLogHandler 7188 */ 7189 private static class SnapshotThresholdSetLogObj implements LogRecord { 7190 private static final long serialVersionUID = 2952948867001823559L; 7191 /** The new snapshot threshold. 7192 * @serial 7193 */ 7194 private int newThreshold; 7195 /** Constructs this class and stores the new snapshot threshold */ 7196 public SnapshotThresholdSetLogObj(int newThreshold) { 7197 this.newThreshold = newThreshold; 7198 } 7199 /** Modifies this service's state by setting the value of the private 7200 * snapshotThresh field to the value of the new threshold. 7201 * @see FiddlerImpl.LocalLogHandler#applyUpdate 7202 */ 7203 public void apply(FiddlerImpl fiddlerImpl) { 7204 logInfoPersist 7205 ("Log recovery: apply changing log-to-snapshot threshold"); 7206 fiddlerImpl.snapshotThresh = newThreshold; 7207 } 7208 }//end SnapshotThresholdSetLogObj 7209 7210 /* 3. Definitions related to state changes made to the set of active 7211 * registrations, generated by client requests made through the 7212 * <code>LookupDiscoveryRegistration</code> interface. 7213 */ 7214 /** 7215 * LogObj class whose instances are recorded to the log file whenever 7216 * a registration is created and returned to a client. 7217 * 7218 * @see FiddlerImpl.LocalLogHandler 7219 */ 7220 private static class RegistrationGrantedLogObj implements LogRecord { 7221 private static final long serialVersionUID = 3983963008572188308L; 7222 /** Object which acts as a record of the current registration with the 7223 * lookup discovery service; containing all of the information about 7224 * that registration: IDs, managed sets, lease information, and 7225 * event registration information. 7226 * @serial 7227 */ 7228 private RegistrationInfo regInfo; 7229 /** Constructs this class and stores the registration information */ 7230 public RegistrationGrantedLogObj(RegistrationInfo regInfo) { 7231 this.regInfo = regInfo; 7232 } 7233 /** Modifies this service's state by registering the information 7234 * stored in the regInfo parameter; and by updating both the event 7235 * sequence number and the event ID for the registration. 7236 * 7237 * Note that the granting of a registration to a client typically 7238 * involves the modification of the managed sets in the discovery 7239 * manager, which usually involves starting the discovery protocol. 7240 * Since an IOException can occur when the discovery protocol fails 7241 * to start, and since such a situation is un-recoverable, this 7242 * method does the following: catches the exception, informs this 7243 * service's administrator by displaying the stack trace, and exits. 7244 * @see FiddlerImpl.LocalLogHandler#applyUpdate 7245 */ 7246 public void apply(FiddlerImpl fiddlerImpl) { 7247 logInfoPersist("Log recovery: apply recording granted registration" 7248 +" info\n (ID = " 7249 +regInfo.registrationID+")"); 7250 regInfo.seqNum += Integer.MAX_VALUE; 7251 try { 7252 /* Note that the locators of this recovered registration 7253 * were already successfully prepared in the method 7254 * RegistrationInfo.readObject() when this object was 7255 * deserialized during recovery. 7256 */ 7257 fiddlerImpl.addRegistration(regInfo); 7258 } catch(IOException e) { 7259 if( problemLogger.isLoggable(Level.SEVERE) ) { 7260 problemLogger.log(Level.SEVERE, "During log recovery " 7261 +"(apply addRegistration) -- failure in " 7262 +"multicast request protocol\n", e); 7263 }//endif 7264 fiddlerImpl.destroyDo(); 7265 } 7266 fiddlerImpl.curEventID++; 7267 } 7268 }//end RegistrationGrantedLogObj 7269 7270 /* 4. Definitions related to state changes made to the set of active 7271 * registrations, generated by client requests made through the 7272 * <code>LookupDiscoveryService</code> interface. 7273 */ 7274 7275 /** 7276 * LogObj class whose instances are recorded to the log file whenever 7277 * the managed set of groups corresponding to a registration is 7278 * is augmented with new elements. 7279 * 7280 * @see FiddlerImpl.LocalLogHandler 7281 */ 7282 private static class GroupsAddedToRegistrationLogObj implements LogRecord { 7283 private static final long serialVersionUID = 2L; 7284 /** The ID of the data structure record corresponding to the 7285 * registration whose managed set of groups was augmented. 7286 * @serial 7287 */ 7288 private Uuid registrationID; 7289 /** The set of groups added to the registration's managed set of groups 7290 * @serial 7291 */ 7292 private String[] groups; 7293 /** Constructs this class and stores the ID and new set of groups */ 7294 public GroupsAddedToRegistrationLogObj(Uuid registrationID, 7295 String[] groups) 7296 { 7297 this.registrationID = registrationID; 7298 this.groups = groups; 7299 } 7300 /** Modifies this service's state by adding the set of group names to 7301 * registration's managed set of groups, as well as by updating the 7302 * set of all groups (across all registrations) to discover. 7303 * 7304 * Note that the augmentation of a registration's set of groups 7305 * typically involves the modification of the managed sets in the 7306 * discovery manager, which usually involves starting the discovery 7307 * protocol. Since an IOException can occur when the discovery 7308 * protocol fails to start, and since such a situation is 7309 * un-recoverable, this method does the following: catches the 7310 * exception, informs this service's administrator by displaying 7311 * the stack trace, and exits. 7312 * @see FiddlerImpl.LocalLogHandler#applyUpdate 7313 */ 7314 public void apply(FiddlerImpl fiddlerImpl) { 7315 logInfoPersist("Log recovery: apply adding to groups to discover " 7316 +"for registration\n (ID = " 7317 +registrationID+")"); 7318 try { 7319 fiddlerImpl.addGroupsDo(registrationID, 7320 fiddlerImpl.registrationByID, 7321 groups); 7322 } catch(Exception e) { 7323 if( problemLogger.isLoggable(Level.SEVERE) ) { 7324 problemLogger.log(Level.SEVERE, "During log recovery " 7325 +"(apply addGroupsDO) -- failure in " 7326 +"multicast request protocol\n", e); 7327 }//endif 7328 fiddlerImpl.destroyDo(); 7329 } 7330 }//end apply 7331 }//end GroupsAddedToRegistrationLogObj 7332 7333 /** 7334 * LogObj class whose instances are recorded to the log file whenever 7335 * a the managed set of groups corresponding to a registration is 7336 * is replaced (set) with a new set of group names. 7337 * 7338 * @see FiddlerImpl.LocalLogHandler 7339 */ 7340 private static class GroupsSetInRegistrationLogObj implements LogRecord { 7341 static final long serialVersionUID = 2L; 7342 /** The ID of the data structure record corresponding to the 7343 * registration whose managed set of groups was replaced. 7344 * @serial 7345 */ 7346 private Uuid registrationID; 7347 /** The set of groups that replaced the registration's current 7348 * managed set of groups. 7349 * @serial 7350 */ 7351 private String[] groups; 7352 /** Constructs this class and stores the ID and new set of groups */ 7353 public GroupsSetInRegistrationLogObj(Uuid registrationID, 7354 String[] groups) 7355 { 7356 this.registrationID = registrationID; 7357 this.groups = groups; 7358 } 7359 /** Modifies this service's state by replacing the registration's 7360 * current managed set of groups with the set of group names 7361 * stored in this class by the constructor, as well as by updating 7362 * the set of all groups (across all registrations) to discover. 7363 * 7364 * Note that the replacement of a registration's set of groups 7365 * typically involves the modification of the managed sets in the 7366 * discovery manager, which usually involves starting the discovery 7367 * protocol. Since an IOException can occur when the discovery 7368 * protocol fails to start, and since such a situation is 7369 * un-recoverable, this method does the following: catches the 7370 * exception, informs this service's administrator by displaying 7371 * the stack trace, and exits. 7372 * @see FiddlerImpl.LocalLogHandler#applyUpdate 7373 */ 7374 public void apply(FiddlerImpl fiddlerImpl) { 7375 logInfoPersist("Log recovery: apply replacing groups to discover " 7376 +"for registration\n (ID = " 7377 +registrationID+") ..."); 7378 try { 7379 fiddlerImpl.setGroupsDo(registrationID, 7380 fiddlerImpl.registrationByID, 7381 groups); 7382 } catch(Exception e) { 7383 if( problemLogger.isLoggable(Level.SEVERE) ) { 7384 problemLogger.log(Level.SEVERE, "Failure during log " 7385 +"recovery (apply setGroups) -- \n", e); 7386 }//endif 7387 fiddlerImpl.destroyDo(); 7388 } 7389 } 7390 }//end GroupsSetInRegistrationLogObj 7391 7392 /** 7393 * LogObj class whose instances are recorded to the log file whenever 7394 * one or more elements of the managed set of groups corresponding to a 7395 * registration are removed. 7396 * 7397 * @see FiddlerImpl.LocalLogHandler 7398 */ 7399 private static class GroupsRemovedFromRegistrationLogObj 7400 implements LogRecord 7401 { 7402 private static final long serialVersionUID = 2L; 7403 /** The ID of the data structure record corresponding to the 7404 * registration with managed set from which groups were removed. 7405 * @serial 7406 */ 7407 private Uuid registrationID; 7408 /** The set of groups removed from the registration's managed set 7409 * of groups. 7410 * @serial 7411 */ 7412 private String[] groups; 7413 /** Constructs this class and stores the ID and groups to remove */ 7414 public GroupsRemovedFromRegistrationLogObj(Uuid registrationID, 7415 String[] groups) 7416 { 7417 this.registrationID = registrationID; 7418 this.groups = groups; 7419 } 7420 /** Modifies this service's state by removing the set of group names 7421 * from registration's managed set of groups, as well as by updating 7422 * the set of all groups (across all registrations) to discover. 7423 * 7424 * Note that the removal of one or more group names from a 7425 * registration's set of groups typically involves the modification 7426 * of the managed sets in the discovery manager, which usually 7427 * involves starting the discovery protocol. Since an IOException 7428 * can occur when the discovery protocol fails to start, and since 7429 * such a situation is un-recoverable, this method does the 7430 * following: catches the exception, informs this service's 7431 * administrator by displaying the stack trace, and exits. 7432 * @see FiddlerImpl.LocalLogHandler#applyUpdate 7433 */ 7434 public void apply(FiddlerImpl fiddlerImpl) { 7435 logInfoPersist("Log recovery: apply removing from groups to " 7436 +"discover for registration\n (ID = " 7437 +registrationID+")"); 7438 try { 7439 fiddlerImpl.removeGroupsDo(registrationID, 7440 fiddlerImpl.registrationByID, 7441 groups); 7442 } catch(Exception e) { 7443 if( problemLogger.isLoggable(Level.SEVERE) ) { 7444 problemLogger.log(Level.SEVERE, "Failure during log " 7445 +"recovery (apply removeGroups) -- \n", e); 7446 }//endif 7447 fiddlerImpl.destroyDo(); 7448 } 7449 } 7450 }//end GroupsRemovedFromRegistrationLogObj 7451 7452 /** 7453 * LogObj class whose instances are recorded to the log file whenever 7454 * the managed set of locators corresponding to a registration is 7455 * is augmented with new elements. 7456 * 7457 * @see FiddlerImpl.LocalLogHandler 7458 */ 7459 private static class LocsAddedToRegistrationLogObj implements LogRecord { 7460 private static final long serialVersionUID = 2L; 7461 /** The ID of the data structure record corresponding to the 7462 * registration whose managed set of locators was augmented. 7463 * @serial 7464 */ 7465 private Uuid registrationID; 7466 /** The set of locators added to the registration's managed set 7467 * @serial 7468 */ 7469 private LookupLocator[] locators; 7470 /** Constructs this class and stores the ID and new set of locators */ 7471 public LocsAddedToRegistrationLogObj(Uuid registrationID, 7472 LookupLocator[] locators) 7473 { 7474 this.registrationID = registrationID; 7475 this.locators = locators; 7476 } 7477 /** Modifies this service's state by adding the set of locators to 7478 * registration's managed set of locators, as well as by updating the 7479 * set of all locators (across all registrations) to discover. 7480 * @see FiddlerImpl.LocalLogHandler#applyUpdate 7481 */ 7482 public void apply(FiddlerImpl fiddlerImpl) { 7483 logInfoPersist("Log recovery: apply adding to locators to discover" 7484 +" for registration\n (ID = " 7485 +registrationID+")"); 7486 int nUnprepared = locators.length; 7487 /* Prepare the recovered locators */ 7488 locators = 7489 prepareOldLocators(fiddlerImpl.recoveredLocatorToDiscoverPreparer, locators); 7490 /* If all the locs were successfully prepared, add them to the 7491 * associated registration; otherwise, remove the registration 7492 * from the managed set. (For more information, see the comment 7493 * in RegistrationInfo.readObject()). 7494 */ 7495 if(nUnprepared == locators.length) { 7496 fiddlerImpl.addLocatorsDo( registrationID, 7497 fiddlerImpl.registrationByID, 7498 locators ); 7499 } else { 7500 if( problemLogger.isLoggable(Level.WARNING) ) { 7501 problemLogger.log(Level.WARNING, "failure preparing " 7502 +"locator while recovering " 7503 +"LocsAddedToRegistrationLogObj " 7504 +"... removing registration with ID = " 7505 +registrationID); 7506 }//endif 7507 try { 7508 fiddlerImpl.removeRegistration 7509 ( (RegistrationInfo)(fiddlerImpl.registrationByID.get 7510 (registrationID)) ); 7511 } catch(IOException e) { 7512 String eStr = "failure removing registration (ID = " 7513 +registrationID 7514 +") after locator preparation failure"; 7515 if( problemLogger.isLoggable(Level.INFO) ) { 7516 problemLogger.log(Level.INFO, eStr, e); 7517 }//endif 7518 Entry[] errorAttrs 7519 = new Entry[] 7520 { new FiddlerStatus(StatusType.ERROR), 7521 new Comment(eStr) 7522 }; 7523 fiddlerImpl.joinMgr.addAttributes(errorAttrs,true); 7524 } 7525 }//endif 7526 }//end apply 7527 }//end LocsAddedToRegistrationLogObj 7528 7529 /** 7530 * LogObj class whose instances are recorded to the log file whenever 7531 * the managed set of locators corresponding to a registration is 7532 * is replaced (set) with a new set of locators. 7533 * 7534 * @see FiddlerImpl.LocalLogHandler 7535 */ 7536 private static class LocsSetInRegistrationLogObj implements LogRecord { 7537 private static final long serialVersionUID = 2L; 7538 /** The ID of the data structure record corresponding to the 7539 * registration whose managed set of locators was replaced. 7540 * @serial 7541 */ 7542 private Uuid registrationID; 7543 /** The set of locators that replaced the registration's current 7544 * managed set of locators. 7545 * @serial 7546 */ 7547 private LookupLocator[] locators; 7548 /** Constructs this class and stores the ID and new set of locators */ 7549 public LocsSetInRegistrationLogObj(Uuid registrationID, 7550 LookupLocator[] locators) 7551 { 7552 this.registrationID = registrationID; 7553 this.locators = locators; 7554 } 7555 /** Modifies this service's state by replacing the registration's 7556 * current managed set of locators with the set of locators 7557 * stored in this class by the constructor, as well as by updating 7558 * the set of all locators (across all registrations) to discover. 7559 * @see FiddlerImpl.LocalLogHandler#applyUpdate 7560 */ 7561 public void apply(FiddlerImpl fiddlerImpl) { 7562 logInfoPersist("Log recovery: apply replacing locators to discover" 7563 +" for registration\n (ID = " 7564 +registrationID+")"); 7565 int nUnprepared = locators.length; 7566 /* Prepare the recovered locators */ 7567 locators = 7568 prepareOldLocators(fiddlerImpl.recoveredLocatorToDiscoverPreparer, locators); 7569 /* If all the locs were successfully prepared, set them in the 7570 * associated registration; otherwise, remove the registration 7571 * from the managed set. (For more information, see the comment 7572 * in RegistrationInfo.readObject()). 7573 */ 7574 if(nUnprepared == locators.length) { 7575 fiddlerImpl.setLocatorsDo( registrationID, 7576 fiddlerImpl.registrationByID, 7577 locators ); 7578 } else { 7579 if( problemLogger.isLoggable(Level.WARNING) ) { 7580 problemLogger.log(Level.WARNING, 7581 "failure preparing locator while " 7582 +"recovering LocsSetInRegistrationLogObj" 7583 +" ... removing registration with ID = " 7584 +registrationID); 7585 }//endif 7586 try { 7587 fiddlerImpl.removeRegistration 7588 ( (RegistrationInfo)(fiddlerImpl.registrationByID.get 7589 (registrationID)) ); 7590 } catch(IOException e) { 7591 String eStr = "failure removing registration (ID = " 7592 +registrationID 7593 +") after locator preparation failure"; 7594 if( problemLogger.isLoggable(Level.WARNING) ) { 7595 problemLogger.log(Level.WARNING, eStr, e); 7596 }//endif 7597 Entry[] errorAttrs 7598 = new Entry[] 7599 { new FiddlerStatus(StatusType.ERROR), 7600 new Comment(eStr) 7601 }; 7602 fiddlerImpl.joinMgr.addAttributes(errorAttrs,true); 7603 } 7604 }//endif 7605 } 7606 }//end LocsSetInRegistrationLogObj 7607 7608 /** 7609 * LogObj class whose instances are recorded to the log file whenever 7610 * one or more elements of the managed set of locators corresponding to a 7611 * registration are removed. 7612 * 7613 * @see FiddlerImpl.LocalLogHandler 7614 */ 7615 private static class LocsRemovedFromRegistrationLogObj 7616 implements LogRecord 7617 { 7618 private static final long serialVersionUID = 2L; 7619 /** The ID of the data structure record corresponding to the 7620 * registration with managed set from which locators were removed. 7621 * @serial 7622 */ 7623 private Uuid registrationID; 7624 /** The set of locators removed from the registration's managed set 7625 * of locators. 7626 * @serial 7627 */ 7628 private LookupLocator[] locators; 7629 /** Constructs this class and stores the ID and locators to remove */ 7630 public LocsRemovedFromRegistrationLogObj(Uuid registrationID, 7631 LookupLocator[] locators) 7632 { 7633 this.registrationID = registrationID; 7634 this.locators = locators; 7635 } 7636 /** Modifies this service's state by removing the set of locators 7637 * from registration's managed set of locators, as well as by updating 7638 * the set of all locators (across all registrations) to discover. 7639 * @see FiddlerImpl.LocalLogHandler#applyUpdate 7640 */ 7641 public void apply(FiddlerImpl fiddlerImpl) { 7642 logInfoPersist("Log recovery: apply removing from locators to " 7643 +"discover for registration\n (ID = " 7644 +registrationID+") ..."); 7645 int nUnprepared = locators.length; 7646 /* Prepare the recovered locators */ 7647 locators = 7648 prepareOldLocators(fiddlerImpl.recoveredLocatorToDiscoverPreparer, locators); 7649 /* If all the locs were successfully prepared, remove them from 7650 * the associated registration; otherwise, remove the registration 7651 * from the managed set. (For more information, see the comment 7652 * in RegistrationInfo.readObject()). 7653 */ 7654 if(nUnprepared == locators.length) { 7655 fiddlerImpl.removeLocatorsDo( registrationID, 7656 fiddlerImpl.registrationByID, 7657 locators ); 7658 } else { 7659 if( problemLogger.isLoggable(Level.WARNING) ) { 7660 problemLogger.log(Level.WARNING, "failure preparing " 7661 +"locator while recovering" 7662 +"LocsRemovedFromRegistrationLogObj " 7663 +"... removing registration with ID = " 7664 +registrationID); 7665 }//endif 7666 try { 7667 fiddlerImpl.removeRegistration 7668 ( (RegistrationInfo)(fiddlerImpl.registrationByID.get 7669 (registrationID)) ); 7670 } catch(IOException e) { 7671 String eStr = "failure removing registration (ID = " 7672 +registrationID 7673 +") after locator preparation failure"; 7674 if( problemLogger.isLoggable(Level.WARNING) ) { 7675 problemLogger.log(Level.WARNING, eStr, e); 7676 }//endif 7677 Entry[] errorAttrs 7678 = new Entry[] 7679 { new FiddlerStatus(StatusType.ERROR), 7680 new Comment(eStr) 7681 }; 7682 fiddlerImpl.joinMgr.addAttributes(errorAttrs,true); 7683 } 7684 }//endif 7685 } 7686 }//end LocsRemovedFromRegistrationLogObj 7687 7688 /** 7689 * LogObj class whose instances are recorded to the log file whenever 7690 * a lease on an existing registration (granted by the current backend 7691 * server of the lookup discovery service -- the lease grantor) is renewed. 7692 * 7693 * @see FiddlerImpl.LocalLogHandler 7694 */ 7695 private static class LeaseRenewedLogObj implements LogRecord { 7696 private static final long serialVersionUID = 2L; 7697 /** The ID of the data structure record corresponding to the 7698 * registration whose lease was renewed. 7699 * @serial 7700 */ 7701 private Uuid registrationID; 7702 /** The identifier assigned by the lease grantor to the lease that was 7703 * renewed. 7704 * @serial 7705 */ 7706 private Uuid leaseID; 7707 /** The new absolute time of expiration of the lease that was renewed. 7708 * @serial 7709 */ 7710 private long expiration; 7711 /** Constructs this class and stores the IDs and the expiration time */ 7712 public LeaseRenewedLogObj(Uuid registrationID, 7713 Uuid leaseID, 7714 long expiration) 7715 { 7716 this.registrationID = registrationID; 7717 this.leaseID = leaseID; 7718 this.expiration = expiration; 7719 } 7720 /** Modifies this service's state by renewing the lease with ID equal 7721 * to this class' leaseID field, and which corresponds to the 7722 * regInfo record. The lease will be renewed to have a new expiration 7723 * time equal to the value of the expiration field. 7724 * @see FiddlerImpl.LocalLogHandler#applyUpdate 7725 */ 7726 public void apply(FiddlerImpl fiddlerImpl) { 7727 logInfoPersist("Log recovery: apply renewing lease for " 7728 +"registration\n (ID = " 7729 +registrationID+")"); 7730 fiddlerImpl.renewLeaseAbs(registrationID, 7731 fiddlerImpl.registrationByID, 7732 leaseID, expiration); 7733 } 7734 }//end LeaseRenewedLogObj 7735 7736 /** 7737 * LogObj class whose instances are recorded to the log file whenever 7738 * a set of leases from a <code>LeaseMap</code> are renewed. 7739 * 7740 * @see FiddlerImpl.LocalLogHandler 7741 */ 7742 private static class LeasesRenewedLogObj implements LogRecord { 7743 private static final long serialVersionUID = 2L; 7744 /** The set of unique identifiers each assigned to a registration that 7745 * corresponds to one of the leases that was renewed. 7746 * @serial 7747 */ 7748 private Uuid[] registrationIDs; 7749 /** The set of identifiers each assigned by the lease grantor to one 7750 * of the leases that was renewed. 7751 * @serial 7752 */ 7753 private Uuid[] leaseIDs; 7754 /** The set of new absolute expiration times of each lease that was 7755 * renewed. 7756 * @serial 7757 */ 7758 private long[] expirations; 7759 /** Constructs this class and stores the sets of IDs and the set of 7760 * expiration times. 7761 */ 7762 public LeasesRenewedLogObj(Uuid[] registrationIDs, 7763 Uuid[] leaseIDs, 7764 long[] expirations) 7765 { 7766 this.registrationIDs = registrationIDs; 7767 this.leaseIDs = leaseIDs; 7768 this.expirations = expirations; 7769 } 7770 /** Modifies this service's state by renewing, with the corresponding 7771 * expiration time, each of the leases specified by the stored IDs. 7772 * @see FiddlerImpl.LocalLogHandler#applyUpdate 7773 */ 7774 public void apply(FiddlerImpl fiddlerImpl) { 7775 logInfoPersist("Log recovery: apply renewing leases corresponding " 7776 +"to "+registrationIDs.length 7777 +" registration IDs"); 7778 fiddlerImpl.renewLeasesAbs(registrationIDs, leaseIDs, expirations); 7779 } 7780 }//end LeasesRenewedLogObj 7781 7782 /** 7783 * LogObj class whose instances are recorded to the log file whenever 7784 * a lease on an existing registration (granted by the current backend 7785 * server of the lookup discovery service -- the lease grantor) is 7786 * cancelled. 7787 * 7788 * @see FiddlerImpl.LocalLogHandler 7789 */ 7790 private static class LeaseCancelledLogObj implements LogRecord { 7791 private static final long serialVersionUID = 2L; 7792 /** The ID of the data structure record corresponding to the 7793 * registration whose lease was cancelled. 7794 * @serial 7795 */ 7796 private Uuid registrationID; 7797 /** The identifier assigned by the lease grantor to the lease that was 7798 * cancelled. 7799 * @serial 7800 */ 7801 private Uuid leaseID; 7802 /** Constructs this class and stores the IDs corresponding to the 7803 * lease that was cancelled. 7804 */ 7805 public LeaseCancelledLogObj(Uuid registrationID, 7806 Uuid leaseID) { 7807 this.registrationID = registrationID; 7808 this.leaseID = leaseID; 7809 } 7810 /** Modifies this service's state by canceling the lease on the 7811 * registration with ID equal to that stored by the constructor, 7812 * as well as by updating the managed set of groups and locators 7813 * (across all registrations) in the appropriate way. 7814 * 7815 * Note that the cancellation of a lease typically involves the 7816 * modification of the managed sets in the discovery manager, which 7817 * usually involves starting the discovery protocol. Since an 7818 * IOException can occur when the discovery protocol fails to start, 7819 * and since such a situation is un-recoverable, this method does 7820 * the following: catches the exception, informs this service's 7821 * administrator by displaying the stack trace, and exits. 7822 * @see FiddlerImpl.LocalLogHandler#applyUpdate 7823 */ 7824 public void apply(FiddlerImpl fiddlerImpl) { 7825 try { 7826 logInfoPersist("Log recovery: apply cancelling lease for " 7827 +"registration\n (ID = " 7828 +registrationID+")"); 7829 fiddlerImpl.cancelLeaseDo(registrationID, 7830 fiddlerImpl.registrationByID, 7831 leaseID); 7832 } catch(IOException e) { 7833 if( problemLogger.isLoggable(Level.SEVERE) ) { 7834 problemLogger.log(Level.SEVERE, "During log recovery " 7835 +"(apply cancelLease) -- failure in " 7836 +"multicast request protocol\n", e); 7837 }//endif 7838 fiddlerImpl.destroyDo(); 7839 } catch (UnknownLeaseException e) { 7840 /* this exception should never occur when recovering */ 7841 } 7842 } 7843 }//end LeaseCancelledLogObj 7844 7845 /** 7846 * LogObj class whose instances are recorded to the log file whenever 7847 * a set of leases from a <code>LeaseMap</code> are cancelled. 7848 * 7849 * @see FiddlerImpl.LocalLogHandler 7850 */ 7851 private static class LeasesCancelledLogObj implements LogRecord { 7852 private static final long serialVersionUID = 2L; 7853 /** The set of unique identifiers each assigned to a registration that 7854 * corresponds to one of the leases that was cancelled. 7855 * @serial 7856 */ 7857 private Uuid[] registrationIDs; 7858 /** The set of identifiers each assigned by the lease grantor to one 7859 * of the leases that was cancelled. 7860 * @serial 7861 */ 7862 private Uuid[] leaseIDs; 7863 /** Constructs this class and stores the IDs corresponding to the 7864 * leases that were cancelled. 7865 */ 7866 public LeasesCancelledLogObj(Uuid[] registrationIDs, 7867 Uuid[] leaseIDs) 7868 { 7869 this.registrationIDs = registrationIDs; 7870 this.leaseIDs = leaseIDs; 7871 } 7872 /** Modifies this service's state by canceling each of the leases 7873 * specified by the stored IDs. 7874 * @see FiddlerImpl.LocalLogHandler#applyUpdate 7875 */ 7876 public void apply(FiddlerImpl fiddlerImpl) { 7877 logInfoPersist("Log recovery: apply cancelling leases " 7878 +"corresponding to "+registrationIDs.length 7879 +" registration IDs"); 7880 /* Because unknown leases were not weeded out, exceptions can 7881 * occur and be propagated upward, but they can be ignored. 7882 */ 7883 fiddlerImpl.cancelLeasesDo(registrationIDs, leaseIDs); 7884 } 7885 }//end LeasesCancelledLogObj 7886 /* END Persistent State Logging Interfaces & Classes ------------------- */ 7887 7888 /* BEGIN Private Logging Facility Methods ------------------------------ */ 7889 /* Returns a String containing the elements of the array */ 7890 private static String writeArrayElementsToString(Object[] arr) { 7891 if(arr == null) return "[]"; 7892 if(arr.length <= 0) { 7893 return "[]"; 7894 }//endif 7895 StringBuffer strBuf = new StringBuffer("["+arr[0]); 7896 for(int i=1;i<arr.length;i++){ 7897 strBuf.append(", ").append(arr[i]); 7898 }//end loop 7899 strBuf.append("]"); 7900 return strBuf.toString(); 7901 }//end writeArrayElementsToString 7902 7903 /* Logs the elements of the array to a single line of output */ 7904 private static void writeArrayElements(Object[] arr, 7905 Logger logger, 7906 Level level) 7907 { 7908 if((arr == null) || (logger == null) || !(logger.isLoggable(level))) { 7909 return; 7910 } 7911 String writeStr = writeArrayElementsToString(arr); 7912 logger.log(level,writeStr); 7913 }//end writeArrayElements 7914 7915 /* Returns a String containing the group names in writable form */ 7916 private static String writeGroupArrayToString(String[] groups) { 7917 if(groups == null) { 7918 return "[ALL_GROUPS]"; 7919 }//endif 7920 if(groups.length <= 0) { 7921 return "[]"; 7922 }//endif 7923 StringBuffer strBuf = null; 7924 if(groups[0].compareTo("") == 0) { 7925 strBuf = new StringBuffer("[The PUBLIC Group"); 7926 } else { 7927 strBuf = new StringBuffer("["+groups[0]); 7928 }//endif 7929 for(int i=1;i<groups.length;i++) { 7930 if(groups[i].compareTo("") == 0) { 7931 strBuf.append(", The PUBLIC Group"); 7932 } else { 7933 strBuf.append(", ").append(groups[i]); 7934 }//endif 7935 }//end loop 7936 strBuf.append("]"); 7937 return strBuf.toString(); 7938 }//end writeGroupArrayToString 7939 7940 /* Logs the group names to a single line of output */ 7941 private static void writeGroupArray(String[] groups, 7942 Logger logger, 7943 Level level) 7944 { 7945 if( (logger == null) || !(logger.isLoggable(level)) ) return; 7946 String writeStr = writeGroupArrayToString(groups); 7947 logger.log(level,writeStr); 7948 }//end writeGroupArray 7949 7950 /* Logs each registrar's locator on a single line of output */ 7951 private static void writeRegistrarsArray(ServiceRegistrar[] regs, 7952 Logger logger, 7953 Level level) 7954 { 7955 if((regs == null) || (logger == null) || !(logger.isLoggable(level))) { 7956 return; 7957 } 7958 if(regs.length == 0) { 7959 logger.log(level, "[NO REGISTRARS for Event]"); 7960 }//endif 7961 if(regs.length == 1) { 7962 try{ 7963 LookupLocator loc = regs[0].getLocator(); 7964 logger.log(level, "["+loc+"]"); 7965 }catch(SecurityException e){ 7966 logger.log(level, "[SecurityException]"); 7967 }catch(Exception e){ 7968 logger.log(level, "[Exception]"); 7969 } 7970 }//endif(regs.length == 1) 7971 if(regs.length > 1) { 7972 try{ 7973 LookupLocator loc = regs[0].getLocator(); 7974 logger.log(level, "["+loc+","); 7975 }catch(SecurityException e){ 7976 logger.log(level, "[SecurityException,"); 7977 }catch(Exception e){ 7978 logger.log(level, "[Exception,"); 7979 } 7980 for(int i=1;i<(regs.length-1);i++){ 7981 try{ 7982 LookupLocator loc = regs[i].getLocator(); 7983 logger.log(level, loc+","); 7984 }catch(SecurityException e){ 7985 logger.log(level, "SecurityException,"); 7986 }catch(Exception e){ 7987 logger.log(level, "Exception,"); 7988 } 7989 }//end loop 7990 try{ 7991 LookupLocator loc = regs[regs.length-1].getLocator(); 7992 logger.log(level, loc+"]"); 7993 }catch(SecurityException e){ 7994 logger.log(level, "SecurityException]"); 7995 }catch(Exception e){ 7996 logger.log(level, "Exception]"); 7997 } 7998 }//endif(regs.length > 1) 7999 }//end writeRegistrarsArray 8000 8001 /* Logs data on a single attribute to a file or standard output */ 8002 private static void writeAttribute(Entry attr, 8003 Logger logger, 8004 Level level) 8005 { 8006 if((attr == null) || (logger == null) || !(logger.isLoggable(level))) { 8007 return; 8008 } 8009 if(attr instanceof BasicServiceType) { 8010 logger.log(level, " attribute = BasicServiceType"); 8011 logger.log(level, " Display Name = " 8012 +((BasicServiceType)(attr)).getDisplayName()); 8013 logger.log(level, " Description = " 8014 +((BasicServiceType)(attr)).getShortDescription()); 8015 } else if(attr instanceof ServiceInfo) { 8016 logger.log(level, " attribute = ServiceInfo"); 8017 logger.log(level, " Service Name = " 8018 +((ServiceInfo)(attr)).name); 8019 logger.log(level, " Service Manufacturer = " 8020 +((ServiceInfo)(attr)).manufacturer); 8021 logger.log(level, " Service Vendor = " 8022 +((ServiceInfo)(attr)).vendor); 8023 logger.log(level, " Service Version = " 8024 +((ServiceInfo)(attr)).version); 8025 logger.log(level, " Service Model = " 8026 +((ServiceInfo)(attr)).model); 8027 logger.log(level, " Service Serial # = " 8028 +((ServiceInfo)(attr)).serialNumber); 8029 } else { 8030 logger.log(level, " attribute = "+attr); 8031 }//endif 8032 }//end writeAttribute 8033 8034 /* Logs data on each attribute in a set to a file or standard output */ 8035 private static void writeAttributes(Entry[] attrs, 8036 Logger logger, 8037 Level level) 8038 { 8039 if((attrs == null) || (logger == null) || !(logger.isLoggable(level))){ 8040 return; 8041 } 8042 for(int i=0;i<attrs.length;i++) { 8043 if(attrs[i] == null) continue; 8044 writeAttribute(attrs[i],logger,level); 8045 }//end loop 8046 logger.log(level,""); 8047 }//end writeAttributes 8048 8049 /* Logs startup data to file or standard output */ 8050 private void logInfoStartup() { 8051 if (startupLogger.isLoggable(Level.INFO)) { 8052 startupLogger.log 8053 (Level.INFO, "Fiddler started: {0}, {1}, {2}", 8054 new Object[] 8055 { (FiddlerImpl.this.serviceID).toString(), 8056 writeGroupArrayToString(thisServicesGroups), 8057 writeArrayElementsToString(thisServicesLocators) } ); 8058 }//endif 8059 if( startupLogger.isLoggable(Level.CONFIG) ) { 8060 if(persistDir != null) { 8061 startupLogger.log(Level.CONFIG, 8062 " Persistent state directory: {0}", 8063 persistDir); 8064 }//endif 8065 startupLogger.log(Level.CONFIG, 8066 "Attributes to register in each lookup service: "); 8067 writeAttributes(thisServicesAttrs,startupLogger,Level.CONFIG); 8068 }//endif 8069 }//end logInfoStartup 8070 8071 /* Logs shutdown/destroy data to file or standard output */ 8072 private void logInfoShutdown() { 8073 if (startupLogger.isLoggable(Level.INFO)) { 8074 startupLogger.log 8075 (Level.INFO, "Fiddler destroyed: {0}, {1}, {2}", 8076 new Object[] 8077 { (FiddlerImpl.this.serviceID).toString(), 8078 writeGroupArrayToString(thisServicesGroups), 8079 writeArrayElementsToString(thisServicesLocators) } ); 8080 }//endif 8081 }//end logInfoShutdown 8082 8083 /* Logs information related to the run method of a particular task */ 8084 private void logInfoTasks(String str) { 8085 if( tasksLogger.isLoggable(Level.FINEST) ) { 8086 tasksLogger.log(Level.FINEST, str); 8087 }//endif 8088 }//end logInfoTasks 8089 8090 /* Logs information about events that are sent */ 8091 private void logInfoEvents(String str) { 8092 if( eventsLogger.isLoggable(Level.FINE) ) { 8093 eventsLogger.log(Level.FINE, str); 8094 }//endif 8095 }//end logInfoEvents 8096 8097 /* Logs information about events that are sent */ 8098 private void logInfoEvents(Map groupsMap, 8099 long eventID, 8100 long seqNum, 8101 MarshalledObject handback, 8102 boolean discarded, 8103 Logger logger, 8104 Level level) 8105 { 8106 if( (logger == null) || !(logger.isLoggable(level)) ) { 8107 return; 8108 } 8109 String discardedStr = (discarded == true ? "DISCARDED":"DISCOVERED"); 8110 Object hb = null; 8111 if(handback != null) { 8112 try { 8113 hb = new MarshalledInstance(handback).get(false); 8114 } catch (ClassNotFoundException e) { 8115 problemLogger.log(Levels.HANDLED, 8116 "ClassNotFoundException when " 8117 +"unmarshalling handback",e); 8118 } catch (IOException e) { 8119 problemLogger.log(Levels.HANDLED, 8120 "IOException when unmarshalling " 8121 +"handback",e); 8122 } 8123 }//endif 8124 logger.log(level, "\n"+discardedStr+" Event:"); 8125 logger.log(level, " EventID = "+eventID); 8126 logger.log(level, " SeqNum = "+seqNum); 8127 logger.log(level, " handback = "+hb); 8128 ServiceRegistrar[] regs = 8129 (ServiceRegistrar[])(groupsMap.keySet()).toArray 8130 (new ServiceRegistrar[groupsMap.size()]); 8131 logger.log(level, " Registrars = "); 8132 writeRegistrarsArray(regs,logger,level); 8133 for(int i=0;i<regs.length;i++){ 8134 String[] curGroups = (String[])groupsMap.get(regs[i]); 8135 logger.log(level, " member groups ["+i+"] = "); 8136 writeGroupArray(curGroups,logger,level); 8137 }//end loop 8138 logger.log(level, ""); 8139 }//end logInfoEvents 8140 8141 /* Logs group state information over all active registrations */ 8142 private void logInfoGroups() { 8143 String[] allGroups = discoveryMgr.getGroups(); 8144 if( groupsLogger.isLoggable(Level.FINER) ) { 8145 groupsLogger.log(Level.FINER, 8146 "Group(s) over all registrations: "); 8147 writeGroupArray(allGroups,groupsLogger,Level.FINER); 8148 }//endif 8149 }//end logInfoGroups 8150 8151 /* Logs group state information over all active registrations */ 8152 private void logInfoGroups(String headerStr) { 8153 if( (headerStr != null) && (groupsLogger.isLoggable(Level.FINER)) ) { 8154 groupsLogger.log(Level.FINER, headerStr); 8155 }//endif 8156 logInfoGroups(); 8157 }//end logInfoGroups 8158 8159 /* Logs locator state information over all active registrations */ 8160 private void logInfoLocators() { 8161 LookupLocator[] allLocators = discoveryMgr.getLocators(); 8162 if( locatorsLogger.isLoggable(Level.FINER) ) { 8163 locatorsLogger.log(Level.FINER, 8164 "Locator(s) over all registrations: "); 8165 writeArrayElements(allLocators,locatorsLogger,Level.FINER); 8166 }//endif 8167 }//end logInfoLocators 8168 8169 /* Logs information useful to debugging the discard process */ 8170 private void logInfoDiscard(String str, Uuid regID) { 8171 if( (str != null) && (regID != null) 8172 && (discardLogger.isLoggable(Level.FINE)) ) 8173 { 8174 discardLogger.log(Level.FINE, str+" registrationID = "+regID); 8175 }//endif 8176 }//end logInfoDiscard 8177 8178 /* Logs information useful to debugging the discard process */ 8179 private void logInfoDiscard(String str) { 8180 if( discardLogger.isLoggable(Level.FINE) ) { 8181 discardLogger.log(Level.FINE, str); 8182 }//endif 8183 }//end logInfoDiscard 8184 8185 /* Logs information useful to debugging the leasing mechanism */ 8186 private void logInfoLease(String str, Uuid regID, Uuid leaseID) { 8187 if( (str != null) && (regID != null) 8188 && (leaseLogger.isLoggable(Level.FINER)) ) 8189 { 8190 leaseLogger.log(Level.FINER, str+" (registrationID,leaseID) = (" 8191 +regID+", "+leaseID+")"); 8192 }//endif 8193 }//end logInfoLease 8194 8195 /* Logs information useful to debugging the registration mechanism */ 8196 private void logInfoRegistration(String str, Object regInfo) { 8197 if( (str != null) && (regInfo != null) 8198 && (registrationLogger.isLoggable(Level.FINER)) ) 8199 { 8200 registrationLogger.log(Level.FINER, str+" {0}", regInfo); 8201 }//endif 8202 }//end logInfoRegistration 8203 8204 /* Logs information useful to debugging the logging mechanism */ 8205 private static void logInfoPersist(String str) { 8206 if( persistLogger.isLoggable(Level.FINEST) ) { 8207 persistLogger.log(Level.FINEST, str); 8208 }//endif 8209 }//end logInfoPersist 8210 8211 /* Logs information useful to debugging the addLogRecord method */ 8212 private void logInfoAddLogRecord(LogRecord rec) { 8213 if( !(persistLogger.isLoggable(Level.FINEST)) ) return; 8214 String logStr = "Logging a state change: Unknown log record instance"; 8215 /* JoinAdmin */ 8216 if(rec instanceof LookupAttrsAddedLogObj) { 8217 logStr = "Logging state change: lookup attributes added"; 8218 } else if (rec instanceof LookupAttrsModifiedLogObj) { 8219 logStr = "Logging state change: lookup attributes modified"; 8220 } else if (rec instanceof LookupGroupsChangedLogObj) { 8221 logStr = "Logging state change: groups to join changed to " 8222 +writeGroupArrayToString(thisServicesGroups); 8223 } else if (rec instanceof LookupLocatorsChangedLogObj) { 8224 logStr = "Logging state change: locators to join changed to " 8225 +writeArrayElementsToString(thisServicesLocators); 8226 /* FiddlerAdmin */ 8227 } else if (rec instanceof LeaseBoundSetLogObj) { 8228 logStr = "Logging state change: lease duration bound changed"; 8229 } else if (rec instanceof SnapshotWeightSetLogObj) { 8230 logStr = "Logging state change: snapshot weight factor changed"; 8231 } else if (rec instanceof SnapshotThresholdSetLogObj) { 8232 logStr = "Logging state change: log-to-snapshot threshold changed"; 8233 /* LookupDiscoveryService */ 8234 } else if (rec instanceof RegistrationGrantedLogObj) { 8235 logStr = "Logging state change: new registration granted"; 8236 /* LookupDiscoveryRegistration */ 8237 } else if (rec instanceof GroupsAddedToRegistrationLogObj) { 8238 logStr = "Logging state change: added new groups to " 8239 +"registration's set of groups to discover"; 8240 } else if (rec instanceof GroupsSetInRegistrationLogObj) { 8241 logStr = "Logging state change: replaced registration's set of " 8242 +"groups to discover"; 8243 } else if (rec instanceof GroupsRemovedFromRegistrationLogObj) { 8244 logStr = "Logging state change: removed groups from " 8245 +"registration's set of groups to discover"; 8246 } else if (rec instanceof LocsAddedToRegistrationLogObj) { 8247 logStr = "Logging state change: added new locators to " 8248 +"registration's set of locators to discover"; 8249 } else if (rec instanceof LocsSetInRegistrationLogObj) { 8250 logStr = "Logging state change: replaced registration's set of " 8251 +"locators to discover"; 8252 } else if (rec instanceof LocsRemovedFromRegistrationLogObj) { 8253 logStr = "Logging state change: removed locators from " 8254 +"registration's set of locators to discover"; 8255 } else if (rec instanceof LeaseRenewedLogObj) { 8256 logStr = "Logging state change: registration's lease renewed"; 8257 } else if (rec instanceof LeasesRenewedLogObj) { 8258 logStr = "Logging state change: set of leases renewed for a " 8259 +"set of registrations"; 8260 } else if (rec instanceof LeaseCancelledLogObj) { 8261 logStr = "Logging state change: registration's lease cancelled"; 8262 } else if (rec instanceof LeasesCancelledLogObj) { 8263 logStr = "Logging state change: set of leases cancelled for a " 8264 +"set of registrations"; 8265 }//endif 8266 logInfoPersist(logStr); 8267 }//end logInfoAddLogRecord 8268 /* END Private Logging Facility Methods -------------------------------- */ 8269 /* *************** END Private NON-Static Utility Methods ************** */ 8270 8271 }/*end class FiddlerImpl */