1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
142 clazz = Class.forName(driverClassName);
143 } catch (ClassNotFoundException cnfe1) {
144
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
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 }