View Javadoc

1   /* ==============================================================================
2    *   JDBCAdmin, data management software.
3    *   Copyright (C) 2005  Norsys S.A
4    *
5    *   This library is free software; you can redistribute it and/or
6    *   modify it under the terms of the GNU Lesser General Public
7    *   License as published by the Free Software Foundation; either
8    *   version 2.1 of the License, or (at your option) any later version.
9    *
10   *   This library is distributed in the hope that it will be useful,
11   *   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   *   Lesser General Public License for more details.
14   *
15   *   You should have received a copy of the GNU Lesser General Public
16   *   License along with this library; if not, write to the Free Software
17   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18   * ==============================================================================
19   */
20  package jdbcadmin.core.tools;
21  
22  import java.io.File;
23  import java.io.FileOutputStream;
24  import java.io.IOException;
25  import java.net.URL;
26  import java.net.URLClassLoader;
27  import java.sql.Connection;
28  import java.sql.DatabaseMetaData;
29  import java.sql.Driver;
30  import java.sql.ResultSet;
31  import java.sql.SQLException;
32  import java.util.HashMap;
33  import java.util.Map;
34  import java.util.Properties;
35  
36  import javax.naming.Context;
37  import javax.naming.InitialContext;
38  import javax.naming.NameNotFoundException;
39  import javax.naming.NamingException;
40  import javax.sql.DataSource;
41  
42  import jdbcadmin.core.data.ConnectionInfo;
43  import jdbcadmin.core.exceptions.TechnicalException;
44  
45  import org.apache.commons.logging.Log;
46  import org.apache.commons.logging.LogFactory;
47  
48  /***
49   * JDBC connections factory
50   * @author Thomas Recloux (trecloux@norsys.fr)
51   */
52  public final class ConnectionFactory {
53  
54      /***
55       * Configuration map
56       */
57      private static Map classes = new HashMap();
58  
59      /*** Logger */
60      private static Log logger = LogFactory.getLog(ConnectionFactory.class);
61  
62      /*** Private constructor */
63      private ConnectionFactory () {
64      }
65  
66      /***
67       * Init a JDBC connection using the specified connection informations<br>
68       * If the <code>dataSourceJndiName</code> property is specified, it will try to retrieve the
69       * connection from the datasource.<br>
70       * Else, the connection la connection is created using the classics informations (driver, url, user, password)
71       * @param aConInfo connection parameters
72       * @return the connection
73       * @throws TechnicalException Connection error
74       */
75      public static Connection getCnx(ConnectionInfo aConInfo) throws TechnicalException {
76          Connection cnx;
77          if (aConInfo.getDataSourceJndiName() != null
78                  && !"".equals(aConInfo.getDataSourceJndiName())) {
79              cnx = getDataSourceCnx (aConInfo);
80          } else {
81              cnx = getSimpleCnx(aConInfo);
82          }
83          logCnx(cnx);
84          return cnx;
85      }
86  
87      /***
88       * Retrieve a simple connection (driver, url, user, pasword)
89       * @param aConInfo connection parameters
90       * @return the conenction
91       * @throws TechnicalException Connection error
92       */
93      private static Connection getSimpleCnx(ConnectionInfo aConInfo) throws TechnicalException {
94          try {
95              Driver d = loadDriver(aConInfo);
96              Properties props = new Properties();
97              props.put("user", aConInfo.getUserName());
98              props.put("password", aConInfo.getUserPassword());
99              return d.connect(aConInfo.getUrl(), props);
100         } catch (SQLException sqle) {
101             throw new TechnicalException("SQL Error during the db connection", sqle);
102         }
103     }
104 
105     /***
106      * Retrieve a connection using a DataSource
107      * @param aConInfo connection parameters
108      * @return the conenction
109      * @throws TechnicalException Connection error
110      */
111     private static Connection getDataSourceCnx(ConnectionInfo aConInfo) throws TechnicalException {
112         try {
113             Context ctx = new InitialContext();
114             Object o = ctx.lookup(aConInfo.getDataSourceJndiName());
115             DataSource ds = (DataSource) o;
116             return ds.getConnection();
117         } catch (NameNotFoundException nfe) {
118             throw new TechnicalException("The name " + aConInfo.getDataSourceJndiName()
119                     + " has not been found in the JNDI directory", nfe);
120         } catch (NamingException ne) {
121             throw new TechnicalException("Error searching for the datasource in the JNDI directory", ne);
122         } catch (ClassCastException cce) {
123             throw new TechnicalException("Error, the object found in the JNDI directory is not a DataSource", cce);
124         } catch (SQLException sqle) {
125             throw new TechnicalException("SQL Error connecting using the DataSource", sqle);
126         }
127     }
128 
129     /***
130      * Loads the JDBC Driver and instanciate it.<br>
131      * We try to load it from the classic class loader, if it's not found, we
132      * try to load it from the jar file specified in the connection informations.
133      * @param aConInfo connections informations
134      * @throws TechnicalException Technical error
135      * @return the driver
136      */
137     private static Driver loadDriver(ConnectionInfo aConInfo) throws TechnicalException {
138         String driverClassName = aConInfo.getDriverName();
139         Class clazz = null;
140         try {
141             // from the normal class loader
142             clazz = Class.forName(driverClassName);
143         } catch (ClassNotFoundException cnfe1) {
144             // looking in the loaded classes
145             clazz = (Class) classes.get(driverClassName);
146             if (clazz == null) {
147                 if (aConInfo.getDriverJarData() != null
148                         && aConInfo.getDriverJarData().length > 0) {
149                     URL jarUrl = createDriverJarFile(aConInfo);
150                     URLClassLoader jarLoader = new URLClassLoader (new URL [] {jarUrl});
151                     try {
152                         clazz = jarLoader.loadClass(driverClassName);
153                         // keeeping a reference on the class
154                         classes.put(driverClassName, clazz);
155                     } catch (ClassNotFoundException cnfe2) {
156                         throw new TechnicalException("Error loading the JDBC Driver", cnfe2);
157                     }
158                 } else {
159                     throw new TechnicalException("Error loading the JDBC Driver", cnfe1);
160                 }
161             }
162         }
163         try {
164             return (Driver) clazz.newInstance();
165         } catch (InstantiationException ie) {
166             throw new TechnicalException("Error instanciating the JDBC driver", ie);
167         } catch (IllegalAccessException iae) {
168             throw new TechnicalException("Error instanciating the JDBC driver", iae);
169         }
170     }
171 
172     /***
173      * Create a temporary file containing the JDBC jar file.
174      * @param aConInfos connection informations
175      * @return URL of the created file
176      * @throws TechnicalException Technical error
177      */
178     private static URL createDriverJarFile (ConnectionInfo aConInfos) throws TechnicalException {
179         try {
180             File jar = File.createTempFile("driver", ".jar");
181             jar.deleteOnExit();
182             FileOutputStream fout = new FileOutputStream (jar);
183             fout.write(aConInfos.getDriverJarData());
184             fout.close();
185             return jar.toURL();
186         } catch (IOException ioe) {
187             throw new TechnicalException("Error saving the jar file containing the JDBC Driver", ioe);
188         }
189     }
190 
191     /***
192      * Log connection
193      * @param aCnx The cnx to log
194      */
195     private static void logCnx(Connection aCnx) {
196         if (logger.isInfoEnabled()) {
197             try {
198                 DatabaseMetaData metas = aCnx.getMetaData();
199                 logger.info("Connection established : " + metas.getDriverName() + " / " + metas.getDriverVersion());
200                 logger.info("\t Supports scrolling : " + metas.supportsResultSetType(ResultSet.TYPE_SCROLL_SENSITIVE));
201             } catch (SQLException sqle) {
202                 logger.warn("Connexion established : Error grabing the driver informations");
203             }
204         }
205     }
206 }