You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@river.apache.org by pe...@apache.org on 2013/04/12 10:11:54 UTC

svn commit: r1467198 - in /river/jtsk/skunk/qa_refactor/trunk/src: com/sun/jini/mercury/MailboxImpl.java com/sun/jini/mercury/MailboxImplInit.java net/jini/discovery/LookupLocatorDiscovery.java

Author: peter_firmstone
Date: Fri Apr 12 08:11:54 2013
New Revision: 1467198

URL: http://svn.apache.org/r1467198
Log:
Fix MailboxImpl constructor thread visibility and safe publication issues known to cause data race conditions.

Added:
    river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/mercury/MailboxImplInit.java
Modified:
    river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/mercury/MailboxImpl.java
    river/jtsk/skunk/qa_refactor/trunk/src/net/jini/discovery/LookupLocatorDiscovery.java

Modified: river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/mercury/MailboxImpl.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/mercury/MailboxImpl.java?rev=1467198&r1=1467197&r2=1467198&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/mercury/MailboxImpl.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/mercury/MailboxImpl.java Fri Apr 12 08:11:54 2013
@@ -37,6 +37,7 @@ import com.sun.jini.reliableLog.Reliable
 import com.sun.jini.reliableLog.LogException;
 import com.sun.jini.reliableLog.LogHandler;
 import com.sun.jini.start.LifeCycle;
+import com.sun.jini.start.Starter;
 import com.sun.jini.thread.InterruptedStatusThread;
 import com.sun.jini.thread.ReadersWriter;
 import com.sun.jini.thread.ReadersWriter.ConcurrentLockException;
@@ -153,7 +154,7 @@ See recoverSnapshot() for exact details 
 */
 
 class MailboxImpl implements MailboxBackEnd, TimeConstants, 
