=== modified file 'src/com/goldencode/p2j/persist/DatabaseManager.java'
--- src/com/goldencode/p2j/persist/DatabaseManager.java	2021-03-19 12:14:26 +0000
+++ src/com/goldencode/p2j/persist/DatabaseManager.java	2021-05-15 21:43:38 +0000
@@ -376,6 +376,12 @@
  */
 public final class DatabaseManager
 {
+   /** Logger. */
+   private static final Logger LOG = LogHelper.getLogger(DatabaseManager.class.getName());
+ 
+  /** session auto-connection registry key */
+   private static final String CFG_AUTO_CONNECT = "database-connections";
+   
    /** Reserved name of temp table schema */
    public static final String TEMP_TABLE_SCHEMA = "_temp";
    
@@ -403,6 +409,10 @@
    
    /** Set of databases auto-connected at bootstrap */
    private static final Set<Database> permanentConnections = new LinkedHashSet<>();
+
+   /** Map of managed non-permanent databases to sets of connected sessions. */
+   private static final Map<Database, Set<com.goldencode.p2j.net.Session>> sessionDBs = 
+            new ConcurrentHashMap<>();
    
    /** Map of databases to database {@code Dialect} objects */
    private static final Map<Database, Dialect> dialects = new ConcurrentHashMap<>();
@@ -416,6 +426,46 @@
    /** Set of DMO entity names which correspond to read-only tables */
    private static final Set<String> readOnly = new HashSet<>();
    
+   /** Flag indicating that the metadata manager was initialized */ 
+   private static boolean useMeta = false;
+
+   /** Set of registered meta dbs */
+   private static final Set<String> metaDBs = ConcurrentHashMap.newKeySet();
+   
+   /** Session listener */
+   public static SessionListener sessionListener = new SessionListener()
+   {
+      @Override
+      public void initialize(com.goldencode.p2j.net.Session session)
+      {
+         Directory dir = DirectoryManager.getInstance();
+         List<String> connectStrings = dir.getStrings(Directory.ID_RELATIVE, CFG_AUTO_CONNECT);
+         for(String connectString: connectStrings)
+         {
+            LOG.info("Connecting to [" + connectString + "]");
+            ConnectionManager.connect(connectString);
+         }
+      }
+
+      @Override
+      public void terminate(com.goldencode.p2j.net.Session session)
+      {
+         for (Database db: session.sessionDbs())
+         {
+            Set<com.goldencode.p2j.net.Session> connected = sessionDBs.get(db);
+            if (connected == null || !connected.remove(session))
+            {
+               LOG.warning(String.format(
+                        "Session %s not regiterd for database %s",
+                        session.toString(),
+                        db.toString()
+               ));
+            }
+         }
+         
+      }
+   }; 
+
    /** Context local data */
    private static final ContextLocal<Context> context = new ContextLocal<Context>()
    {
@@ -578,7 +628,7 @@
       for (Database database : getManagedDatabases())
       {
          Persistence persistence = PersistenceFactory.getInstance(database);
-         LockManager manager = persistence.getLockManager();
+         LockManager<?> manager = persistence.getLockManager();
          LockAdministrator admin = manager.getLockAdministrator();
          if (admin != null)
          {
@@ -890,6 +940,15 @@
       return new character();
    }
    
+   /**
+    * Get the database configuration.
+    * @param database
+    *        the database which configuration is requested
+    * @return the database configuration
+    *       
+    * @throws PersistenceException
+    *          if an error occurs accessing configuration data.
+    */
    public static DatabaseConfig getConfiguration(Database database)
    throws PersistenceException
    {
@@ -1006,8 +1065,6 @@
             
             try
             {
-               boolean useMeta = false;
-               
                String dbID = Utils.findDirectoryNodePath(ds, "database", "container", false);
                
                // Read the names of all permanently connected databases.
@@ -1070,113 +1127,27 @@
                   }
                }
                
-               HashSet<String> metaDBs = new HashSet<>();
-               
                // Collect name and permanence data.
                for (String nodeID : dbNodes)
                {
                   String pdb = nodeID.replace('.', File.separatorChar);
-                  Database primaryDB = new Database(pdb, Database.Type.PRIMARY, true);
-                  Database metaDB = null;
-                  Database[] dbs = null;
-                  
-                  if (useMeta && !TEMP_TABLE_DB.equals(primaryDB))
+                  if (TEMP_TABLE_SCHEMA.equals(pdb))
                   {
-                     // create and prepare the physical meta database
-                     metaDB = new Database(pdb, Database.Type.META, true);
-                     MetadataManager.prepareDatabase(metaDB);
-                     dbs = new Database[] { metaDB, primaryDB };
+                     initTempDb();
                   }
                   else
                   {
-                     dbs = new Database[] { primaryDB };
-                  }
-                  
-                  // determine auto-connect status
-                  Boolean perm = ds.getNodeBoolean(
-                     dbID + "/" + nodeID + "/p2j/load_at_startup",
-                     "value");
-                  
-                  // if directory is silent on auto-connect, assume true
-                  if (perm == null)
-                  {
-                     perm = true;
-                  }
-                  
-                  for (Database database : dbs)
-                  {
-                     // read and cache the database configuration info
-                     DatabaseConfig cfg = getLocalConfiguration(database);
-                     
-                     if (!TEMP_TABLE_DB.equals(database))
-                     {
-                        // remember that this server is authoritative for this database (not
-                        // including temp table database)
-                        managed.add(database);
-                        
-                        if (useMeta && database.isPrimary() && lockTableUpdaters != null)
-                        {
-                           // create and store lock table updater for primary database, if needed;
-                           // will be registered with lock manager when that object is created
-                           // later; creating these now ensures the proper server context is used
-                           // for the associated worker thread created by the updater
-                           LockTableUpdater ltu = new LockTableUpdater(metaDB);
-                           lockTableUpdaters.put(primaryDB, ltu);
-                        }
-                     }
-                     
-                     // if database must be auto-connected or is a meta database, register it now
-                     if (perm || database.isMeta())
-                     {
-                        // register database
-                        registerDatabase(cfg, database, true, false);
-                        
-                        if (useMeta && !TEMP_TABLE_DB.equals(primaryDB))
-                        {
-                           // initialize infrastructure for _connect metadata
-                           ConnectionManager.initializeMeta(primaryDB, metaDB);
-                           
-                           // initialize infrastructure for _trans metadata
-                           TransactionManager.initializeMeta(primaryDB);
-                        }
-                        
-                        // preload Persistence object for database
-                        PersistenceFactory.getInstance(database);
-                        
-                        // register a dirty database, only if this is a non-temp database
-                        if (database.isPrimary() && !TEMP_TABLE_DB.equals(database))
-                        {
-                           Persistence.reportUDFVersion(database);
-                           registerDirtyDatabase(cfg, database, true);
-                        }
-                     }
-                     else if (database.isPrimary() && useMeta && metaDB != null)
-                     {
-                        registerDatabase(cfg, database, false, false);
-                        PersistenceFactory.getInstance(database);
-                     }
-                  }
-                  
-                  if (useMeta && metaDB != null)
-                  {
-                     DatabaseConfig cfg = getLocalConfiguration(primaryDB);
-                     String schema = cfg.getSchema();
-                     if (!metaDBs.contains(schema))
-                     {
-                        metaDBs.add(schema);
-                        
-                        // populate the meta database
-                        MetadataManager.populateDatabase(metaDB, schema);
-                        
-                        // initialize the meta persistence's lock table updater to be that of
-                        // the primary database
-                        if (lockTableUpdaters != null)
-                        {
-                           Persistence mPrim = PersistenceFactory.getInstance(metaDB);
-                           mPrim.shareLockTableUpdater(primaryDB);
-                        }
-                     }
-                  }
+                     // determine auto-connect status (default is true)
+                     boolean perm = !Boolean.FALSE.equals(
+                              ds.getNodeBoolean(
+                                    dbID + "/" + nodeID + "/p2j/load_at_startup",
+                                    "value"));
+                     initDb(pdb, perm);
+                  }
+               }
+               if (!permanentConnections.contains(TEMP_TABLE_DB))
+               {
+                  initTempDb();
                }
             }
             finally
@@ -1206,6 +1177,158 @@
       // Identity manager multiplexer.
       IdentityManagerMultiplexerImpl.initialize();
    }
