<snip>
On Fri, 28 Jan 2005 08:46:30 -0600, Scott Purcell
<[EMAIL PROTECTED]> wrote:
> Hello,
> 
> I am running Tomcat struts. I am beginning a new project using the struts 
> technologies and have a question in regards to handling connections.
> 
> First off, just to give you some background, older projects I worked on had a 
> singleton class that handed me database connections. So when I needed a 
> connection, I would just ask for a connection from a static class.
> 
> Now that I am starting into my struts project, I am beginning to wonder how 
> the best practice would be to handle connections. In tomcat I configured a 
> <ResourceParams name="jdbc/JNDITest" object to configure the data source.
</snip>

Struts does not care, of course, whether you use JNDI or
ServiceLocator or not, cf.
http://java.sun.com/blueprints/corej2eepatterns/Patterns/index.html . 
If you don't have the problem a pattern is meant to solve, don't use
the pattern.  Nothing wrong with a simple design where there is a
simple problem.  I use a DAOFactory that is preconfigured to different
databases, such as MySQL, PostgreSQL, Sybase, etc.  I also use a
Thread pool for connections that has worked so well for me that I have
never found something better.  I have tried many times, but have not.

I start with a SiteConnection which has a static ConnectionPool field
and returns a Connection object.

public class SiteConnection {
  private static ConnectionPool pool;

  private SiteConnection() {
  }

  public static final Connection getConnection()
      throws SQLException {
    if(pool == null) {
      pool = ConnectionPoolFactory.getInstance(SiteConstant.SITE_DATABASE);
    }
    return pool.getConnection();
  }
}

The ConnectionPool is an abstract class:

public abstract class ConnectionPool {
  private   static final String           LINUX           = "src";
  private   static final String           COM             = "com";
  private   static final String           CONNECTION_POOL = "[package
address + ConnectionPool.class]";
  protected static       ConnectionThread thread;
  protected static       Hashtable        connections;

  public abstract Connection getConnection() throws SQLException;

  public static final void checkConnections() {
    Enumeration keys   = connections.keys();
    Thread      thread = null;
    Connection  conn   = null;

    while(keys.hasMoreElements()) {
      thread = (Thread)keys.nextElement();
      if(!thread.isAlive()) {
        conn = (Connection)connections.remove(thread);
        if (conn != null) {
          try {
           conn.close();
          } catch(SQLException sqle) {
           // ignore an exception closing the conn
          }
        }
      }
    }
  }

  public static final void closeConnections() {
    Enumeration keys   = connections.keys();
    Thread      thread = null;
    Connection  conn   = null;

    while(keys.hasMoreElements()) {
      thread = (Thread)keys.nextElement();
      conn = (Connection)connections.remove(thread);
      if (conn != null) {
        try {
         StdOut.log("log.database.shutdown","\tConnection is not null:
so, connection " + conn + " closed");
         conn.close();
        } catch(SQLException sqle) {
         // ignore an exception closing the connection
        }
      }
    }
  }

  protected static final String getClasspath() {
    ClassLoader loader  = Classpath.class.getClassLoader();
    URL         url     = loader.getResource(CONNECTION_POOL);
    String      content = url.getFile();

    if (content.indexOf(LINUX) >= 0) {
      return content.substring(0, content.lastIndexOf(COM));
    } else {
      return content.substring(1, content.lastIndexOf(COM));
    }
  }
} ///;-)

The ConnectionPoolFactory is also an abstract class:

public abstract class ConnectionPoolFactory {
  private static ConnectionPool connectionPool;

  public static ConnectionPool getInstance(String connectionPoolType) {
    if(connectionPool != null) {
      return connectionPool;
    }
    Class clazz = null;
    try {
      clazz = Class.forName(connectionPoolType);
    } catch (ClassNotFoundException cnfe) {
      StdOut.log(SiteConstant.ERROR_LOG,cnfe.getMessage());
    }
    try {
      connectionPool = (ConnectionPool)clazz.newInstance();
    } catch (IllegalAccessException iae) {
      StdOut.log(SiteConstant.ERROR_LOG,iae.getMessage());
    } catch (InstantiationException ie) {
      StdOut.log(SiteConstant.ERROR_LOG,ie.getMessage());
    }
    return connectionPool;
  }

  public abstract boolean createConnectionPool();
  public abstract boolean populateConnectionPool();
  public abstract boolean setDAOFactory(String ConnectionPool);

}

Particular database factories are called depending on what the
SiteConstant.DATABASE value is.  For example, HSQLDB might be:


