Main Page | Packages | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages

AbstractConnectionManager.java

00001 /**
00002  * C-JDBC: Clustered JDBC.
00003  * Copyright (C) 2002-2004 French National Institute For Research In Computer
00004  * Science And Control (INRIA).
00005  * Contact: c-jdbc@objectweb.org
00006  * 
00007  * This library is free software; you can redistribute it and/or modify it
00008  * under the terms of the GNU Lesser General Public License as published by the
00009  * Free Software Foundation; either version 2.1 of the License, or any later
00010  * version.
00011  * 
00012  * This library is distributed in the hope that it will be useful, but WITHOUT
00013  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
00015  * for more details.
00016  * 
00017  * You should have received a copy of the GNU Lesser General Public License
00018  * along with this library; if not, write to the Free Software Foundation,
00019  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00020  *
00021  * Initial developer(s): Emmanuel Cecchet.
00022  * Contributor(s): Mathieu Peltier.
00023  */
00024 
00025 package org.objectweb.cjdbc.controller.connection;
00026 
00027 import java.io.Serializable;
00028 import java.sql.Connection;
00029 import java.sql.SQLException;
00030 import java.util.Hashtable;
00031 
00032 import org.objectweb.cjdbc.common.exceptions.UnreachableBackendException;
00033 import org.objectweb.cjdbc.common.i18n.Translate;
00034 import org.objectweb.cjdbc.common.log.Trace;
00035 import org.objectweb.cjdbc.common.xml.DatabasesXmlTags;
00036 import org.objectweb.cjdbc.common.xml.XmlComponent;
00037 
00038 /**
00039  * A <code>ConnectionManager</code> object is responsible to talk directly
00040  * with a database backend.
00041  * 
00042  * @author <a href="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
00043  * @author <a href="mailto:Mathieu.Peltier@inrialpes.fr">Mathieu Peltier </a>
00044  * @author <a href="mailto:Nicolas.Modrzyk@inrialpes.fr">Nicolas Modrzyk </a>
00045  * @version 1.0
00046  */
00047 public abstract class AbstractConnectionManager
00048     implements
00049       Serializable,
00050       XmlComponent,
00051       Cloneable
00052 {
00053   /*
00054    * How the code is organized ? 1. Member variables 2. Connection handling 3.
00055    * Getter/Setter (possibly in alphabetical order)
00056    */
00057 
00058   /** Logger instance. */
00059   static Trace                logger = Trace
00060                                          .getLogger("org.objectweb.cjdbc.controller.connection");
00061 
00062   /** URL of the <code>DatabaseBackend</code> owning this connection manager. */
00063   protected String            backendUrl;
00064 
00065   /**
00066    * Name of the <code>DatabaseBackend</code> owning this connection manager.
00067    */
00068   protected String            backendName;
00069 
00070   /** Backend connection login to be used by this connection manager. */
00071   protected String            rLogin;
00072 
00073   /** Backend connection password to be used by this connection manager. */
00074   protected String            rPassword;
00075 
00076   /** The class name of the driver */
00077   protected String            driverClassName;
00078 
00079   /**
00080    * The path to the driver if null the default directory is used
00081    */
00082   protected String            driverPath;
00083 
00084   /** <code>true</code> if the connection pool has been initialized. */
00085   protected boolean           initialized;
00086 
00087   /** Hastable of connections associated to a transaction. */
00088   private transient Hashtable connectionForTransaction;
00089 
00090   /** Virtual Login to be that use this connection manager */
00091   private String              vLogin;
00092 
00093   /*
00094    * Constructor(s)
00095    */
00096 
00097   /**
00098    * Creates a new <code>AbstractConnectionManager</code> instance: assigns
00099    * login/password and instanciates transaction id/connection mapping.
00100    * 
00101    * @param backendUrl URL of the <code>DatabaseBackend</code> owning this
00102    *          connection manager
00103    * @param backendName name of the <code>DatabaseBackend</code> owning this
00104    *          connection manager
00105    * @param rLogin backend connection login to be used by this connection
00106    *          manager
00107    * @param rPassword backend connection password to be used by this connection
00108    *          manager
00109    * @param driverPath path for driver
00110    * @param driverClassName class name for driver
00111    */
00112   public AbstractConnectionManager(String backendUrl, String backendName,
00113       String rLogin, String rPassword, String driverPath, String driverClassName)
00114   {
00115     if (backendUrl == null)
00116       throw new IllegalArgumentException(
00117           "Illegal null database backend URL in AbstractConnectionManager constructor");
00118 
00119     if (backendName == null)
00120       throw new IllegalArgumentException(
00121           "Illegal null database backend name in AbstractConnectionManager constructor");
00122 
00123     if (rLogin == null)
00124       throw new IllegalArgumentException(
00125           "Illegal null database backend login in AbstractConnectionManager constructor");
00126 
00127     if (rPassword == null)
00128       throw new IllegalArgumentException(
00129           "Illegal null database backend password in AbstractConnectionManager constructor");
00130 
00131     if (driverPath != null)
00132     {
00133       if (driverClassName == null)
00134       {
00135         throw new IllegalArgumentException(
00136             "Illegal null database backend driverClassName in AbstractConnectionManager constructor");
00137       }
00138     }
00139     this.backendUrl = backendUrl;
00140     this.backendName = backendName;
00141     this.rLogin = rLogin;
00142     this.rPassword = rPassword;
00143     this.driverPath = driverPath;
00144     this.driverClassName = driverClassName;
00145     connectionForTransaction = new Hashtable();
00146 
00147   }
00148 
00149   /**
00150    * Copy this connection manager and replace the name of the backend and its
00151    * url Every other parameter is the same
00152    * 
00153    * @param url the url to the backend associated to this ConnectionManager
00154    * @param name the name of the backend
00155    * @return <code>AbstractConnectionManager</code>
00156    * @throws Exception if clone fails
00157    */
00158   public AbstractConnectionManager copy(String url, String name)
00159       throws Exception
00160   {
00161     AbstractConnectionManager connectionManager = (AbstractConnectionManager) this
00162         .clone();
00163     connectionManager.backendName = name;
00164     connectionManager.backendUrl = url;
00165     return connectionManager;
00166   }
00167 
00168   /*
00169    * Connection handling
00170    */
00171 
00172   /**
00173    * Initializes the connection(s) to the database. The caller must ensure that
00174    * the driver has already been loaded else an exception will be thrown.
00175    * 
00176    * @exception SQLException if an error occurs.
00177    */
00178   public abstract void initializeConnections() throws SQLException;
00179 
00180   /**
00181    * Releases all the connections to the database.
00182    * 
00183    * @exception SQLException if an error occurs.
00184    */
00185   public abstract void finalizeConnections() throws SQLException;
00186 
00187   /**
00188    * Get a connection from DriverManager.
00189    * 
00190    * @return a new connection or null if Driver.getConnection() failed.
00191    * @see DriverManager#getConnection(String, String, String, String, String)
00192    */
00193   public Connection getConnectionFromDriver()
00194 
00195   {
00196     try
00197     {
00198       return DriverManager.getConnection(backendUrl, rLogin, rPassword,
00199           driverPath, driverClassName);
00200     }
00201     catch (SQLException ignore)
00202     {
00203       if (logger.isDebugEnabled())
00204       {
00205         logger.debug("failed to get connection for driver ", ignore);
00206       }
00207       return null;
00208     }
00209   }
00210 
00211   /**
00212    * Gets a connection from the pool (round-robin).
00213    * 
00214    * @return a <code>Connection</code> or <code>null</code> if no connection
00215    *         is available or if the connection has not been initialized.
00216    * @throws UnreachableBackendException if the backend must be disabled
00217    */
00218   public abstract Connection getConnection() throws UnreachableBackendException;
00219 
00220   /**
00221    * Gets a new connection for a transaction. This function calls
00222    * {@link #getConnection()}to get the connection and store the mapping
00223    * between the connection and the transaction id.
00224    * 
00225    * @param transactionId the transaction id.
00226    * @return a <code>Connection</code> or <code>null</code> if no connection
00227    *         is available .
00228    * @throws UnreachableBackendException if the backend must be disabled
00229    * @see #getConnection()
00230    */
00231   public Connection getConnection(long transactionId)
00232       throws UnreachableBackendException
00233   {
00234     Long lTid = new Long(transactionId);
00235     Connection c = getConnection();
00236     if (c != null)
00237     {
00238       if (connectionForTransaction.put(lTid, c) != null)
00239       {
00240         logger
00241             .error("A new connection for transaction "
00242                 + lTid
00243                 + " has been opened but there was a remaining connection for this transaction that has not been closed.");
00244       }
00245     }
00246     return c;
00247   }
00248 
00249   /**
00250    * Retrieves a connection used for a transaction. This connection must have
00251    * been allocated by calling {@link #getConnection(long)}.
00252    * 
00253    * @param transactionId the transaction id.
00254    * @return a <code>Connection</code> or <code>null</code> if no connection
00255    *         has been found for this transaction id.
00256    * @see #getConnection(long)
00257    */
00258   public Connection retrieveConnection(long transactionId)
00259   {
00260     Long id = new Long(transactionId);
00261     synchronized (connectionForTransaction)
00262     {
00263       return (Connection) connectionForTransaction.get(id);
00264     }
00265   }
00266 
00267   /**
00268    * Releases a connection.
00269    * 
00270    * @param connection the connection to release.
00271    */
00272   public abstract void releaseConnection(Connection connection);
00273 
00274   /**
00275    * Releases a connection used for a transaction. The corresponding connection
00276    * is released by calling {@link #releaseConnection(Connection)}.
00277    * 
00278    * @param transactionId the transaction id.
00279    * @see #releaseConnection(Connection)
00280    */
00281   public void releaseConnection(long transactionId)
00282   {
00283     Connection c = (Connection) connectionForTransaction.remove(new Long(
00284         transactionId));
00285 
00286     if (c == null)
00287       logger.error(Translate.get("connection.transaction.unknown",
00288           transactionId));
00289     else
00290       releaseConnection(c);
00291   }
00292 
00293   /**
00294    * Delete a connection that is no more valid.
00295    * 
00296    * @param connection the connection to delete.
00297    */
00298   public abstract void deleteConnection(Connection connection);
00299 
00300   /**
00301    * Delete a bad connection that was used for a transaction. The corresponding
00302    * connection is deleted by calling {@link #deleteConnection(Connection)}.
00303    * 
00304    * @param transactionId the transaction id.
00305    * @see #releaseConnection(Connection)
00306    */
00307   public void deleteConnection(long transactionId)
00308   {
00309     Connection c = (Connection) connectionForTransaction.remove(new Long(
00310         transactionId));
00311 
00312     if (c == null)
00313       logger.error(Translate.get("connection.transaction.unknown",
00314           transactionId));
00315     else
00316       deleteConnection(c);
00317   }
00318 
00319   /**
00320    * Tests if the connections have been initialized.
00321    * 
00322    * @return <code>true</code> if the connections have been initialized.
00323    */
00324   public boolean isInitialized()
00325   {
00326     return initialized;
00327   }
00328 
00329   /*
00330    * Getter/setter methods
00331    */
00332 
00333   /**
00334    * Returns the login used by this connection manager.
00335    * 
00336    * @return a <code>String</code> value.
00337    */
00338   public String getLogin()
00339   {
00340     return rLogin;
00341   }
00342 
00343   /**
00344    * Sets the login to be used by this connection manager.
00345    * 
00346    * @param rLogin the login to set.
00347    */
00348   public void setLogin(String rLogin)
00349   {
00350     this.rLogin = rLogin;
00351   }
00352 
00353   /**
00354    * Returns the password used by this connection manager.
00355    * 
00356    * @return a <code>String</code> value.
00357    */
00358   public String getPassword()
00359   {
00360     return rPassword;
00361   }
00362 
00363   /**
00364    * Sets the password to be used by this connection manager.
00365    * 
00366    * @param rPassword the password to set.
00367    */
00368   public void setPassword(String rPassword)
00369   {
00370     this.rPassword = rPassword;
00371   }
00372 
00373   /*
00374    * Debug/monitoring information
00375    */
00376 
00377   /**
00378    * Gets xml formatted information on this connection manager
00379    * 
00380    * @return xml formatted string that conforms to c-jdbc.dtd
00381    */
00382   public abstract String getXmlImpl();
00383 
00384   /**
00385    * @see org.objectweb.cjdbc.common.xml.XmlComponent#getXml()
00386    */
00387   public String getXml()
00388   {
00389     StringBuffer info = new StringBuffer();
00390     info.append("<" + DatabasesXmlTags.ELT_ConnectionManager + " "
00391         + DatabasesXmlTags.ATT_vLogin + "=\"" + vLogin + "\"  " + ""
00392         + DatabasesXmlTags.ATT_rLogin + "=\"" + rLogin + "\"  " + ""
00393         + DatabasesXmlTags.ATT_rPassword + "=\"" + rPassword + "\"  " + ">");
00394     info.append(this.getXmlImpl());
00395     info.append("</" + DatabasesXmlTags.ELT_ConnectionManager + ">");
00396     return info.toString();
00397   }
00398 
00399   /**
00400    * Ensures that the connections are closed when the object is garbage
00401    * collected.
00402    * 
00403    * @exception Throwable if an error occurs.
00404    */
00405   protected void finalize() throws Throwable
00406   {
00407     if (isInitialized())
00408       finalizeConnections();
00409     super.finalize();
00410   }
00411 
00412   /**
00413    * @return Returns the vLogin.
00414    */
00415   public String getVLogin()
00416   {
00417     return vLogin;
00418   }
00419 
00420   /**
00421    * @param login The vLogin to set.
00422    */
00423   public void setVLogin(String login)
00424   {
00425     vLogin = login;
00426   }
00427 
00428   /**
00429    * Get the current number of connections open for this connection manager.
00430    * 
00431    * @return the current number of open connections
00432    */
00433   public abstract int getCurrentNumberOfConnections();
00434 
00435   /**
00436    * Returns the driverClassName value.
00437    * 
00438    * @return Returns the driverClassName.
00439    */
00440   public String getDriverClassName()
00441   {
00442     return driverClassName;
00443   }
00444 
00445   /**
00446    * Sets the driverClassName value.
00447    * 
00448    * @param driverClassName The driverClassName to set.
00449    */
00450   public void setDriverClassName(String driverClassName)
00451   {
00452     this.driverClassName = driverClassName;
00453   }
00454 
00455   /**
00456    * Returns the driverPath value.
00457    * 
00458    * @return Returns the driverPath.
00459    */
00460   public String getDriverPath()
00461   {
00462     return driverPath;
00463   }
00464 
00465   /**
00466    * Sets the driverPath value.
00467    * 
00468    * @param driverPath The driverPath to set.
00469    */
00470   public void setDriverPath(String driverPath)
00471   {
00472     this.driverPath = driverPath;
00473   }
00474 
00475   protected abstract Object clone() throws CloneNotSupportedException;
00476 }

Generated on Mon Apr 11 22:01:28 2005 for C-JDBC by  doxygen 1.3.9.1