<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]