public class DAOHsqlFactory
    extends DAOFactory {
  public DAOHsqlFactory() {
  }

  public Connection createConnection()
      throws SQLException, ChainedException {
      Connection connection = SiteConnection.getConnection();
      return connection;
  }

  public DAOGuiKey getDAOGuiKey() { return new DAOHsqlGuiKey(); }
  public DAOHostKey getDAOHostKey() { return new DAOHsqlHostKey(); }
  public DAOId getDAOId() { return new DAOHsqlId(); }
  public DAOKey getDAOKey()  { return new DAOHsqlKey(); }
  public DAOMail getDAOMail()  { return new DAOHsqlMail(); }
  public DAOPort getDAOPort() { return new DAOHsqlPort(); }
  public DAOSite getDAOSite() { return new DAOHsqlSite(); }
  public DAOUser getDAOUser() { return new DAOHsqlUser(); }
}

A ConnectionPool type might be:


public final class HsqlPool
    extends ConnectionPool {
  private static       String DB_TYPE  = "jdbc:hsqldb:";
  private static final String PATH     = getClasspath()  + [database package];
  private static final String DATABASE = "[database name";
  private static final String USERNAME = "[username]l";
  private static final String PASSWORD = "[password]";
  private static final String DRIVER   = "org.hsqldb.jdbcDriver";
  private static final String DB_URL   = DB_TYPE + PATH + DATABASE;

  public HsqlPool() {
    if (connections == null) {
      connections = new Hashtable();
    }
    if (thread == null || ! thread.isAlive()) {
      thread = new ConnectionThread();
      thread.start();
    }
    try {
      Class.forName(DRIVER);
    } catch(ClassNotFoundException cnfe) {
      throw new RuntimeException(cnfe.toString());
    }

    Properties properties = System.getProperties();
    properties.put("jdbc.DRIVERs", DRIVER);
    System.setProperties(properties);
  }

  public Connection getConnection()
      throws SQLException {
    Thread threadCurrent = Thread.currentThread();
    Connection conn = (Connection)connections.get(threadCurrent);
    if (conn == null) {
      conn = DriverManager.getConnection(DB_URL, USERNAME, PASSWORD);
      connections.put(threadCurrent, conn);
    }
    return conn;
  }
}

or 

public final class MySQLPool extends ConnectionPool {
  private static final String           USERNAME = "[username]";
  private static final String           PASSWORD = "[password]";
  private static final String           DRIVER   = "org.gjt.mm.mysql.Driver";
  private static final String           DB_URL   =
"jdbc:mysql://localhost/[database name]";
  private static       ConnectionThread thread;

  public MySQLPool() {
    if (connections == null) {
      connections = new Hashtable();
    }

    if (thread == null || ! thread.isAlive()) {
      thread = new ConnectionThread();
      thread.start();
    }

    try {
      Class.forName(DRIVER);
    } catch(ClassNotFoundException cnfe) {
      throw new RuntimeException(cnfe.toString());
    }

    Properties properties = System.getProperties();
    properties.put("jdbc.drivers", DRIVER);
    System.setProperties(properties);
  }

  public Connection getConnection()
      throws SQLException {
    Thread         threadCurrent = Thread.currentThread();
    Connection     conn          = (Connection)connections.get(threadCurrent);
    if (conn == null) {
      StdOut.log(SiteConstant.ERROR_LOG,DB_URL);
      StdOut.log(SiteConstant.ERROR_LOG,USERNAME);
      StdOut.log(SiteConstant.ERROR_LOG,PASSWORD);
      conn = DriverManager.getConnection(DB_URL, USERNAME, PASSWORD);
      connections.put(threadCurrent, conn);
    }
    return conn;
  }
}

And the ConnectionThread might be:

public class ConnectionThread extends Thread {
  private boolean run;

  protected ConnectionThread() {
    super();
    run = true;
  }

  public void run() {
    while(run) {
      ConnectionPool.checkConnections();
      try {
        sleep(300); // sleep for 0.3 seconds
      } catch (InterruptedException ie) {
        run = false;
      }
    }
  }

  public void kill() {
    run = false;
  }
}

This works great for me with Struts.  If you have any critiques, I
would be the first to be grateful for improvements.

Jack

-- 
------------------------------

"You can lead a horse to water but you cannot make it float on its back."

~Dakota Jack~

"You can't wake a person who is pretending to be asleep."

~Native Proverb~

"Each man is good in His sight. It is not necessary for eagles to be
crows.  We are poor . . . but we are free."

~Hunkesni (Sitting Bull), Hunkpapa Sioux~

-----------------------------------------------

"This message may contain confidential and/or privileged information.
If you are not the addressee or authorized to receive this for the
addressee, you must not use, copy, disclose, or take any action based
on this message or any information herein. If you have received this
message in error, please advise the sender immediately by reply e-mail
and delete this message. Thank you for your cooperation."

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to