> List of tutorials

Index of Basic knowledge for developing Fat-Clients with Java

Base-Class for the Database-Connection-Manager (JSBS_DB_ConnectionManager) - Fat-Client-Development

* For this document and all references (links) please obey the hints and regulations concerning copyright, disclaimer and trademarks.

  • The owner of this web-site (www.javascout.biz) is not responsible for the content of web-sites linked within this document or other documents of www.javascout.biz.

  • If this document or other documents of this web-site (www.javascout.biz) infringes your rights or you think that rights of others (third parties) are infringed, please inform the author.
    An e-mail can be sent by clicking onto the 'hungry mailbox' in the upper right corner.

Last revision of this document:
2006-07-24

This is document contains the code for Class JSBS_DB_ConnectionManager.
For easy 'cut and paste' ;-)

For an overview of the idea of Data-Base-Access Objects please refer to Using Business Objects to handle data-storage and -retrieval .
For an explanation how the variables in this object contribute to produce a change-history, please refer to Common Attributes for all database-tables .

package js_base.connections;

import java.sql.*;

import java.util.*;


import js_base.structures.*;

import js_base.xml.*;


/**
 
*
 * @author
kurt@javascout.biz
 * @date 2006-09-22
 *
 * @description
 *  Methods to establish and administrate connections to the database-system.
 *  This class keeps track of all connections to the database.
 *  As establishing of a connection to the database takes relatively long,
 *  no longer needed connections are not 'closed'; just marked as unused
 *  and used again at a new request for a database-connection (method 'reserveConnection').
 
*
 * @change-log
 * when         who               why
 * --------------------------------------------------------
 *
 */