-    ServerProxyTrust, ProxyAccessor
+    ServerProxyTrust, ProxyAccessor, Starter
  
 {
 
@@ -200,7 +201,7 @@ class MailboxImpl implements MailboxBack
     static final Logger operationsLogger =
         Logger.getLogger(MERCURY + ".operations");
 
-    private static final String mailboxSourceClass = 
+    static final String mailboxSourceClass = 
 	MailboxImpl.class.getName();
 
     private static final String notifierSourceClass = 
@@ -260,32 +261,28 @@ class MailboxImpl implements MailboxBack
     /** ServiceInfo version value */
     private static final String VERSION = 
 	com.sun.jini.constants.VersionConstants.SERVER_VERSION;
+    /** Log format version */
+    private static final int LOG_VERSION = 2;
 
     /** The inner proxy of this server */
-    private /*final*/ MailboxBackEnd serverStub;
-    
+    private /*final*/ volatile MailboxBackEnd serverStub;
     /** The outter proxy of this server */
-    private /*final*/ MailboxProxy mailboxProxy;
-
+    private /*final*/ volatile MailboxProxy mailboxProxy;
     /** The admin proxy of this server */
-    private /*final*/ MailboxAdminProxy mailboxAdminProxy;
-
+    private /*final*/ volatile MailboxAdminProxy mailboxAdminProxy;
     /** Concurrent object (lock) to control read and write access */
     private final ReadersWriter concurrentObj = new ReadersWriter();
-
     /** Map from <code>Uuid</code> to <code>ServiceRegistration</code> */
     // HashMap is unsynchronized, but we are performing external
     // synchronization via the <code>concurrentObj</code> field. 
-    private HashMap regByID = new HashMap(); 
-
+    private final HashMap<Uuid,ServiceRegistration> regByID; 
     /**
      * Identity map of <tt>ServiceRegistration</tt>, ordered by lease 
      * expiration. This is a parallel data structure to <code>regByID</code>.
      */
     // TreeMap is unsynchronized, but we are performing external
     // synchronization via the <code>concurrentObj</code> field. 
-    private final TreeMap regByExpiration = new TreeMap();
-
+    private final TreeMap<ServiceRegistration,ServiceRegistration> regByExpiration;
     /** 
      * List of <tt>ServiceRegistration</tt>s that have event 
      * delivery enabled, but don't have any event delivery tasks 
@@ -294,8 +291,7 @@ class MailboxImpl implements MailboxBack
     // Using an ArrayList for random access performance. 
     // ArrayList is unsynchronized, but we are performing external
     // synchronization via the <code>concurrentObj</code> field. 
-    private List pendingReg = new ArrayList();
-
+    private final List<Uuid> pendingReg;
     /**
      * Map of <tt>ServiceRegistration</tt>s that have event 
      * delivery enabled and have event delivery tasks currently 
@@ -303,70 +299,47 @@ class MailboxImpl implements MailboxBack
      */
     // HashMap is unsynchronized, but we are performing external
     // synchronization via the <code>concurrentObj</code> field. 
-    private Map activeReg = new HashMap();
-
+    private final Map<Uuid,NotifyTask> activeReg;
     /** Reliable log to hold registration state information */
     // Note that event state is kept separately
-    private ReliableLog log;
-
-    /** Log format version */
-    private static final int LOG_VERSION = 2;
-
+    private final ReliableLog log;
     /** Flag indicating whether system is in a state of recovery */
-    private boolean inRecovery;
-
+    private volatile boolean inRecovery;
     /** Current number of records in the Log File since the last snapshot */
     private int logFileSize = 0;
-
     /** Log File must contain this many records before a snapshot is allowed */
 // TODO (FCS)- allow this to be a user configurable parameter
     private int logToSnapshotThreshold = 50;
-
     /** Object on which the snapshot-taking thread will synchronize */
     private final Object snapshotNotifier = new Object();
-
     /** Snapshot-taking thread */
-    private Thread snapshotter = null;
-
+    private final Thread snapshotter;
     /** The login context, for logging out */
-    protected LoginContext loginContext;
-
+    protected final LoginContext loginContext;
     /** Name of persistence directory */
-    private String persistenceDirectory = null;
-
+    private final String persistenceDirectory;
     /** Proxy preparer for listeners */
-    private ProxyPreparer listenerPreparer;
-
+    private final ProxyPreparer listenerPreparer;
     /** The exporter for exporting and unexporting */
-    protected Exporter exporter;
-    
+    protected final Exporter exporter;
    /** ServiceID returned from the lookup registration process */
-    private Uuid serviceID = null;
-
+    private volatile Uuid serviceID;
     /** Our activation ID */
-    private ActivationID activationID = null;
-
+    private final ActivationID activationID;
     /** Whether the activation ID has been prepared */
-    private boolean activationPrepared;
-
+    private final boolean activationPrepared;
     /** The activation system, prepared */
-    private ActivationSystem activationSystem;
-    
+    private final ActivationSystem activationSystem;
     /** <code>EventLogIterator</code> generator */
-    private final EventLogFactory eventLogFactory = new EventLogFactory();
-
+    private final EventLogFactory eventLogFactory;
     /** <code>LeasePeriodPolicy</code> for this service */
-    private LeasePeriodPolicy leasePolicy = null; 
-    
+    private final LeasePeriodPolicy leasePolicy; 
     /** <code>LandLordLeaseFactory</code> we use to create leases */
-    private LeaseFactory leaseFactory = null;
-
+    private volatile LeaseFactory leaseFactory;
     /** LocalLandlord to use with LandlordUtil calls */
-    private LocalLandlordAdaptor localLandlord = new LocalLandlordAdaptor();
-
+    private final LocalLandlordAdaptor localLandlord = new LocalLandlordAdaptor();
     /** Manager for joining lookup services */
     private JoinManager joiner = null;
-
     /** 
      * DiscoveryManager for joining lookup services. 
      * This can always be obtained from the JoinManager, so
@@ -375,90 +348,78 @@ class MailboxImpl implements MailboxBack
     private DiscoveryManagement lookupDiscMgr = null;
 
     /** The attributes to use when joining lookup services */
-    private Entry[] baseLookupAttrs = new Entry[] { 
+    private final Entry[] baseLookupAttrs = new Entry[] { 
 	    new ServiceInfo(PRODUCT, MANUFACTURER, VENDOR, VERSION, "", ""),
             new BasicServiceType("Event Mailbox")
     };
     private Entry[] lookupAttrs = new Entry[] {};
-
     /** 
      * The lookup groups we should join. 
      * Default is to join no groups. 
      */
     private String[] lookupGroups = LookupDiscovery.NO_GROUPS;
-
     /** 
      * The lookup locators we should join 
      * Default is to join with no locators. 
      */
     private LookupLocator[] lookupLocators = new LookupLocator[0];
-
     /* Preparer for initial and new lookup locators this service should
      * discover and join.
      */
     private static ProxyPreparer locatorToJoinPreparer;
-    
     /* Preparer for lookup locators this service should discover and join
      * that were previously prepared and which were recovered from this
      * service's persisted state.
      */
     private static ProxyPreparer recoveredLocatorToJoinPreparer;
-    
    /** Event delivery thread */
-    private Notifier notifier = null;
-
+    private final Thread notifier;
     /** Object for coordinating actions with the notification thread */
     private final Object eventNotifier = new Object();
-
     /** Registration expirer thread */
-    private ExpirationThread expirer = null;
-
+    private final Thread expirer;
     /** Earliest expiration time of any registration */
     private long minRegExpiration = Long.MAX_VALUE;
-
     /** Object for coordinating actions with the expire thread */
     private final Object expirationNotifier = new Object();
- 
     /** Object for coordinating the destroy process */
     private final Object destroyLock = new Object();
- 
     /** 
      * Flag that denotes whether or not destroy has already been called.
      * The variable is guarded by <code>destroyLock</code>.
      */
-    private boolean destroySucceeded = false;
-
+    private volatile boolean destroySucceeded = false;
     /**
      * When destroying the space, how long to wait for a clean
      * unexport (which allows the destroy call to return) before
      * giving up calling <code>unexport(true)</code>
      */
-    private long maxUnexportDelay;
-
-    /**
-     * Length of time to sleep between unexport attempts
-     */
-    private long unexportRetryDelay;
-    
+    private final long maxUnexportDelay;
+    /** Length of time to sleep between unexport attempts */
+    private final long unexportRetryDelay;
     /** 
      * Object used to prevent access to this service during the service's
      *  initialization or shutdown processing.
      */
     private final ReadyState readyState = new ReadyState();
-    
     /**
      * <code>LifeCycle</code> object used to notify starter framework
      * that this object's implementation reference, if any, should not
      * be held onto any longer. This is only used in the non-activatable case.
      */
-    private LifeCycle lifeCycle = null;
-
+    private volatile LifeCycle lifeCycle;
     /**
      * <code>boolean</code> flag used to determine persistence support.
      * Defaulted to true, and overridden in the constructor overload that takes
      * a <code>boolean</code> argument.
      */
-    private boolean persistent = true;
+    private final boolean persistent;
+    
+     // The following two fields are only required by start, called by the
+    // constructor thread and set to null after starting.
+    private Configuration config;
+    private Throwable thrown;
+    private volatile boolean started = false;
     
     ///////////////////////
     // Activation Methods
@@ -513,23 +474,24 @@ class MailboxImpl implements MailboxBack
     MailboxImpl(ActivationID activationID, MarshalledObject data) 
 	throws Exception
     {
-        if (operationsLogger.isLoggable(Level.FINER)) {
-	    operationsLogger.entering(mailboxSourceClass, 
-	        "MailboxImpl", 
-		new Object[] {activationID, data});
-	}
-	this.activationID = activationID;
-	try {
-	    // Initialize state
-	    init((String[])data.get());
-	} catch (Throwable e) {
-	    cleanup();
-	    initFailed(e);
-	}	  
-        if (operationsLogger.isLoggable(Level.FINER)) {
-	    operationsLogger.exiting(mailboxSourceClass, 
-	        "MailboxImpl");
-	}
+        this((String[])data.get(), activationID, true, new Object[] {activationID, data} );
+//        if (operationsLogger.isLoggable(Level.FINER)) {
+//	    operationsLogger.entering(mailboxSourceClass, 
+//	        "MailboxImpl", 
+//		new Object[] {activationID, data});
+//	}
+//	this.activationID = activationID;
+//	try {
+//	    // Initialize state
+//	    init((String[])data.get());
+//	} catch (Throwable e) {
+//	    cleanup();
+//	    initFailed(e);
+//	}	  
+//        if (operationsLogger.isLoggable(Level.FINER)) {
+//	    operationsLogger.exiting(mailboxSourceClass, 
+//	        "MailboxImpl");
+//	}
     }
     
     /////////////////////////
@@ -540,415 +502,703 @@ class MailboxImpl implements MailboxBack
      * instances. 
      * State information is still logged to persistent storage.
      * This method is only intended for debugging purposes at this time.
-     *
+     *  
      */
     // @param log directory where persistent state is maintained
     MailboxImpl(String[] configArgs, LifeCycle lc, boolean persistent) 
 	throws Exception
     {
-        if (operationsLogger.isLoggable(Level.FINER)) {
-	    operationsLogger.entering(mailboxSourceClass, 
-	        "MailboxImpl", 
-		new Object[] { configArgs, lc, Boolean.valueOf(persistent)});
-	}
-	try {
-	    lifeCycle = lc;
-	    this.persistent = persistent;
-            init(configArgs);
-	} catch (Throwable e) {
-	    cleanup();
-	    initFailed(e);
-	}	  
-        if (operationsLogger.isLoggable(Level.FINER)) {
-	    operationsLogger.exiting(mailboxSourceClass, 
-	        "MailboxImpl");
-	}
+        this(configArgs, null, persistent, new Object[] {Arrays.asList(configArgs), lc, Boolean.valueOf(persistent)});
+	lifeCycle = lc; 
+//        if (operationsLogger.isLoggable(Level.FINER)) {
+//	    operationsLogger.entering(mailboxSourceClass, 
+//	        "MailboxImpl", 
+//		new Object[] { configArgs, lc, Boolean.valueOf(persistent)});
+//	}
+//	try {
+//	    lifeCycle = lc;
+//	    this.persistent = persistent;
+//            init(configArgs);
+//	} catch (Throwable e) {
+//	    cleanup();
+//	    initFailed(e);
+//	}	  
+//        if (operationsLogger.isLoggable(Level.FINER)) {
+//	    operationsLogger.exiting(mailboxSourceClass, 
+//	        "MailboxImpl");
+//	}
+    }
+    
+    private MailboxImpl(String[] configArgs, final ActivationID activID, final boolean persistant, Object [] logMessage){
+        if (operationsLogger.isLoggable(Level.FINER)) {
+            operationsLogger.entering(
+		MailboxImpl.class.getName(), "MailboxImpl",logMessage );
+	}
+        this.persistent = persistant;
+        MailboxImplInit init = null;
+        final Configuration config;
+        LoginContext loginContext = null;
+        try {
+           if (operationsLogger.isLoggable(Level.FINER)) {
+                operationsLogger.entering(mailboxSourceClass, 
+                    "init", (Object[])configArgs);
+           }
+           config =
+                ConfigurationProvider.getInstance(
+                    configArgs, getClass().getClassLoader());
+            loginContext = (LoginContext) config.getEntry(
+                MERCURY, "loginContext", LoginContext.class, null);
+            if (loginContext != null) {
+//                doInitWithLogin(config, loginContext);
+                /* */
+                if (operationsLogger.isLoggable(Level.FINER)) {
+                    operationsLogger.entering(mailboxSourceClass, 
+                        "doInitWithLogin", new Object[] { config, loginContext});
+                }
+                loginContext.login();
+                try {
+                    init = Subject.doAsPrivileged(
+                        loginContext.getSubject(),
+                        new PrivilegedExceptionAction<MailboxImplInit>() {
+                            public MailboxImplInit run() throws Exception {
+//                                doInit(config);
+                                // Create these threads here so they inherit
+                                // current context.
+                                return new MailboxImplInit(config,
+                                        persistant, 
+                                        activID, 
+                                        baseLookupAttrs, 
+                                        new LocalLogHandler(),
+                                        persistant ? new SnapshotThread(): null,
+                                        new Notifier(config),
+                                        new ExpirationThread()
+                                        );
+                            }
+                        },
+                        null);
+                } catch (PrivilegedActionException e) {
+                    try {
+                        loginContext.logout();
+                    } catch (LoginException le) {
+        //TODO - Move to end of cleanup()
+                        if (initLogger.isLoggable(Levels.HANDLED)) {
+                            initLogger.log(Levels.HANDLED, "Trouble logging out", le);
+                        }
+                    }
+                    throw e.getException();
+                }
+                if (operationsLogger.isLoggable(Level.FINER)) {
+                    operationsLogger.exiting(mailboxSourceClass, 
+                        "doInitWithLogin");
+                }
+                /* */
+            } else {
+//                doInit(config);
+                init = new MailboxImplInit(config, 
+                        persistant, 
+                        activID, 
+                        baseLookupAttrs, 
+                        new LocalLogHandler(),
+                        persistant ? new SnapshotThread(): null,
+                        new Notifier(config),
+                        new ExpirationThread()
+                        );
+                
+            }
+            if (operationsLogger.isLoggable(Level.FINER)) {
+                operationsLogger.exiting(mailboxSourceClass, 
+                    "init");
+            }
+        } catch (Throwable t){
+            thrown = t;
+        } finally {
+            if (init != null){
+                activationID = init.activationID;
+                activationSystem = init.activationSystem;
+                activationPrepared = init.activationPrepared;
+                exporter = init.exporter;
+                listenerPreparer = init.listenerPreparer;
+                locatorToJoinPreparer = init.locatorToJoinPreparer;
+                leasePolicy = init.leasePolicy;
+                persistenceDirectory = init.persistenceDirectory;
+                recoveredLocatorToJoinPreparer = init.recoveredLocatorToJoinPreparer;
+                logToSnapshotThreshold = init.logToSnapshotThreshold;
+                log = init.log;
+                serviceID = init.serviceID;
+                lookupGroups = init.lookupGroups;
+                lookupLocators = init.lookupLocators;
+                lookupAttrs = init.lookupAttrs;
+                maxUnexportDelay = init.maxUnexportDelay;
+                unexportRetryDelay = init.unexportRetryDelay;
+                lookupDiscMgr = init.lookupDiscMgr;
+                regByExpiration = init.regByExpiration;
+                regByID = init.regByID;
+                activeReg = init.activeReg;
+                /** <code>EventLogIterator</code> generator */
+                eventLogFactory = init.eventLogFactory;
+                pendingReg = init.pendingReg;
+                snapshotter = init.snapshotter;
+                notifier = init.notifier;
+                expirer = init.expirer;
+                this.config = init.config;
+                this.loginContext = loginContext;
+                
+            } else {
+                activationID = activID;
+                activationSystem = null;
+                activationPrepared = false;
+                exporter = null;
+                listenerPreparer = null;
+                locatorToJoinPreparer = null;
+                leasePolicy = null;
+                persistenceDirectory = null;
+                recoveredLocatorToJoinPreparer = null;
+                logToSnapshotThreshold = 0;
+                log = null;
+                serviceID = null;
+                lookupGroups = null;
+                lookupLocators = null;
+                lookupAttrs = null;
+                maxUnexportDelay = 0;
+                unexportRetryDelay = 0;
+                lookupDiscMgr = null;
+                regByExpiration = null;
+                regByID = null;
+                activeReg = null;
+                /** <code>EventLogIterator</code> generator */
+                eventLogFactory = null;
+                pendingReg = null;
+                snapshotter = null;
+                notifier = null;
+                expirer = null;
+                this.config = null;
+                this.loginContext = loginContext;
+            }
+            // Assign fields.
+        }
+        
     }
 
-    /** Initialization common to both activatable and transient instances. */
-    private void init(String[] configArgs) 
-	throws Exception
-    {
-       if (operationsLogger.isLoggable(Level.FINER)) {
-	    operationsLogger.entering(mailboxSourceClass, 
-	        "init", (Object[])configArgs);
-       }
-       final Configuration config =
-            ConfigurationProvider.getInstance(
-	        configArgs, getClass().getClassLoader());
-        loginContext = (LoginContext) config.getEntry(
-            MERCURY, "loginContext", LoginContext.class, null);
-        if (loginContext != null) {
-            doInitWithLogin(config, loginContext);
-        } else {
-            doInit(config);
-	}
-	if (operationsLogger.isLoggable(Level.FINER)) {
-	    operationsLogger.exiting(mailboxSourceClass, 
-	        "init");
-	}
-    }
+//    /** Initialization common to both activatable and transient instances. */
+//    private void init(String[] configArgs) 
+//	throws Exception
+//    {
+//       if (operationsLogger.isLoggable(Level.FINER)) {
+//	    operationsLogger.entering(mailboxSourceClass, 
+//	        "init", (Object[])configArgs);
+//       }
+//       final Configuration config =
+//            ConfigurationProvider.getInstance(
+//	        configArgs, getClass().getClassLoader());
+//        loginContext = (LoginContext) config.getEntry(
+//            MERCURY, "loginContext", LoginContext.class, null);
+//        if (loginContext != null) {
+//            doInitWithLogin(config, loginContext);
+//        } else {
+//            doInit(config);
+//	}
+//	if (operationsLogger.isLoggable(Level.FINER)) {
+//	    operationsLogger.exiting(mailboxSourceClass, 
+//	        "init");
+//	}
+//    }
     
     /** 
      * Method that attempts to login before delegating the
      * rest of the initialization process to <code>doInit</code>
      */
-    private void doInitWithLogin(final Configuration config, 
-        LoginContext loginContext) throws Exception 
-    {
-        if (operationsLogger.isLoggable(Level.FINER)) {
-	    operationsLogger.entering(mailboxSourceClass, 
-	        "doInitWithLogin", new Object[] { config, loginContext});
-	}
-        loginContext.login();
-	try {
-            Subject.doAsPrivileged(
-                loginContext.getSubject(),
-                new PrivilegedExceptionAction() {
-                    public Object run() throws Exception {
-                        doInit(config);
-                        return null;
-                    }
-                },
-                null);
-	} catch (PrivilegedActionException e) {
-	    try {
-	        loginContext.logout();
-	    } catch (LoginException le) {
-//TODO - Move to end of cleanup()
-		if (initLogger.isLoggable(Levels.HANDLED)) {
-	            initLogger.log(Levels.HANDLED, "Trouble logging out", le);
-		}
-	    }
-	    throw e.getException();
-        }
-        if (operationsLogger.isLoggable(Level.FINER)) {
-	    operationsLogger.exiting(mailboxSourceClass, 
-	        "doInitWithLogin");
-	}
-    }
-    
-    /** Initialization common to both activatable and transient instances. */
-    private void doInit(Configuration config) throws Exception { 
+//    private void doInitWithLogin(final Configuration config, 
+//        LoginContext loginContext) throws Exception 
+//    {
+//        if (operationsLogger.isLoggable(Level.FINER)) {
+//	    operationsLogger.entering(mailboxSourceClass, 
+//	        "doInitWithLogin", new Object[] { config, loginContext});
+//	}
+//        loginContext.login();
+//	try {
+//            Subject.doAsPrivileged(
+//                loginContext.getSubject(),
+//                new PrivilegedExceptionAction() {
+//                    public Object run() throws Exception {
+//                        doInit(config);
+//                        return null;
+//                    }
+//                },
+//                null);
+//	} catch (PrivilegedActionException e) {
+//	    try {
+//	        loginContext.logout();
+//	    } catch (LoginException le) {
+////TODO - Move to end of cleanup()
+//		if (initLogger.isLoggable(Levels.HANDLED)) {
+//	            initLogger.log(Levels.HANDLED, "Trouble logging out", le);
+//		}
+//	    }
+//	    throw e.getException();
+//        }
+//        if (operationsLogger.isLoggable(Level.FINER)) {
+//	    operationsLogger.exiting(mailboxSourceClass, 
+//	        "doInitWithLogin");
+//	}
+//    }
+    
+//    /** Initialization common to both activatable and transient instances. */
+//    private void doInit(Configuration config) throws Exception { 
+//
+//        if (operationsLogger.isLoggable(Level.FINER)) {
+//	    operationsLogger.entering(mailboxSourceClass, 
+//	        "doInit", config);
+//	}
+////TODO - defer "big" default object to catch block around getNonNullEntry()
+//    
+//        // Get activation specific configuration items, if activated
+//	if (activationID != null) {
+//            ProxyPreparer activationSystemPreparer =
+//                (ProxyPreparer) Config.getNonNullEntry(config,
+//	            MERCURY, "activationSystemPreparer", 
+//		    ProxyPreparer.class, new BasicProxyPreparer());
+//            if (initLogger.isLoggable(Level.CONFIG)) {
+//                initLogger.log(Level.CONFIG, "activationSystemPreparer: {0}", 
+//	        activationSystemPreparer);
+//	    }		
+//            activationSystem =
+//                (ActivationSystem) activationSystemPreparer.prepareProxy(
+//                    ActivationGroup.getSystem());
+//            if (initLogger.isLoggable(Level.FINEST)) {
+//                initLogger.log(Level.FINEST, "Prepared activation system is: {0}", 
+//	        activationSystem);
+//	    }		
+//            ProxyPreparer activationIdPreparer = 
+//	        (ProxyPreparer)  Config.getNonNullEntry(config,
+//	            MERCURY, "activationIdPreparer", 
+//		    ProxyPreparer.class, new BasicProxyPreparer());
+//            if (initLogger.isLoggable(Level.CONFIG)) {
+//                initLogger.log(Level.CONFIG, "activationIdPreparer: {0}", 
+//	        activationIdPreparer);
+//	    }		
+//            activationID = (ActivationID) activationIdPreparer.prepareProxy(
+//                activationID);
+//            if (initLogger.isLoggable(Level.FINEST)) {
+//                initLogger.log(Level.FINEST, "Prepared activationID is: {0}", 
+//	        activationID);
+//	    }		
+//            activationPrepared = true;
+//	
+//            exporter = (Exporter)Config.getNonNullEntry(config,
+//	        MERCURY, "serverExporter", Exporter.class,
+//		new ActivationExporter(
+//		    activationID, 
+//		    new BasicJeriExporter(
+//		        TcpServerEndpoint.getInstance(0), 
+//			new BasicILFactory(), false, true)),
+//		activationID);
+//            if (initLogger.isLoggable(Level.CONFIG)) {
+//                initLogger.log(Level.CONFIG, "Activatable service exporter is: {0}", 
+//	        exporter);
+//	    }		
+//	} else { //Get non-activatable configuration items
+//            exporter = (Exporter) Config.getNonNullEntry(config,
+//                MERCURY, "serverExporter", Exporter.class, 
+//		new BasicJeriExporter(
+//		    TcpServerEndpoint.getInstance(0), 
+//		    new BasicILFactory(), false, true));
+//            if (initLogger.isLoggable(Level.CONFIG)) {
+//                initLogger.log(Level.CONFIG, 
+//		"Non-activatable service exporter is: {0}", exporter);		
+//	    }
+//	}
+//
+//        listenerPreparer = (ProxyPreparer) Config.getNonNullEntry(
+//	    config, MERCURY, "listenerPreparer", ProxyPreparer.class,
+//            new BasicProxyPreparer());
+//        if (initLogger.isLoggable(Level.CONFIG)) {
+//            initLogger.log(Level.CONFIG, "Listener preparer is: {0}", 
+//	    listenerPreparer);	
+//	}
+//	
+//        /* Get the proxy preparers for the lookup locators to join */
+//        locatorToJoinPreparer = (ProxyPreparer)Config.getNonNullEntry
+//             (config, MERCURY, "locatorToJoinPreparer",
+//              ProxyPreparer.class, new BasicProxyPreparer());
+//        if (initLogger.isLoggable(Level.CONFIG)) {
+//            initLogger.log(Level.CONFIG, "Locator preparer is: {0}", 
+//	    locatorToJoinPreparer);
+//	}	
+//	
+//        // Create lease policy -- used by recovery logic, below
+//        leasePolicy = (LeasePeriodPolicy) Config.getNonNullEntry(config,
+//	    MERCURY, "leasePeriodPolicy", LeasePeriodPolicy.class,
+//            new FixedLeasePeriodPolicy(3 * HOURS, 1 * HOURS));
+//        if (initLogger.isLoggable(Level.CONFIG)) {
+//            initLogger.log(Level.CONFIG, "LeasePeriodPolicy is: {0}", 
+//	    leasePolicy);
+//	}	
+//	    
+//	// Note: referenced by recovery logic in rebuildTransientState()	
+//        ProxyPreparer recoveredListenerPreparer = null;
+//        if (persistent) {
+//	    persistenceDirectory = 
+//	        (String)Config.getNonNullEntry(
+//                    config, MERCURY, "persistenceDirectory", String.class);
+//            if (initLogger.isLoggable(Level.CONFIG)) {
+//                initLogger.log(Level.CONFIG, "Persistence directory is: {0}", 
+//	        persistenceDirectory);
+//	    }	
+//	    // Note: referenced by recovery logic in rebuildTransientState()	
+//            recoveredListenerPreparer = 
+//	        (ProxyPreparer) Config.getNonNullEntry(
+//	        config, MERCURY, "recoveredListenerPreparer", ProxyPreparer.class,
+//                new BasicProxyPreparer());
+//            if (initLogger.isLoggable(Level.CONFIG)) {
+//                initLogger.log(Level.CONFIG, "Recovered listener preparer is: {0}", 
+//	        recoveredListenerPreparer);	
+//	    }
+//	    // Note: referenced by recovery logic, below	
+//            recoveredLocatorToJoinPreparer = (ProxyPreparer)Config.getNonNullEntry
+//                 (config, MERCURY, "recoveredLocatorToJoinPreparer",
+//                  ProxyPreparer.class, new BasicProxyPreparer());
+//            if (initLogger.isLoggable(Level.CONFIG)) {
+//                initLogger.log(Level.CONFIG, "Recovered locator preparer is: {0}", 
+//	        recoveredLocatorToJoinPreparer);
+//	    }	
+//
+//	    logToSnapshotThreshold = Config.getIntEntry(config,
+//                MERCURY, "logToSnapshotThreshold", 50, 0, Integer.MAX_VALUE);
+//	    
+////            log = new ReliableLog(persistenceDirectory, new LocalLogHandler());
+//
+//	    if (initLogger.isLoggable(Level.FINEST)) {
+//                initLogger.log(Level.FINEST, "Recovering persistent state");
+//	    }
+//            inRecovery = true;
+//            log.recover();
+//            inRecovery = false;
+//	}
+//
+//	if (serviceID == null) { // First time up, get initial values
+//	    if (initLogger.isLoggable(Level.FINEST)) {
+//                initLogger.log(Level.FINEST, "Getting initial values.");
+//	    }
+//	    serviceID = UuidFactory.generate();
+//	    if (initLogger.isLoggable(Level.FINEST)) {
+//                initLogger.log(Level.FINEST, "ServiceID: {0}", serviceID);
+//	    }
+//	    // Can be null for ALL_GROUPS
+//            lookupGroups = (String[])config.getEntry(MERCURY, 
+//	        "initialLookupGroups", String[].class, 
+//		new String[] { "" }); //default to public group
+//	    if (initLogger.isLoggable(Level.CONFIG)) {
+//                initLogger.log(Level.CONFIG, "Initial groups:");
+//	        dumpGroups(lookupGroups, initLogger, Level.CONFIG);
+//	    }
+//	    /*
+//	     * Note: Configuration provided locators are assumed to be 
+//	     * prepared already.
+//	     */
+//            lookupLocators = (LookupLocator[]) Config.getNonNullEntry(config,
+//	        MERCURY, "initialLookupLocators", LookupLocator[].class, 
+//		new LookupLocator[0]);
+//	    if (initLogger.isLoggable(Level.CONFIG)) {
+//                initLogger.log(Level.CONFIG, "Initial locators:");
+//	        dumpLocators(lookupLocators, initLogger, Level.CONFIG);
+//	    }
+//
+//            final Entry[] initialAttrs = 
+//	        (Entry[])Config.getNonNullEntry(config,
+//	            MERCURY, "initialLookupAttributes" ,
+//		    Entry[].class, new Entry[0]);
+//	    if (initLogger.isLoggable(Level.CONFIG)) {
+//                initLogger.log(Level.CONFIG, "Initial lookup attributes:");
+//	        dumpAttrs(initialAttrs, initLogger, Level.CONFIG);
+//	    }
+//            if (initialAttrs.length == 0) {
+//                lookupAttrs = baseLookupAttrs;
+//            } else {
+//                lookupAttrs = 
+//		    new Entry[initialAttrs.length + baseLookupAttrs.length];
+//                int i=0;
+//                for (int j=0; j<baseLookupAttrs.length; j++, i++)
+//                    lookupAttrs[i] = baseLookupAttrs[j];
+//                for (int j=0; j<initialAttrs.length; j++, i++)
+//                    lookupAttrs[i] = initialAttrs[j];
+//            }
+//	    if (initLogger.isLoggable(Level.FINEST)) {
+//                initLogger.log(Level.FINEST, 
+//		    "Combined lookup attributes:"); 
+//	        dumpAttrs(lookupAttrs, initLogger, Level.FINEST);
+//	    }
+//        } else { // recovered logic
+//	    if (initLogger.isLoggable(Level.FINEST)) {
+//                initLogger.log(Level.FINEST, "Preparing recovered locators:"); 
+//	        dumpLocators(lookupLocators, initLogger, Level.FINEST);
+//	    }
+//            prepareExistingLocators(
+//	        recoveredLocatorToJoinPreparer, lookupLocators);
+////TODO - Add recovered state debug: groups, locators, etc.
+//	}
+//	
+//        if (persistent) {
+//	    // Take snapshot of current state.
+//	    if (initLogger.isLoggable(Level.FINEST)) {
+//                initLogger.log(Level.FINEST, "Taking snapshot.");
+//	    }
+//            log.snapshot();
+//
+//            // Reconstruct any transient state, if necessary.
+//            rebuildTransientState(recoveredListenerPreparer);
+//	    
+//            /*  ----  ----- */
+//	    // Start snapshot thread belongs in start method
+////	    snapshotter = new SnapshotThread();
+//            snapshotter.start();
+//	}
+//        
+//	maxUnexportDelay = Config.getLongEntry(config, MERCURY, 
+//	    "maxUnexportDelay", 2 * MINUTES, 0, Long.MAX_VALUE);
+//
+//	unexportRetryDelay = Config.getLongEntry(config, MERCURY, 
+//	    "unexportRetryDelay", SECONDS, 1, Long.MAX_VALUE);
+//        
+//        /*  ---  The following will go into start method --- */
+//
+//        // Start threads
+////	notifier = new Notifier(config);
+//        notifier.start();
+////	expirer = new ExpirationThread();
+//        expirer.start();
+//
+//	// Export server instance and get its reference
+//	serverStub = (MailboxBackEnd)exporter.export(this);
+//        if (initLogger.isLoggable(Level.FINEST)) {
+//            initLogger.log(Level.FINEST, "Service stub is: {0}", 
+//	    serverStub);	
+//	}	
+//
+//        // Create the proxy that will be registered in the lookup service
+//        mailboxProxy = 
+//	    MailboxProxy.create(serverStub, serviceID);
+//        if (initLogger.isLoggable(Level.FINEST)) {
+//            initLogger.log(Level.FINEST, "Service proxy is: {0}", 
+//	    mailboxProxy);
+//	}		
+//
+//        // Create the admin proxy for this service
+//        mailboxAdminProxy = 
+//	    MailboxAdminProxy.create(serverStub, serviceID);
+//        if (initLogger.isLoggable(Level.FINEST)) {
+//            initLogger.log(Level.FINEST, "Service admin proxy is: {0}", 
+//	    mailboxAdminProxy);		
+//	}
+//
+//	// Create leaseFactory
+//	leaseFactory = new LeaseFactory(serverStub, serviceID);
+//
+//        // Get shorthand reference to the discovery manager
+//	try {
+//            lookupDiscMgr  = 
+//                (DiscoveryManagement)Config.getNonNullEntry(config,
+//	            MERCURY, "discoveryManager",
+//                    DiscoveryManagement.class);
+//            if(lookupDiscMgr instanceof DiscoveryGroupManagement) {
+//                 // Verify proper initial state ---> NO_GROUPS
+//                String[] groups =
+//                    ((DiscoveryGroupManagement)lookupDiscMgr).getGroups();
+//                if( (groups == DiscoveryGroupManagement.ALL_GROUPS) ||
+//                    (groups.length != 0) )
+//                {
+//                    throw new ConfigurationException(
+//                        "discoveryManager entry must be configured " +
+//		        " with no groups.");
+//                }//endif
+//	    } else {
+//               throw new ConfigurationException(
+//                    "discoveryManager entry must implement " +
+//                    "DiscoveryGroupManagement");
+//            }
+//	    
+//            if(lookupDiscMgr instanceof DiscoveryLocatorManagement) {
+//                LookupLocator[] locs =
+//                        ((DiscoveryLocatorManagement)lookupDiscMgr).getLocators();
+//                if( (locs != null) && (locs.length != 0) ) {
+//                    throw new ConfigurationException(
+//                        "discoveryManager entry must be configured " +
+//		        "with no locators");
+//                }//endif
+//	    } else {
+//                throw new ConfigurationException(
+//                    "discoveryManager entry must implement " +
+//                    "DiscoveryLocatorManagement");
+//            }  
+//	    
+//	    ((DiscoveryGroupManagement)lookupDiscMgr).setGroups(lookupGroups);
+//	    ((DiscoveryLocatorManagement)lookupDiscMgr).setLocators(lookupLocators);
+//	} catch (NoSuchEntryException e) {
+//	    lookupDiscMgr  =
+//		new LookupDiscoveryManager(lookupGroups, lookupLocators,
+//                    null, config);
+//	}
+//        if (initLogger.isLoggable(Level.FINEST)) {
+//            initLogger.log(Level.FINEST, "Discovery manager is: {0}", 
+//	    lookupDiscMgr);
+//	}		
+//
+//        ServiceID lookupID = new ServiceID(
+//	    serviceID.getMostSignificantBits(),
+//	    serviceID.getLeastSignificantBits());
+//
+//	if (initLogger.isLoggable(Level.FINEST)) {
+//            initLogger.log(Level.FINEST, "Creating JoinManager.");
+//	}
+//	joiner = new JoinManager(
+//	    mailboxProxy,                // service object
+//	    lookupAttrs,               // service attributes
+//	    lookupID,                 // Service ID
+//	    lookupDiscMgr,             // DiscoveryManagement ref - default
+//	    null,                      // LeaseRenewalManager reference
+//	    config); 
+//	                      
+//        if (operationsLogger.isLoggable(Level.FINER)) {
+//	    operationsLogger.exiting(mailboxSourceClass, 
+//	        "doInit");
+//	}
+//        readyState.ready();
+//
+//	if (startupLogger.isLoggable(Level.INFO)) {
+//            startupLogger.log
+//                   (Level.INFO, "Mercury started: {0}", this);
+//        }
+//
+//    } // End doInit()
+//    
+    public void start() throws Exception {
+        if (started) return;
+        concurrentObj.writeLock();
+        started = true; // mutual exclusion
+        try {
+            if (thrown != null) throw thrown;
+            if (persistent){
+                // Start snapshot thread belongs in start method
+    //	    snapshotter = new SnapshotThread();
+                snapshotter.start();
+            }
 
-        if (operationsLogger.isLoggable(Level.FINER)) {
-	    operationsLogger.entering(mailboxSourceClass, 
-	        "doInit", config);
-	}
-//TODO - defer "big" default object to catch block around getNonNullEntry()
-    
-        // Get activation specific configuration items, if activated
-	if (activationID != null) {
-            ProxyPreparer activationSystemPreparer =
-                (ProxyPreparer) Config.getNonNullEntry(config,
-	            MERCURY, "activationSystemPreparer", 
-		    ProxyPreparer.class, new BasicProxyPreparer());
-            if (initLogger.isLoggable(Level.CONFIG)) {
-                initLogger.log(Level.CONFIG, "activationSystemPreparer: {0}", 
-	        activationSystemPreparer);
-	    }		
-            activationSystem =
-                (ActivationSystem) activationSystemPreparer.prepareProxy(
-                    ActivationGroup.getSystem());
+            /*  ---  The following will go into start method --- */
+
+            // Start threads
+    //	notifier = new Notifier(config);
+            notifier.start();
+    //	expirer = new ExpirationThread();
+            expirer.start();
+
+            // Export server instance and get its reference
+            serverStub = (MailboxBackEnd)exporter.export(this);
             if (initLogger.isLoggable(Level.FINEST)) {
-                initLogger.log(Level.FINEST, "Prepared activation system is: {0}", 
-	        activationSystem);
-	    }		
-            ProxyPreparer activationIdPreparer = 
-	        (ProxyPreparer)  Config.getNonNullEntry(config,
-	            MERCURY, "activationIdPreparer", 
-		    ProxyPreparer.class, new BasicProxyPreparer());
-            if (initLogger.isLoggable(Level.CONFIG)) {
-                initLogger.log(Level.CONFIG, "activationIdPreparer: {0}", 
-	        activationIdPreparer);
-	    }		
-            activationID = (ActivationID) activationIdPreparer.prepareProxy(
-                activationID);
+                initLogger.log(Level.FINEST, "Service stub is: {0}", 
+                serverStub);	
+            }	
+
+            // Create the proxy that will be registered in the lookup service
+            mailboxProxy = 
+                MailboxProxy.create(serverStub, serviceID);
             if (initLogger.isLoggable(Level.FINEST)) {
-                initLogger.log(Level.FINEST, "Prepared activationID is: {0}", 
-	        activationID);
-	    }		
-            activationPrepared = true;
-	
-            exporter = (Exporter)Config.getNonNullEntry(config,
-	        MERCURY, "serverExporter", Exporter.class,
-		new ActivationExporter(
-		    activationID, 
-		    new BasicJeriExporter(
-		        TcpServerEndpoint.getInstance(0), 
-			new BasicILFactory(), false, true)),
-		activationID);
-            if (initLogger.isLoggable(Level.CONFIG)) {
-                initLogger.log(Level.CONFIG, "Activatable service exporter is: {0}", 
-	        exporter);
-	    }		
-	} else { //Get non-activatable configuration items
-            exporter = (Exporter) Config.getNonNullEntry(config,
-                MERCURY, "serverExporter", Exporter.class, 
-		new BasicJeriExporter(
-		    TcpServerEndpoint.getInstance(0), 
-		    new BasicILFactory(), false, true));
-            if (initLogger.isLoggable(Level.CONFIG)) {
-                initLogger.log(Level.CONFIG, 
-		"Non-activatable service exporter is: {0}", exporter);		
-	    }
-	}
-
-        listenerPreparer = (ProxyPreparer) Config.getNonNullEntry(
-	    config, MERCURY, "listenerPreparer", ProxyPreparer.class,
-            new BasicProxyPreparer());
-        if (initLogger.isLoggable(Level.CONFIG)) {
-            initLogger.log(Level.CONFIG, "Listener preparer is: {0}", 
-	    listenerPreparer);	
-	}
-	
-        /* Get the proxy preparers for the lookup locators to join */
-        locatorToJoinPreparer = (ProxyPreparer)Config.getNonNullEntry
-             (config, MERCURY, "locatorToJoinPreparer",
-              ProxyPreparer.class, new BasicProxyPreparer());
-        if (initLogger.isLoggable(Level.CONFIG)) {
-            initLogger.log(Level.CONFIG, "Locator preparer is: {0}", 
-	    locatorToJoinPreparer);
-	}	
-	
-        // Create lease policy -- used by recovery logic, below
-        leasePolicy = (LeasePeriodPolicy) Config.getNonNullEntry(config,
-	    MERCURY, "leasePeriodPolicy", LeasePeriodPolicy.class,
-            new FixedLeasePeriodPolicy(3 * HOURS, 1 * HOURS));
-        if (initLogger.isLoggable(Level.CONFIG)) {
-            initLogger.log(Level.CONFIG, "LeasePeriodPolicy is: {0}", 
-	    leasePolicy);
-	}	
-	    
-	// Note: referenced by recovery logic in rebuildTransientState()	
-        ProxyPreparer recoveredListenerPreparer = null;
-        if (persistent) {
-	    persistenceDirectory = 
-	        (String)Config.getNonNullEntry(
-                    config, MERCURY, "persistenceDirectory", String.class);
-            if (initLogger.isLoggable(Level.CONFIG)) {
-                initLogger.log(Level.CONFIG, "Persistence directory is: {0}", 
-	        persistenceDirectory);
-	    }	
-	    // Note: referenced by recovery logic in rebuildTransientState()	
-            recoveredListenerPreparer = 
-	        (ProxyPreparer) Config.getNonNullEntry(
-	        config, MERCURY, "recoveredListenerPreparer", ProxyPreparer.class,
-                new BasicProxyPreparer());
-            if (initLogger.isLoggable(Level.CONFIG)) {
-                initLogger.log(Level.CONFIG, "Recovered listener preparer is: {0}", 
-	        recoveredListenerPreparer);	
-	    }
-	    // Note: referenced by recovery logic, below	
-            recoveredLocatorToJoinPreparer = (ProxyPreparer)Config.getNonNullEntry
-                 (config, MERCURY, "recoveredLocatorToJoinPreparer",
-                  ProxyPreparer.class, new BasicProxyPreparer());
-            if (initLogger.isLoggable(Level.CONFIG)) {
-                initLogger.log(Level.CONFIG, "Recovered locator preparer is: {0}", 
-	        recoveredLocatorToJoinPreparer);
-	    }	
-
-	    logToSnapshotThreshold = Config.getIntEntry(config,
-                MERCURY, "logToSnapshotThreshold", 50, 0, Integer.MAX_VALUE);
-	    
-            log = new ReliableLog(persistenceDirectory, new LocalLogHandler());
-
-	    if (initLogger.isLoggable(Level.FINEST)) {
-                initLogger.log(Level.FINEST, "Recovering persistent state");
-	    }
-            inRecovery = true;
-            log.recover();
-            inRecovery = false;
-	}
-
-	if (serviceID == null) { // First time up, get initial values
-	    if (initLogger.isLoggable(Level.FINEST)) {
-                initLogger.log(Level.FINEST, "Getting initial values.");
-	    }
-	    serviceID = UuidFactory.generate();
-	    if (initLogger.isLoggable(Level.FINEST)) {
-                initLogger.log(Level.FINEST, "ServiceID: {0}", serviceID);
-	    }
-	    // Can be null for ALL_GROUPS
-            lookupGroups = (String[])config.getEntry(MERCURY, 
-	        "initialLookupGroups", String[].class, 
-		new String[] { "" }); //default to public group
-	    if (initLogger.isLoggable(Level.CONFIG)) {
-                initLogger.log(Level.CONFIG, "Initial groups:");
-	        dumpGroups(lookupGroups, initLogger, Level.CONFIG);
-	    }
-	    /*
-	     * Note: Configuration provided locators are assumed to be 
-	     * prepared already.
-	     */
-            lookupLocators = (LookupLocator[]) Config.getNonNullEntry(config,
-	        MERCURY, "initialLookupLocators", LookupLocator[].class, 
-		new LookupLocator[0]);
-	    if (initLogger.isLoggable(Level.CONFIG)) {
-                initLogger.log(Level.CONFIG, "Initial locators:");
-	        dumpLocators(lookupLocators, initLogger, Level.CONFIG);
-	    }
-
-            final Entry[] initialAttrs = 
-	        (Entry[])Config.getNonNullEntry(config,
-	            MERCURY, "initialLookupAttributes" ,
-		    Entry[].class, new Entry[0]);
-	    if (initLogger.isLoggable(Level.CONFIG)) {
-                initLogger.log(Level.CONFIG, "Initial lookup attributes:");
-	        dumpAttrs(initialAttrs, initLogger, Level.CONFIG);
-	    }
-            if (initialAttrs.length == 0) {
-                lookupAttrs = baseLookupAttrs;
-            } else {
-                lookupAttrs = 
-		    new Entry[initialAttrs.length + baseLookupAttrs.length];
-                int i=0;
-                for (int j=0; j<baseLookupAttrs.length; j++, i++)
-                    lookupAttrs[i] = baseLookupAttrs[j];
-                for (int j=0; j<initialAttrs.length; j++, i++)
-                    lookupAttrs[i] = initialAttrs[j];
+                initLogger.log(Level.FINEST, "Service proxy is: {0}", 
+                mailboxProxy);
+            }		
+
+            // Create the admin proxy for this service
+            mailboxAdminProxy = 
+                MailboxAdminProxy.create(serverStub, serviceID);
+            if (initLogger.isLoggable(Level.FINEST)) {
+                initLogger.log(Level.FINEST, "Service admin proxy is: {0}", 
+                mailboxAdminProxy);		
             }
-	    if (initLogger.isLoggable(Level.FINEST)) {
-                initLogger.log(Level.FINEST, 
-		    "Combined lookup attributes:"); 
-	        dumpAttrs(lookupAttrs, initLogger, Level.FINEST);
-	    }
-        } else { // recovered logic
-	    if (initLogger.isLoggable(Level.FINEST)) {
-                initLogger.log(Level.FINEST, "Preparing recovered locators:"); 
-	        dumpLocators(lookupLocators, initLogger, Level.FINEST);
-	    }
-            prepareExistingLocators(
-	        recoveredLocatorToJoinPreparer, lookupLocators);
-//TODO - Add recovered state debug: groups, locators, etc.
-	}
-	
-        if (persistent) {
-	    // Take snapshot of current state.
-	    if (initLogger.isLoggable(Level.FINEST)) {
-                initLogger.log(Level.FINEST, "Taking snapshot.");
-	    }
-            log.snapshot();
-
-            // Reconstruct any transient state, if necessary.
-            rebuildTransientState(recoveredListenerPreparer);
-	    
-	    // Start snapshot thread
-	    snapshotter = new SnapshotThread();
-	}
-        
-	maxUnexportDelay = Config.getLongEntry(config, MERCURY, 
-	    "maxUnexportDelay", 2 * MINUTES, 0, Long.MAX_VALUE);
 
-	unexportRetryDelay = Config.getLongEntry(config, MERCURY, 
-	    "unexportRetryDelay", SECONDS, 1, Long.MAX_VALUE);
+            // Create leaseFactory
+            leaseFactory = new LeaseFactory(serverStub, serviceID);
 
-        // Start threads
-	notifier = new Notifier(config);
-	expirer = new ExpirationThread();
-
-	// Export server instance and get its reference
-	serverStub = (MailboxBackEnd)exporter.export(this);
-        if (initLogger.isLoggable(Level.FINEST)) {
-            initLogger.log(Level.FINEST, "Service stub is: {0}", 
-	    serverStub);	
-	}	
-
-        // Create the proxy that will be registered in the lookup service
-        mailboxProxy = 
-	    MailboxProxy.create(serverStub, serviceID);
-        if (initLogger.isLoggable(Level.FINEST)) {
-            initLogger.log(Level.FINEST, "Service proxy is: {0}", 
-	    mailboxProxy);
-	}		
-
-        // Create the admin proxy for this service
-        mailboxAdminProxy = 
-	    MailboxAdminProxy.create(serverStub, serviceID);
-        if (initLogger.isLoggable(Level.FINEST)) {
-            initLogger.log(Level.FINEST, "Service admin proxy is: {0}", 
-	    mailboxAdminProxy);		
-	}
-
-	// Create leaseFactory
-	leaseFactory = new LeaseFactory(serverStub, serviceID);
+            // Get shorthand reference to the discovery manager
+            try {
+                lookupDiscMgr  = 
+                    (DiscoveryManagement)Config.getNonNullEntry(config,
+                        MERCURY, "discoveryManager",
+                        DiscoveryManagement.class);
+                if(lookupDiscMgr instanceof DiscoveryGroupManagement) {
+                     // Verify proper initial state ---> NO_GROUPS
+                    String[] groups =
+                        ((DiscoveryGroupManagement)lookupDiscMgr).getGroups();
+                    if( (groups == DiscoveryGroupManagement.ALL_GROUPS) ||
+                        (groups.length != 0) )
+                    {
+                        throw new ConfigurationException(
+                            "discoveryManager entry must be configured " +
+                            " with no groups.");
+                    }//endif
+                } else {
+                   throw new ConfigurationException(
+                        "discoveryManager entry must implement " +
+                        "DiscoveryGroupManagement");
+                }
 
-        // Get shorthand reference to the discovery manager
-	try {
-            lookupDiscMgr  = 
-                (DiscoveryManagement)Config.getNonNullEntry(config,
-	            MERCURY, "discoveryManager",
-                    DiscoveryManagement.class);
-            if(lookupDiscMgr instanceof DiscoveryGroupManagement) {
-                 // Verify proper initial state ---> NO_GROUPS
-                String[] groups =
-                    ((DiscoveryGroupManagement)lookupDiscMgr).getGroups();
-                if( (groups == DiscoveryGroupManagement.ALL_GROUPS) ||
-                    (groups.length != 0) )
-                {
+                if(lookupDiscMgr instanceof DiscoveryLocatorManagement) {
+                    LookupLocator[] locs =
+                            ((DiscoveryLocatorManagement)lookupDiscMgr).getLocators();
+                    if( (locs != null) && (locs.length != 0) ) {
+                        throw new ConfigurationException(
+                            "discoveryManager entry must be configured " +
+                            "with no locators");
+                    }//endif
+                } else {
                     throw new ConfigurationException(
-                        "discoveryManager entry must be configured " +
-		        " with no groups.");
-                }//endif
-	    } else {
-               throw new ConfigurationException(
-                    "discoveryManager entry must implement " +
-                    "DiscoveryGroupManagement");
+                        "discoveryManager entry must implement " +
+                        "DiscoveryLocatorManagement");
+                }  
+
+                ((DiscoveryGroupManagement)lookupDiscMgr).setGroups(lookupGroups);
+                ((DiscoveryLocatorManagement)lookupDiscMgr).setLocators(lookupLocators);
+            } catch (NoSuchEntryException e) {
+                lookupDiscMgr  =
+                    new LookupDiscoveryManager(lookupGroups, lookupLocators,
+                        null, config);
             }
-	    
-            if(lookupDiscMgr instanceof DiscoveryLocatorManagement) {
-                LookupLocator[] locs =
-                        ((DiscoveryLocatorManagement)lookupDiscMgr).getLocators();
-                if( (locs != null) && (locs.length != 0) ) {
-                    throw new ConfigurationException(
-                        "discoveryManager entry must be configured " +
-		        "with no locators");
-                }//endif
-	    } else {
-                throw new ConfigurationException(
-                    "discoveryManager entry must implement " +
-                    "DiscoveryLocatorManagement");
-            }  
-	    
-	    ((DiscoveryGroupManagement)lookupDiscMgr).setGroups(lookupGroups);
-	    ((DiscoveryLocatorManagement)lookupDiscMgr).setLocators(lookupLocators);
-	} catch (NoSuchEntryException e) {
-	    lookupDiscMgr  =
-		new LookupDiscoveryManager(lookupGroups, lookupLocators,
-                    null, config);
-	}
-        if (initLogger.isLoggable(Level.FINEST)) {
-            initLogger.log(Level.FINEST, "Discovery manager is: {0}", 
-	    lookupDiscMgr);
-	}		
-
-        ServiceID lookupID = new ServiceID(
-	    serviceID.getMostSignificantBits(),
-	    serviceID.getLeastSignificantBits());
-
-	if (initLogger.isLoggable(Level.FINEST)) {
-            initLogger.log(Level.FINEST, "Creating JoinManager.");
-	}
-	joiner = new JoinManager(
-	    mailboxProxy,                // service object
-	    lookupAttrs,               // service attributes
-	    lookupID,                 // Service ID
-	    lookupDiscMgr,             // DiscoveryManagement ref - default
-	    null,                      // LeaseRenewalManager reference
-	    config); 
-	                      
-        if (operationsLogger.isLoggable(Level.FINER)) {
-	    operationsLogger.exiting(mailboxSourceClass, 
-	        "doInit");
-	}
-        readyState.ready();
+            if (initLogger.isLoggable(Level.FINEST)) {
+                initLogger.log(Level.FINEST, "Discovery manager is: {0}", 
+                lookupDiscMgr);
+            }		
+
+            ServiceID lookupID = new ServiceID(
+                serviceID.getMostSignificantBits(),
+                serviceID.getLeastSignificantBits());
 
-	if (startupLogger.isLoggable(Level.INFO)) {
-            startupLogger.log
-                   (Level.INFO, "Mercury started: {0}", this);
-        }
+            if (initLogger.isLoggable(Level.FINEST)) {
+                initLogger.log(Level.FINEST, "Creating JoinManager.");
+            }
+            joiner = new JoinManager(
+                mailboxProxy,                // service object
+                lookupAttrs,               // service attributes
+                lookupID,                 // Service ID
+                lookupDiscMgr,             // DiscoveryManagement ref - default
+                null,                      // LeaseRenewalManager reference
+                config); 
+
+            if (operationsLogger.isLoggable(Level.FINER)) {
+                operationsLogger.exiting(mailboxSourceClass, 
+                    "doInit");
+            }
+            readyState.ready();
 
-    } // End doInit()
+            if (startupLogger.isLoggable(Level.INFO)) {
+                startupLogger.log
+                       (Level.INFO, "Mercury started: {0}", this);
+            }
+        } catch (Throwable t){
+            cleanup();
+	    initFailed(t);
+        } finally {
+            config = null;
+            thrown = null;
+            concurrentObj.writeUnlock();
+        }
+    }
 
     // Rebuilds internal data structures after a restart.
     private void rebuildTransientState(ProxyPreparer recoveredListenerPreparer) {
@@ -1835,7 +2085,7 @@ class MailboxImpl implements MailboxBack
      * Utility method that returns the associated File object
      * for the given Uuid's persistence directory 
      */
-    private static File getEventLogPath(String parent, Uuid uuid) {
+    static File getEventLogPath(String parent, Uuid uuid) {
         return new File(parent, uuid.toString());
     }
 
@@ -2638,7 +2888,7 @@ class MailboxImpl implements MailboxBack
          * <code>TaskManager</code> that will be handling the 
 	 * notification tasks 
          */
-        private TaskManager	taskManager;	
+        private final TaskManager	taskManager;	
 
         /** wakeup manager for <code>NotifyTask</code> */
         private final WakeupManager wakeupMgr =
@@ -2648,7 +2898,7 @@ class MailboxImpl implements MailboxBack
          * Random number generator that will be used for implementing
          * a simple load balancing scheme. Seed it with the current time.
          */
-        private Random rand = new Random(System.currentTimeMillis());
+        private final Random rand = new Random(System.currentTimeMillis());
     
         /** Time to wait between notification checks */
         private final static long	PAUSE_TIME = 5000; // 5 seconds
@@ -2662,7 +2912,7 @@ class MailboxImpl implements MailboxBack
 	        MERCURY, "notificationsTaskManager",
 	        TaskManager.class, new TaskManager());
 //TODO - defer TaskManager() creation to catch block of getEntry()
-    	    start();
+    	    //start();
         }
     
         /**
@@ -3516,7 +3766,7 @@ class MailboxImpl implements MailboxBack
                 expirationLogger.log(Level.FINEST,
 		    "ExpirationThread started ...");
             }
-            start();
+            //start();
 	}
 
 	/** 
@@ -4498,7 +4748,9 @@ class MailboxImpl implements MailboxBack
         MarshalledObject[] marshalledAttrs
                                     = (MarshalledObject[])stream.readObject();
 	lookupAttrs = unmarshalAttributes(marshalledAttrs);
-	regByID = (HashMap)stream.readObject();
+	HashMap<Uuid, ServiceRegistration> regByID = (HashMap<Uuid, ServiceRegistration>)stream.readObject();
+        this.regByID.clear();
+        this.regByID.putAll(regByID);
 	if (recoveryLogger.isLoggable(Level.FINEST)) {
             recoveryLogger.log(Level.FINEST, 
                 "serviceID: {0}", serviceID);
@@ -4679,7 +4931,7 @@ class MailboxImpl implements MailboxBack
 	public SnapshotThread() {
 	    super("SnapshotThread");
 	    setDaemon(true);
-	    start();
+//	    start();
 	}
 
 	public void run() {
@@ -4739,7 +4991,7 @@ class MailboxImpl implements MailboxBack
 
 
     /** Utility method for displaying lookup group attributes */
-    private static void dumpGroups(String[] grps, Logger logger, Level level) {
+    static void dumpGroups(String[] grps, Logger logger, Level level) {
         if (logger.isLoggable(level)) {
             if (grps == null)
                 logger.log(level, "<ALL_GROUPS>");
@@ -4760,7 +5012,7 @@ class MailboxImpl implements MailboxBack
     }
 
     /** Utility method for displaying lookup locator attributes */
-    private static void dumpLocators(LookupLocator[] locs, Logger logger, Level level) {
+    static void dumpLocators(LookupLocator[] locs, Logger logger, Level level) {
         if (logger.isLoggable(level)) {
 	    if (locs == null)
 	        logger.log(level, "<null>");
@@ -4774,7 +5026,7 @@ class MailboxImpl implements MailboxBack
     }
 
     /** Utility method for displaying lookup service attributes */
-    private static void dumpAttrs(Entry[] attrs, Logger logger, Level level) {
+    static void dumpAttrs(Entry[] attrs, Logger logger, Level level) {
         if (logger.isLoggable(level)) {
 	    if (attrs == null)
 	        logger.log(level, "<null>");
@@ -4851,7 +5103,7 @@ class MailboxImpl implements MailboxBack
 	}
     } 
 
-    private static LookupLocator[] prepareExistingLocators(
+    static LookupLocator[] prepareExistingLocators(
         ProxyPreparer preparer, LookupLocator[] lookupLocators) 
     {
         if (operationsLogger.isLoggable(Level.FINER)) {
@@ -4906,7 +5158,7 @@ class MailboxImpl implements MailboxBack
     /**
      * Utility method that check for valid resource
      */
-    private static boolean ensureCurrent(LeasedResource resource) {
+    static boolean ensureCurrent(LeasedResource resource) {
         return resource.getExpiration() > System.currentTimeMillis();
     }
 }//end class MailboxImpl

Added: river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/mercury/MailboxImplInit.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/mercury/MailboxImplInit.java?rev=1467198&view=auto
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/mercury/MailboxImplInit.java (added)
+++ river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/mercury/MailboxImplInit.java Fri Apr 12 08:11:54 2013
@@ -0,0 +1,373 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.sun.jini.mercury;
+
+import com.sun.jini.config.Config;
+import com.sun.jini.constants.TimeConstants;
+import com.sun.jini.landlord.FixedLeasePeriodPolicy;
+import com.sun.jini.landlord.LeasePeriodPolicy;
+import com.sun.jini.logging.Levels;
+import com.sun.jini.reliableLog.LogHandler;
+import com.sun.jini.reliableLog.ReliableLog;
+import com.sun.jini.thread.InterruptedStatusThread;
+import java.io.IOException;
+import java.rmi.RemoteException;
+import java.rmi.activation.ActivationException;
+import java.rmi.activation.ActivationGroup;
+import java.rmi.activation.ActivationID;
+import java.rmi.activation.ActivationSystem;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.logging.Level;
+import net.jini.activation.ActivationExporter;
+import net.jini.config.Configuration;
+import net.jini.config.ConfigurationException;
+import net.jini.core.discovery.LookupLocator;
+import net.jini.core.entry.Entry;
+import net.jini.discovery.DiscoveryManagement;
+import net.jini.export.Exporter;
+import net.jini.id.Uuid;
+import net.jini.id.UuidFactory;
+import net.jini.jeri.BasicILFactory;
+import net.jini.jeri.BasicJeriExporter;
+import net.jini.jeri.tcp.TcpServerEndpoint;
+import net.jini.security.BasicProxyPreparer;
+import net.jini.security.ProxyPreparer;
+
+/**
+ *
+ * @author peter
+ */
+class MailboxImplInit {
+    ActivationID activationID;
+    ActivationSystem activationSystem;
+    boolean activationPrepared;
+    Exporter exporter;
+    ProxyPreparer listenerPreparer;
+    ProxyPreparer locatorToJoinPreparer;
+    LeasePeriodPolicy leasePolicy;
+    String persistenceDirectory;
+    ProxyPreparer recoveredLocatorToJoinPreparer;
+    int logToSnapshotThreshold;
+    ReliableLog log;
+    Uuid serviceID;
+    String[] lookupGroups;
+    LookupLocator[] lookupLocators;
+    Entry[] lookupAttrs;
+    long maxUnexportDelay;
+    long unexportRetryDelay;
+    DiscoveryManagement lookupDiscMgr;
+    TreeMap<ServiceRegistration, ServiceRegistration> regByExpiration = new TreeMap<ServiceRegistration, ServiceRegistration>();
+    HashMap<Uuid, ServiceRegistration> regByID = new HashMap<Uuid, ServiceRegistration>();
+    Map<Uuid, MailboxImpl.NotifyTask> activeReg = new HashMap<Uuid, MailboxImpl.NotifyTask>();
+    /** <code>EventLogIterator</code> generator */
+    EventLogFactory eventLogFactory = new EventLogFactory();
+    List<Uuid> pendingReg = new ArrayList<Uuid>();
+    Thread snapshotter;
+    Thread notifier;
+    Thread expirer;
+    Configuration config;
+
+    MailboxImplInit(Configuration config, 
+                    boolean persistent, 
+                    ActivationID activationID, 
+                    Entry[] baseLookupAttrs, 
+                    LogHandler localLogHandler,
+                    Thread snapshotter,
+                    Thread notifier,
+                    Thread expirer)
+            throws ConfigurationException, RemoteException, ActivationException, IOException
+    {
+        this.notifier = notifier;
+        this.expirer = expirer;
+        this.config = config;
+        // Get activation specific configuration items, if activated
+        if (activationID != null) {
+            ProxyPreparer activationSystemPreparer = (ProxyPreparer) Config.getNonNullEntry(config, MailboxImpl.MERCURY, "activationSystemPreparer", ProxyPreparer.class, new BasicProxyPreparer());
+            if (MailboxImpl.initLogger.isLoggable(Level.CONFIG)) {
+                MailboxImpl.initLogger.log(Level.CONFIG, "activationSystemPreparer: {0}", activationSystemPreparer);
+            }
+            activationSystem = (ActivationSystem) activationSystemPreparer.prepareProxy(ActivationGroup.getSystem());
+            if (MailboxImpl.initLogger.isLoggable(Level.FINEST)) {
+                MailboxImpl.initLogger.log(Level.FINEST, "Prepared activation system is: {0}", activationSystem);
+            }
+            ProxyPreparer activationIdPreparer = (ProxyPreparer) Config.getNonNullEntry(config, MailboxImpl.MERCURY, "activationIdPreparer", ProxyPreparer.class, new BasicProxyPreparer());
+            if (MailboxImpl.initLogger.isLoggable(Level.CONFIG)) {
+                MailboxImpl.initLogger.log(Level.CONFIG, "activationIdPreparer: {0}", activationIdPreparer);
+            }
+            activationID = (ActivationID) activationIdPreparer.prepareProxy(activationID);
+            if (MailboxImpl.initLogger.isLoggable(Level.FINEST)) {
+                MailboxImpl.initLogger.log(Level.FINEST, "Prepared activationID is: {0}", activationID);
+            }
+            activationPrepared = true;
+            exporter = (Exporter) Config.getNonNullEntry(config, MailboxImpl.MERCURY, "serverExporter", Exporter.class, new ActivationExporter(activationID, new BasicJeriExporter(TcpServerEndpoint.getInstance(0), new BasicILFactory(), false, true)), activationID);
+            if (MailboxImpl.initLogger.isLoggable(Level.CONFIG)) {
+                MailboxImpl.initLogger.log(Level.CONFIG, "Activatable service exporter is: {0}", exporter);
+            }
+            this.activationID = activationID;
+        } else {
+            //Get non-activatable configuration items
+            exporter = (Exporter) Config.getNonNullEntry(config, MailboxImpl.MERCURY, "serverExporter", Exporter.class, new BasicJeriExporter(TcpServerEndpoint.getInstance(0), new BasicILFactory(), false, true));
+            if (MailboxImpl.initLogger.isLoggable(Level.CONFIG)) {
+                MailboxImpl.initLogger.log(Level.CONFIG, "Non-activatable service exporter is: {0}", exporter);
+            }
+        }
+        listenerPreparer = (ProxyPreparer) Config.getNonNullEntry(config, MailboxImpl.MERCURY, "listenerPreparer", ProxyPreparer.class, new BasicProxyPreparer());
+        if (MailboxImpl.initLogger.isLoggable(Level.CONFIG)) {
+            MailboxImpl.initLogger.log(Level.CONFIG, "Listener preparer is: {0}", listenerPreparer);
+        }
+        /* Get the proxy preparers for the lookup locators to join */
+        locatorToJoinPreparer = (ProxyPreparer) Config.getNonNullEntry(config, MailboxImpl.MERCURY, "locatorToJoinPreparer", ProxyPreparer.class, new BasicProxyPreparer());
+        if (MailboxImpl.initLogger.isLoggable(Level.CONFIG)) {
+            MailboxImpl.initLogger.log(Level.CONFIG, "Locator preparer is: {0}", locatorToJoinPreparer);
+        }
+        // Create lease policy -- used by recovery logic, below
+        leasePolicy = (LeasePeriodPolicy) Config.getNonNullEntry(config, MailboxImpl.MERCURY, "leasePeriodPolicy", LeasePeriodPolicy.class, new FixedLeasePeriodPolicy(3 * TimeConstants.HOURS, 1 * TimeConstants.HOURS));
+        if (MailboxImpl.initLogger.isLoggable(Level.CONFIG)) {
+            MailboxImpl.initLogger.log(Level.CONFIG, "LeasePeriodPolicy is: {0}", leasePolicy);
+        }
+        // Note: referenced by recovery logic in rebuildTransientState()
+        ProxyPreparer recoveredListenerPreparer = null;
+        if (persistent) {
+            persistenceDirectory = (String) Config.getNonNullEntry(config, MailboxImpl.MERCURY, "persistenceDirectory", String.class);
+            if (MailboxImpl.initLogger.isLoggable(Level.CONFIG)) {
+                MailboxImpl.initLogger.log(Level.CONFIG, "Persistence directory is: {0}", persistenceDirectory);
+            }
+            // Note: referenced by recovery logic in rebuildTransientState()
+            recoveredListenerPreparer = (ProxyPreparer) Config.getNonNullEntry(config, MailboxImpl.MERCURY, "recoveredListenerPreparer", ProxyPreparer.class, new BasicProxyPreparer());
+            if (MailboxImpl.initLogger.isLoggable(Level.CONFIG)) {
+                MailboxImpl.initLogger.log(Level.CONFIG, "Recovered listener preparer is: {0}", recoveredListenerPreparer);
+            }
+            // Note: referenced by recovery logic, below
+            recoveredLocatorToJoinPreparer = (ProxyPreparer) Config.getNonNullEntry(config, MailboxImpl.MERCURY, "recoveredLocatorToJoinPreparer", ProxyPreparer.class, new BasicProxyPreparer());
+            if (MailboxImpl.initLogger.isLoggable(Level.CONFIG)) {
+                MailboxImpl.initLogger.log(Level.CONFIG, "Recovered locator preparer is: {0}", recoveredLocatorToJoinPreparer);
+            }
+            logToSnapshotThreshold = Config.getIntEntry(config, MailboxImpl.MERCURY, "logToSnapshotThreshold", 50, 0, Integer.MAX_VALUE);
+            log = new ReliableLog(persistenceDirectory, localLogHandler);
+            if (MailboxImpl.initLogger.isLoggable(Level.FINEST)) {
+                MailboxImpl.initLogger.log(Level.FINEST, "Recovering persistent state");
+            }
+            log.recover();
+        }
+        if (serviceID == null) {
+            // First time up, get initial values
+            if (MailboxImpl.initLogger.isLoggable(Level.FINEST)) {
+                MailboxImpl.initLogger.log(Level.FINEST, "Getting initial values.");
+            }
+            serviceID = UuidFactory.generate();
+            if (MailboxImpl.initLogger.isLoggable(Level.FINEST)) {
+                MailboxImpl.initLogger.log(Level.FINEST, "ServiceID: {0}", serviceID);
+            }
+            // Can be null for ALL_GROUPS
+            lookupGroups = (String[]) config.getEntry(MailboxImpl.MERCURY, "initialLookupGroups", String[].class, new String[]{""}); //default to public group
+            //default to public group
+            if (MailboxImpl.initLogger.isLoggable(Level.CONFIG)) {
+                MailboxImpl.initLogger.log(Level.CONFIG, "Initial groups:");
+                MailboxImpl.dumpGroups(lookupGroups, MailboxImpl.initLogger, Level.CONFIG);
+            }
+            /*
+             * Note: Configuration provided locators are assumed to be
+             * prepared already.
+             */
+            lookupLocators = (LookupLocator[]) Config.getNonNullEntry(config, MailboxImpl.MERCURY, "initialLookupLocators", LookupLocator[].class, new LookupLocator[0]);
+            if (MailboxImpl.initLogger.isLoggable(Level.CONFIG)) {
+                MailboxImpl.initLogger.log(Level.CONFIG, "Initial locators:");
+                MailboxImpl.dumpLocators(lookupLocators, MailboxImpl.initLogger, Level.CONFIG);
+            }
+            final Entry[] initialAttrs = (Entry[]) Config.getNonNullEntry(config, MailboxImpl.MERCURY, "initialLookupAttributes", Entry[].class, new Entry[0]);
+            if (MailboxImpl.initLogger.isLoggable(Level.CONFIG)) {
+                MailboxImpl.initLogger.log(Level.CONFIG, "Initial lookup attributes:");
+                MailboxImpl.dumpAttrs(initialAttrs, MailboxImpl.initLogger, Level.CONFIG);
+            }
+            if (initialAttrs.length == 0) {
+                lookupAttrs = baseLookupAttrs;
+            } else {
+                lookupAttrs = new Entry[initialAttrs.length + baseLookupAttrs.length];
+                int i = 0;
+                for (int j = 0; j < baseLookupAttrs.length; j++, i++) {
+                    lookupAttrs[i] = baseLookupAttrs[j];
+                }
+                for (int j = 0; j < initialAttrs.length; j++, i++) {
+                    lookupAttrs[i] = initialAttrs[j];
+                }
+            }
+            if (MailboxImpl.initLogger.isLoggable(Level.FINEST)) {
+                MailboxImpl.initLogger.log(Level.FINEST, "Combined lookup attributes:");
+                MailboxImpl.dumpAttrs(lookupAttrs, MailboxImpl.initLogger, Level.FINEST);
+            }
+        } else {
+            // recovered logic
+            if (MailboxImpl.initLogger.isLoggable(Level.FINEST)) {
+                MailboxImpl.initLogger.log(Level.FINEST, "Preparing recovered locators:");
+                MailboxImpl.dumpLocators(lookupLocators, MailboxImpl.initLogger, Level.FINEST);
+            }
+            MailboxImpl.prepareExistingLocators(recoveredLocatorToJoinPreparer, lookupLocators);
+            //TODO - Add recovered state debug: groups, locators, etc.
+        }
+        if (persistent) {
+            // Take snapshot of current state.
+            if (MailboxImpl.initLogger.isLoggable(Level.FINEST)) {
+                MailboxImpl.initLogger.log(Level.FINEST, "Taking snapshot.");
+            }
+            log.snapshot();
+            // Reconstruct any transient state, if necessary.
+            //rebuildTransientState(recoveredListenerPreparer);
+            if (MailboxImpl.operationsLogger.isLoggable(Level.FINER)) {
+                MailboxImpl.operationsLogger.entering(MailboxImpl.mailboxSourceClass, "rebuildTransientState", recoveredListenerPreparer);
+            }
+            this.snapshotter = snapshotter;
+            // Reconstruct regByExpiration and pendingReg data structures,
+            // if necessary.
+            if (!regByID.isEmpty()) {
+                if (MailboxImpl.recoveryLogger.isLoggable(Level.FINEST)) {
+                    MailboxImpl.recoveryLogger.log(Level.FINEST, "Rebuilding transient state ...");
+                }
+                Collection<ServiceRegistration> regs = regByID.values();
+                Iterator<ServiceRegistration> iter = regs.iterator();
+                ServiceRegistration reg = null;
+                Uuid uuid = null;
+                EventLogIterator eli = null;
+                while (iter.hasNext()) {
+                    reg = iter.next(); // get Reg
+                    // get Reg
+                    uuid = reg.getCookie(); // get its Uuid
+                    // get its Uuid
+                    if (MailboxImpl.recoveryLogger.isLoggable(Level.FINEST)) {
+                        MailboxImpl.recoveryLogger.log(Level.FINEST, "Checking reg : {0}", reg);
+                    }
+                    // Check if registration is still current
+                    if (MailboxImpl.ensureCurrent(reg)) {
+                        if (MailboxImpl.recoveryLogger.isLoggable(Level.FINEST)) {
+                            MailboxImpl.recoveryLogger.log(Level.FINEST, "Restoring reg transient state ...");
+                        }
+                        try {
+                            reg.restoreTransientState(recoveredListenerPreparer);
+                        } catch (Exception e) {
+                            if (MailboxImpl.recoveryLogger.isLoggable(Levels.HANDLED)) {
+                                MailboxImpl.recoveryLogger.log(Levels.HANDLED, "Trouble restoring reg transient state", e);
+                            }
+                            try {
+                                reg.setEventTarget(null);
+                            } catch (IOException ioe) {
+                                throw new AssertionError("Setting a null target threw an exception: " + ioe);
+                            }
+                        }
+                        if (MailboxImpl.recoveryLogger.isLoggable(Level.FINEST)) {
+                            MailboxImpl.recoveryLogger.log(Level.FINEST, "Reinitializing iterator ...");
+                        }
+                        // regenerate an EventLogIterator for this Reg
+                        // Note that event state is maintained separately
+                        // through the event log mechanism.
+                        eli = persistent ? eventLogFactory.iterator(uuid, MailboxImpl.getEventLogPath(persistenceDirectory, uuid)) : eventLogFactory.iterator(uuid);
+                        reg.setIterator(eli);
+                        if (MailboxImpl.recoveryLogger.isLoggable(Level.FINEST)) {
+                            MailboxImpl.recoveryLogger.log(Level.FINEST, "Adding registration to expiration watch list");
+                        }
+                        // Put Reg into time sorted collection
+                        regByExpiration.put(reg, reg);
+                        // Check if registration needs to be added to the
+                        // pending list. Note, we could have processed
+                        // an "enabled" log record during recovery, so
+                        // only add it if it's not already there.
+                        // We don't need to check activeReg since the
+                        // the notifier hasn't kicked in yet. Don't call
+                        // enableRegistration() since it clears the "unknown
+                        // events" list which we want to maintain.
+                        if (reg.hasEventTarget() && !pendingReg.contains(uuid)) {
+                            if (MailboxImpl.recoveryLogger.isLoggable(Level.FINEST)) {
+                                MailboxImpl.recoveryLogger.log(Level.FINEST, "Adding registration to pending task list");
+                            }
+                            pendingReg.add(uuid);
+                        }
+                    } else {
+                        /* Registration has expired, so remove it via the iterator,
+                         * which is the only "safe" way to do it during a traversal.
+                         * Call the overloaded version of removeRegistration()
+                         * which will avoid directly removing the registration
+                         * from regByID (which would result in a
+                         * ConcurrentModificationException). See Bug 4507320.
+                         */
+                        if (MailboxImpl.recoveryLogger.isLoggable(Level.FINEST)) {
+                            MailboxImpl.recoveryLogger.log(Level.FINEST, "Removing expired registration: ");
+                        }
+                        iter.remove();
+                        //	            removeRegistration(uuid, reg, true);
+                        /**/
+                        // Remove Reg from data structures, if present.
+                        // If initializing, don't remove directly from regByID since we
+                        // currently traversing it via an iterator. Assumption is that
+                        // the caller has already removed it via the iterator.
+                        // See Bug 4507320.
+                        //                    if (!initializing) {
+                        //                        regByID.remove(uuid);
+                        //                    }
+                        regByExpiration.remove(reg);
+                        boolean exists = pendingReg.remove(uuid);
+                        MailboxImpl.NotifyTask task = activeReg.remove(uuid);
+                        if (task != null) {
+                            // cancel active task, if any
+                            task.cancel();
+                            if (MailboxImpl.deliveryLogger.isLoggable(Level.FINEST)) {
+                                MailboxImpl.deliveryLogger.log(Level.FINEST, "Cancelling active notification task for {0}", uuid);
+                            }
+                        }
+                        // Delete any associated resources
+                        try {
+                            if (MailboxImpl.persistenceLogger.isLoggable(Level.FINEST)) {
+                                MailboxImpl.persistenceLogger.log(Level.FINEST, "Removing logs for {0}", reg);
+                            }
+                            EventLogIterator it = reg.iterator();
+                            if (it != null) {
+                                it.destroy();
+                            }
+                        } catch (IOException ioe) {
+                            if (MailboxImpl.persistenceLogger.isLoggable(Levels.HANDLED)) {
+                                MailboxImpl.persistenceLogger.log(Levels.HANDLED, "Trouble removing logs", ioe);
+                            }
+                            // Did the best we could ... continue.
+                        }
+                        // Sanity check
+                        if (exists && task != null) {
+                            if (MailboxImpl.leaseLogger.isLoggable(Level.SEVERE)) {
+                                MailboxImpl.leaseLogger.log(Level.SEVERE, "ERROR: Registration was found " + "on both the active and pending lists");
+                            }
+                            // TODO (FCS)- throw assertion error
+                        }
+                        if (MailboxImpl.operationsLogger.isLoggable(Level.FINER)) {
+                            MailboxImpl.operationsLogger.exiting(MailboxImpl.mailboxSourceClass, "removeRegistration");
+                        }
+                        /**/
+                    }
+                }
+            }
+            if (MailboxImpl.operationsLogger.isLoggable(Level.FINER)) {
+                MailboxImpl.operationsLogger.exiting(MailboxImpl.mailboxSourceClass, "rebuildTransientState");
+            }
+        }
+        maxUnexportDelay = Config.getLongEntry(config, MailboxImpl.MERCURY, "maxUnexportDelay", 2 * TimeConstants.MINUTES, 0, Long.MAX_VALUE);
+        unexportRetryDelay = Config.getLongEntry(config, MailboxImpl.MERCURY, "unexportRetryDelay", TimeConstants.SECONDS, 1, Long.MAX_VALUE);
+    }
+    
+}

Modified: river/jtsk/skunk/qa_refactor/trunk/src/net/jini/discovery/LookupLocatorDiscovery.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/net/jini/discovery/LookupLocatorDiscovery.java?rev=1467198&r1=1467197&r2=1467198&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/net/jini/discovery/LookupLocatorDiscovery.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/net/jini/discovery/LookupLocatorDiscovery.java Fri Apr 12 08:11:54 2013
@@ -363,7 +363,7 @@ public class LookupLocatorDiscovery impl
     /** Thread that handles pending notifications. */
     private Notifier notifierThread;
     /** Notifications to be sent to listeners. */
-    private LinkedList pendingNotifies = new LinkedList();
+    private final LinkedList pendingNotifies = new LinkedList();
     /** Stores DiscoveryListeners **/
     private final ArrayList listeners = new ArrayList(1);
     /** Flag indicating whether or not this class is still functional. */