+
+   private static void initDb(String pdb, boolean activate) 
+   throws PersistenceException
+   {
+      Database primaryDB = new Database(pdb, Database.Type.PRIMARY, true);
+      Database metaDB = null;
+      DatabaseConfig cfg = getLocalConfiguration(primaryDB);
+      String schema = cfg.getSchema();
+
+      // Remember the database to schema name mapping.
+      schemaByDatabase.put(primaryDB, schema);
+      
+      if (useMeta)
+      {
+         metaDBs.add(schema);
+         // create and prepare the physical meta database
+         metaDB = new Database(pdb, Database.Type.META, true);
+         registerDb(metaDB, activate);
+         if (lockTableUpdaters != null)
+         {
+            LockTableUpdater ltu = new LockTableUpdater(metaDB);
+            lockTableUpdaters.put(primaryDB, ltu);
+         }
+      }
+      registerDb(primaryDB, activate);
+      if (activate)
+      {
+         activateMetaDb(schema, primaryDB, metaDB, true);
+      }
+   }
+
+   private static void activateMetaDb(String schema, Database primaryDB, Database metaDB, 
+                                      boolean bootstrap)
+   throws PersistenceException
+   {
+      if (!useMeta)
+      {
+         return;
+      }
+      initMetaDb(schema, primaryDB, metaDB, bootstrap);
+      // initialize the meta persistence's lock table updater to be that of
+      // the primary database
+      if (lockTableUpdaters != null)
+      {
+         Persistence mPrim = PersistenceFactory.getInstance(metaDB);
+         mPrim.shareLockTableUpdater(primaryDB);
+      }
+   }
+
+   private static void activateDb(DatabaseConfig cfg, Database database)
+   throws PersistenceException
+   {
+      registerDatabase(cfg, database, false, false);
+      // preload Persistence object for database
+      PersistenceFactory.getInstance(database);
+      
+      if (database.isPrimary())
+      {
+         registerDirtyDatabase(cfg, database, true);
+      }
+   }
+   
+   public static void activate(String pdb)
+   throws PersistenceException
+   {
+      Database primaryDB = new Database(pdb, Database.Type.PRIMARY, true);
+      if (!managed.contains(primaryDB))
+      {
+         throw new PersistenceException("Unknown local database: [" + pdb + "]");
+      }
+      com.goldencode.p2j.net.Session session = SessionManager.get().getSession();
+      DatabaseConfig cfg = getLocalConfiguration(primaryDB);
+      activateAndRegister(session, primaryDB, () -> activateDb(cfg, primaryDB));
+
+      if (useMeta)
+      {
+         String schema = cfg.getSchema();
+         Database metaDB = new Database(pdb, Database.Type.META, true);
+         activateAndRegister(session, metaDB, 
+                  () -> activateMetaDb(schema, primaryDB, metaDB, false));
+      }
+   }
+   
+   private static void activateAndRegister(
+            com.goldencode.p2j.net.Session session, 
+            Database db, 
+            Activator activator) 
+   throws PersistenceException
+   {
+      Set<com.goldencode.p2j.net.Session> connected = sessionDBs.get(db);
+      if (connected == null)
+      {
+         connected = ConcurrentHashMap.newKeySet();
+         Set<com.goldencode.p2j.net.Session> connected_ = 
+                  sessionDBs.putIfAbsent(db, connected);
+         if (connected_ != null)
+         {
+            connected = connected_;
+         }
+         else 
+         {
+            activator.activate();;
+         }
+      }
+      connected.add(session);
+      session.registerDb(db);
+   }
+   
+   private static void initMetaDb(String schema, Database primaryDB, Database metaDB, 
+                                  boolean bootstrap)
+   throws PersistenceException
+   {
+      MetadataManager.prepareDatabase(metaDB);
+      if (!bootstrap)
+      {
+         MetadataManager.setupIdentityManager(metaDB, dialects.get(metaDB));
+      }
+      TransactionManager.initializeMeta(primaryDB);
+      MetadataManager.populateDatabase(metaDB, schema);
+   }
+
+   private static void registerDb(Database database, boolean activate) 
+   throws PersistenceException
+   {
+      // read and cache the database configuration info
+      DatabaseConfig cfg = getLocalConfiguration(database);
+      managed.add(database);
+
+      // Remember dialect for this database.
+      Settings settings = cfg.getOrmSettings();
+      Dialect dialect = Dialect.getDialect(settings);
+      dialects.put(database, dialect);
+      Persistence.reportUDFVersion(database);
+
+      if (activate)
+      {
+         activateDb(cfg, database);
+      }
+   }
+
+   private static void initTempDb()
+   throws PersistenceException
+   {
+      Database tempDB = new Database(TEMP_TABLE_SCHEMA, Database.Type.PRIMARY, true);
+      DatabaseConfig cfg = getLocalConfiguration(tempDB);
+      // register database
+      registerDatabase(cfg, tempDB, true, false);
+      
+      // preload Persistence object for database
+      PersistenceFactory.getInstance(tempDB);
+   }
+   
    
    /**
     * Indicate whether the database manager is currently initializing.
@@ -1823,7 +1946,6 @@
             
             return false;
          }
-         
          // Determine global reference count for this database.
          Integer refCountObj = transientDatabases.get(database);
          int refCount = (refCountObj != null) ? refCountObj : 0;
@@ -1850,9 +1972,6 @@
             String schema = dbConfig.getSchema().intern();
             boolean isTemp = TEMP_TABLE_SCHEMA.equals(schema);
             
-            // Remember the database to schema name mapping.
-            schemaByDatabase.put(database, schema);
-            
             // Get list of classes for the given schema.
 //            Iterator<Class<? extends Record>> iter = DMOIndex.classes(schema);
 //            if (iter == null && !isTemp && log.isLoggable(Level.WARNING))
@@ -1869,10 +1988,6 @@
             
             try
             {
-               // Remember dialect for this database.
-               Settings settings = dbConfig.getOrmSettings();
-               Dialect dialect = Dialect.getDialect(settings);
-               dialects.put(database, dialect);
                
                // TODO: disabling this for now, as this information is now retrieved from DMO annotations;
                // however, keeping this code around to eventually be used to compare index metadata in the
@@ -1887,7 +2002,7 @@
                
                if (database.isMeta() /*|| (database.isPrimary() && !isTemp)*/)
                {
-                  MetadataManager.setupIdentityManager(database, dialect);
+                  MetadataManager.setupIdentityManager(database, dialects.get(database));
                }
                
                // Note that parsed Hibernate mappings are stored by schema, for each database
@@ -2462,4 +2577,18 @@
          dynamicDMOIfaces = null;
       }
    }
+   
+   /**
+    * Database activator
+    */
+   @FunctionalInterface
+   private static interface Activator
+   {
+      /**
+       * Activate.
+       * @throws PersistenceException
+       *         if any error is encountered initializing the persistence framework.
+       */
+      public void activate() throws PersistenceException;
+   }
 }