public class JSBS_DB_ConnectionManager {
/*
 * VARIABLES
.
 * -------------------- */
/*
 * Vector with all established connections to the database. */
    
private Vector vecEstablishedConnections = new Vector();
/*
 * Vector with the method-names that are using a database-connection.
 * An empty string means, that the corresponding connection (in vecEstablishedConnections)
 * is unused and can be reassigned. */
    private Vector vecConnectionUsers
= new Vector();
/*
 * XML-structure with the parameters for the connection to the database. */
    
private JSBS_XML_Connections structJSBS_XML_Connections;
/*
 * Status-Code; with that a calling method can check if an error occured. */
    
public int StatusCode = 0;
/* Status-Message to return the text of a database-error. */
    public String StatusMsg = "";
/*
 * **********
 * Constants for possible Status-Codes happening in this class. */
    
static final int CONST_STATUS_OK = 0;
    static final int CONST_DATABASE_CONNECTION_BROKE = 1;
    static final int CONST_DATABASEDRIVERNAME_ELEMENT_MISSING = 2;
    static final int CONST_DATABASENAME_ELEMENT_MISSING = 3;
    static final int CONST_DATABASEUSERID_ELEMENT_MISSING = 4;
    static final int CONST_DATABASEPASSWORD_ELEMENT_MISSING = 5;
    static final int CONST_DATABASEDRIVER_LOAD_FAILED = 11;
    static final int CONST_DATABASE_CONNECTION_FAILED = 12;
    static final int CONST_CLASS_MISSMATCH = 21;
    static final int CONST_INVALID_REFERENCE = 22;
    static final int CONST_UNKNOWN_ERROR = 999;
/*
 * Offset for Status-Codes returned by the method to read the parameter-file. */
    static final int CONST_XML_STATUS_OFFSET = 100;

/*
 * CONSTURCTOR of the class
 * -------------------- */

    
public JSBS_DB_ConnectionManager(JSBS_UniversalParameters parmJSBS_UniversalParameters) {
/*
 * Reset the Status-Message. */
      
StatusMsg = "";

/*
 * Initialize the XML-structure with the parameters for Database-Connection;
 * the Constructur of the class includes reading the file with the XML-structure. */
      structJSBS_XML_Connections = new JSBS_XML_Connections(parmJSBS_UniversalParameters);
/*
 * Check the status of the just initialized structure and report an error to the calling method. */
      if (structJSBS_XML_Connections.StatusCode == JSBS_XML_Constants.CONST_OK) {
        StatusCode = CONST_STATUS_OK;
      }
      else {
        StatusCode = CONST_XML_STATUS_OFFSET + structJSBS_XML_Connections.StatusCode;
        return;
      }

/*
 * Check that all needed parameters are present. */
      if (structJSBS_XML_Connections.getDataBaseDriverName() == null) {
        StatusCode = CONST_DATABASEDRIVERNAME_ELEMENT_MISSING;
        return;
      }

/* */
      if (structJSBS_XML_Connections.getDataBaseName() == null) {
        StatusCode = CONST_DATABASENAME_ELEMENT_MISSING;
        return;
      }

/* */
      if (structJSBS_XML_Connections.getDataBaseUserID() == null) {
        StatusCode = CONST_DATABASEUSERID_ELEMENT_MISSING;
        return;
      }

/* */
      if (structJSBS_XML_Connections.getDataBasePassword() == null) {
        StatusCode = CONST_DATABASEPASSWORD_ELEMENT_MISSING;
        return;
      }

/*
 * Reserve the first database-connection to check if a database-connection can be established. */
      int locintDBConnectionReference = reserveConnection(this, true);
      if ( locintDBConnectionReference < 0) return;
      Connection locDBConnection = getReservedConnection(this, locintDBConnectionReference);
      returnReservedConnection(this, locintDBConnectionReference);
    }

/*
 * METHODS
 * -------------------- */

/*
 * Method to 'reserve' a connection.
 * First, it is checked if there is an unused connection (to the database)
 * available within the vector.
 * If there is one, then it is reserved (the calling class is stored in the vecConnectionUser),
 * to find it later, the index of the vector-element is returned.
 * If there is no unused connection, the vector is extended by 1 element and the
 * newly established database-connection is stored in the new element.
*/
    public synchronized int reserveConnection(Object parmRequestedFromClass, boolean parmReadOnly) {
/*
 * Database-connection; needed if a new DB-connection has to be established. */
      Connection conDBConnection = null;
/*
 * Reset the Status-Code and the Status-Message. */
      
StatusCode = CONST_STATUS_OK;
      StatusMsg = "";
/*
 * Check if there is an unused connection available. */
      int locintVectorSize = vecEstablishedConnections.size();
      int
locintVectorIndex;
      Object classInVector;
/*    */
      for (locintVectorIndex = 0; locintVectorIndex < locintVectorSize; locintVectorIndex++) {
        classInVector = (Object) vecConnectionUsers.elementAt(locintVectorIndex);
        if (classInVector == null) {
/* Found an unused connection.
 * Change the null-class against the class that requests the connection.
 * This marks the connection as 'used'   */
          vecConnectionUsers.setElementAt(parmRequestedFromClass, locintVectorIndex);
/* Set the 'AutoCommit' if the 'ReadOnly'-parameter is passed.
 * With AutoCommit the rollback-buffer can be managed more efficient and that increases performance.  */
          conDBConnection = (Connection) vecEstablishedConnections.elementAt(locintVectorIndex);
          try {
            if (parmReadOnly) conDBConnection.setAutoCommit(true);
            else conDBConnection.setAutoCommit(false);
          }
          catch(SQLException SQLExc) {
            StatusCode = CONST_DATABASE_CONNECTION_BROKE;
            StatusMsg = SQLExc.getMessage();
            return -1;
          }
/* Existing unused database-connection marked as used;
 * return index of the vector as 'reservation-number'.  */
          return locintVectorIndex;
        }
      }
/* 
 * No unused connection found within the vector.
 * Open a new database-connection and register it at a vector-element.  */
/* 
 * First check if the XML-structure with the DB-connection-parameters
 * covers all parameters.  */
      String locstrDataBaseDriverName = structJSBS_XML_Connections.getDataBaseDriverName();
      if (locstrDataBaseDriverName == null) {
        StatusCode = CONST_DATABASEDRIVERNAME_ELEMENT_MISSING;
        return -1;
      }

/* */
      String locstrDataBaseName = structJSBS_XML_Connections.getDataBaseName();
      if (locstrDataBaseName == null) {
        StatusCode = CONST_DATABASENAME_ELEMENT_MISSING;
        return -1;
      }

/* */
      String locstrDataBaseUserID = structJSBS_XML_Connections.getDataBaseUserID();
      if ( locstrDataBaseUserID == null) {
        StatusCode = CONST_DATABASEUSERID_ELEMENT_MISSING;
        return -1;
      }

/* */
      String locstrDataBasePassword = structJSBS_XML_Connections.getDataBasePassword();
      if (locstrDataBasePassword == null) {
        StatusCode = CONST_DATABASEPASSWORD_ELEMENT_MISSING;
        return -1;
      }

/*
 * Load the class with the database-driver */
      try {
        Class.forName(locstrDataBaseDriverName);
      }
      catch(Exception e) {
        StatusCode = CONST_DATABASEDRIVER_LOAD_FAILED;
        StatusMsg = "Error while loading class for database-driver: " + locstrDataBaseDriverName;
        return -1;
      }
/*
 * Establish the connection to the database */
      try {
        conDBConnection = DriverManager.getConnection(locstrDataBaseName,
                                                       locstrDataBaseUserID,
                                                       locstrDataBasePassword);
      }
      catch
(Exception e) {
        StatusCode = CONST_DATABASE_CONNECTION_FAILED;
        StatusMsg = "Error while establishing database connection for: " +
                    locstrDataBaseName + ", " +
                    locstrDataBaseUserID + ", " +
                    locstrDataBasePassword;
        return -1;
      }
/* Set the 'AutoCommit' if the 'ReadOnly'-parameter is passed.
 * With AutoCommit the rollback-buffer can be managed more efficient and that increases performance.  */
      try {
       if (parmReadOnly) conDBConnection.setAutoCommit(true);
       else conDBConnection.setAutoCommit(false);
 
     }
      catch(SQLException SQLExc) {
        StatusCode = CONST_DATABASE_CONNECTION_BROKE;
        StatusMsg = SQLExc.getMessage();
        return -1;
      }
/*
 * New database-connection established; add it in the new elements of the vetors */
      vecEstablishedConnections.addElement(conDBConnection);
      vecConnectionUsers.addElement(parmRequestedFromClass);
      StatusCode = CONST_STATUS_OK;
 
     return (vecEstablishedConnections.size() - 1);
    }

/*
 * Method to get the handle to a previously reserved database-connection.
 * There is a cross-check implemented that the requesting class is the same
 * as the one that reserved the connection.
 * This is to prevent an erratically miss-assigning of connections. */

    
public synchronized Connection getReservedConnection(Object parmRequestedFromClass,
                                                         int parmConnectionReference) {

/*
 * Reset the Status-Code. */
      
StatusCode
= CONST_STATUS_OK;
/*
 * Check if the reference-number fits within the size of the vector. */
      if (   (parmConnectionReference < 0)
          || (parmConnectionReference > (vecEstablishedConnections.size() -1))) {

        StatusCode = CONST_INVALID_REFERENCE;
 
       return null;
      }
/*
 * Check if the class which reserved the connection is requesting it now. */
      if (parmRequestedFromClass.equals((Object) vecConnectionUsers.elementAt(parmConnectionReference))) {
        Connection conDBConnection =
          (Connection) vecEstablishedConnections.elementAt(parmConnectionReference);

        
StatusCode = CONST_STATUS_OK;
 
       return conDBConnection;
      }
      else {
/*
 * Mismatch between class which reserved the connection and class which requests it now. */
        StatusCode = CONST_CLASS_MISSMATCH;
 
       return null;
      }
    }

/*
 * Method to return the handle of a previously reserved database-connection.
 * There is a cross-check implemented that the returning class is the same
 * as the one that reserved the connection.
 * This is to prevent an erratically miss-assigning of connections. */

    
public synchronized void returnReservedConnection(Object parmRequestedFromClass,
                                                         int parmConnectionReference) {

/*
 * Reset the Status-Code. */
      
StatusCode
= CONST_STATUS_OK;
/*
 * Check if the reference-number fits within the size of the vector. */
      if (   (parmConnectionReference < 0)
          || (parmConnectionReference > (vecEstablishedConnections.size() -1))) {

        
StatusCode
= CONST_INVALID_REFERENCE;
 
       return;
      }
/*
 * Cross-check if the class that reserved the connection is returning it now. */
      if (parmRequestedFromClass.equals((Object) vecConnectionUsers.elementAt(parmConnectionReference))) {
/*
 * Close the connection so that the data-relation is consistent. */
        
Connection conDBConnection =
            (Connection) vecEstablishedConnections.elementAt(parmConnectionReference);
        try {
/* Safety-check if the connection was already closed by a method using it. */
          if (! conDBConnection.isClosed()) {;
            if (! conDBConnection.getAutoCommit()) {
/* 'AutoCommit' not chosen; do the commit now. */
              conDBConnection.commit();
            }
            conDBConnection.close();
          }

 
       }
        catch(SQLException SQLExc) {
/* Error in the database-system occured during close; report it to the calling method. */
          StatusCode = CONST_DATABASE_CONNECTION_BROKE;
          StatusMsg = SQLExc.getMessage();
          return;
        }
/* If the connection was the last element within the vector then remove the vector elements. */
        if
(parmConnectionReference == (vecEstablishedConnections.size() - 1)) {
          vecEstablishedConnections.removeElementAt(parmConnectionReference)
;
          vecConnectionUsers.removeElementAt(parmConnectionReference);
          StatusCode = CONST_STATUS_OK;
          return;
        }
        else
{
/* If the connection was not the last element within the vector
 * then reopen it immediately – that saves time when it is re-used. */
/*
 * Get the parameters out of the XML-structure. */
          String locstrDataBaseDriverName = structJSBS_XML_Connections.getDataBaseDriverName();
          String locstrDataBaseName = structJSBS_XML_Connections.getDataBaseName();
          String locstrDataBaseUserID = structJSBS_XML_Connections.getDataBaseUserID();
          String locstrDataBasePassword = structJSBS_XML_Connections.getDataBasePassword();
/*
 * Load the class with the database-driver */
          try
{
            Class.forName(locstrDataBaseDriverName);
          }
          catch(Exception e) {
            StatusCode = CONST_DATABASEDRIVER_LOAD_FAILED;
    
        StatusMsg = "Error while loading class for database-driver: " + locstrDataBaseDriverName;
            return;
          }
/*
 * Establish the connection to the database */
          try {
            conDBConnection = DriverManager.getConnection(locstrDataBaseName,
                                                           locstrDataBaseUserID,
                                                           locstrDataBasePassword);
            conDBConnection.setAutoCommit(false);
          }
          catch(Exception e) {
            StatusCode = CONST_DATABASE_CONNECTION_FAILED;
            StatusMsg = "Error while establishing database connection for: " +
                        locstrDataBaseName + ", " +
                        locstrDataBaseUserID + ", " +
                        locstrDataBasePassword;
            return;
          }
/*
 * Mark the connection as unused by setting the user(-class) to 'null'. */
          vecConnectionUsers.setElementAt(null, parmConnectionReference);
          StatusCode
= CONST_STATUS_OK;
          return;
        }
      }
      else {
/*
 * Mismatch between class which reserved the connection and class which requests it now. */
        StatusCode = CONST_CLASS_MISSMATCH;
        return;
      }
    }

}