var getSessionFactory = function()

in database-jones/Adapter/api/UserContext.js [414:589]


var getSessionFactory = function(userContext, properties, tableMappings, callback) {
  var database;
  var dbServiceProvider;
  var connectionKey;
  var connection;
  var factory;
  var newSession;
  var sp;
  var i;

  function Connection(connectionKey) {
    this.connectionKey = connectionKey;
    this.factories = {};
    this.count = 0;
    this.isConnecting = true;
    this.waitingForConnection = [];
  }

  function newConnection(connectionKey) {
    var c = new Connection(connectionKey);
    jonesConnections[connectionKey] = c;
    return c;
  }

  function getConnection(connectionKey) {
    return jonesConnections[connectionKey];
  }

  function deleteFactory(key, database, callback) {
    udebug.log('deleteFactory for key', key, 'database', database);
    var c = jonesConnections[key];
    var f = c.factories[database];
    var dbConnectionPool = f.dbConnectionPool;
    
    delete c.factories[database];
    if (--connection.count === 0) {
      // no more factories in this connection
      udebug.log('deleteFactory closing dbConnectionPool for key', key, 'database', database);
      dbConnectionPool.close(callback);
      dbConnectionPool = null;
      delete jonesConnections[key];
    } else {
      callback();
    }
  }

  function resolveTableMappingsAndCallback() {
    function onMappingsResolved() {
      // close the session the hard way (not using UserContext)
      newSession.dbSession.close(function(err) {
        if (err) {
          callback(err, null);
        } else {
          // now remove the session from the session factory's open connections
          newSession.sessionFactory.closeSession(newSession.index);
          // mark this session as unusable
          newSession.closed = true;
          // if any errors during table mapping, report them
          if (userContext.errorMessages) {
            err = reportFirstError(userContext);
            callback(err, null);
          } else {
            // no errors
            callback(null, factory);
          }
        }
      });
    }

    // resolveTableMappingsAndCallback starts here
    if (!tableMappings) {
      callback(null, factory);
    } else {
      // get a session the hard way (not using UserContext) to resolve mappings
      var sessionSlot = factory.allocateSessionSlot();
      factory.dbConnectionPool.getDBSession(userContext.session_index, function(err, dbSession) {
        if (err) {
          // report error
          userContext.appendErrorMessage(err);
          err = new Error(userContext.errorMessages);
          callback(err, null);          
        } else {
          newSession = new apiSession.Session(sessionSlot, factory, dbSession);
          factory.sessions[sessionSlot] = newSession;
          resolveTableMappings(userContext, factory, newSession, tableMappings, onMappingsResolved);
        }
      });
    }
  }

  function createFactory(dbConnectionPool) {
    var newFactory;
    udebug.log('connect createFactory creating factory for', connectionKey, 'database', database);
    newFactory = new sessionFactory.SessionFactory(connectionKey, dbConnectionPool,
        properties, tableMappings, deleteFactory);
    return newFactory;
  }
  
  function dbConnectionPoolCreated_callback(error, dbConnectionPool) {
    if (connection.isConnecting) {
      // the first requester for this connection
      connection.isConnecting = false;
      // remember the error condition
      connection.error = error;
      if (error) {
        callback(error, null);
      } else {
        udebug.log('dbConnectionPool created for', connectionKey, 'database', database);
        connection.dbConnectionPool = dbConnectionPool;
        factory = createFactory(dbConnectionPool);
        connection.factories[database] = factory;
        connection.count++;
        resolveTableMappingsAndCallback();
      }
      // notify all others that the connection is now ready (or an error was signaled)
      for (i = 0; i < connection.waitingForConnection.length; ++i) {
        if(udebug.is_detail()) { udebug.log('dbConnectionPoolCreated_callback notifying...'); }
        connection.waitingForConnection[i](error, dbConnectionPool);
      }
    } else {
      // another user request created the dbConnectionPool and session factory
      if (error) {
        callback(error, null);
      } else {
        udebug.log('dbConnectionPoolCreated_callback', database, connection.factories);
        factory = connection.factories[database];
        if (!factory) {
          factory = createFactory(dbConnectionPool);
          connection.factories[database] = factory;
          connection.count++;
        }
        resolveTableMappingsAndCallback();
      }
    }
  }

  // getSessionFactory starts here
  database = properties.database;
  dbServiceProvider = jones.getDBServiceProvider(properties.implementation);
  connectionKey = dbServiceProvider.getFactoryKey(properties);
  connection = getConnection(connectionKey);

  if(connection === undefined) {
    // there is no connection yet using this connection key    
    udebug.log('connect connection does not exist; creating factory for',
               connectionKey, 'database', database);
    connection = newConnection(connectionKey);
    sp = jones.getDBServiceProvider(properties.implementation);
    sp.connect(properties, dbConnectionPoolCreated_callback);
  } else {
    // there is a connection, but is it already connected?
    if (connection.isConnecting) {
      // wait until the first requester for this connection completes
      udebug.log('connect waiting for db connection by another for', connectionKey, 'database', database);
      connection.waitingForConnection.push(dbConnectionPoolCreated_callback);
    } else {
      // there is a connection, but is there a SessionFactory for this database?
      factory = connection.factories[database];
      if (  factory === undefined) {
        if (!connection.dbConnectionPool) {
          // this connection is unusable due to failure reported in connection.error
          callback(connection.error);
          return;
        }
        // create a SessionFactory for the existing dbConnectionPool
        udebug.log('connect creating factory with existing', connectionKey, 'database', database);
        factory = createFactory(connection.dbConnectionPool);
        connection.factories[database] = factory;
        connection.count++;
      }
//    resolve all table mappings before returning
      resolveTableMappingsAndCallback();
    }
  }
  
};