1 /*
2 * PROJECT : DAR Runtime and Tools
3 * COPYRIGHT : Copyright (C) 1999-2004 tim.stephenson@enableit.org
4 * LICENSE : GNU LESSER GENERAL PUBLIC LICENSE
5 * Version 2.1, February 1999
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21 package org.enableit.db;
22
23
24 // Java Imports
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.sql.Connection;
28 import java.sql.DriverManager;
29 import java.sql.SQLException;
30 import java.util.Enumeration;
31 import java.util.HashMap;
32 import java.util.HashSet;
33 import java.util.Properties;
34 import java.util.Set;
35
36 import org.apache.log4j.Category;
37 import org.enableit.db.beans.Provider;
38 import org.enableit.db.beans.ProviderExt;
39
40
41 /***
42 * General class intended to hide the process of obtaining
43 * database connections to any database.
44 *
45 * <p>Over time this class has evolved to fulfil different goals, but is
46 * maintained for backwards compatibility. There are two principle uses:
47 * <ol>
48 * <li>Connection to a single database when no runtime configuration
49 * mechanism (e.g. JNDI / user login form) exists. </li>
50 * <li>Connection to one or more databases whether or not runtime
51 * configuration exists (If such a mechanism exists you are advised
52 * to use it).</li>
53 * </ol>
54 * It is important not to mix these two usages as unexpected results may ensue.
55 * </p>
56 *
57 * <p>In the first case, the connection properties such as server name,
58 * username/password etc.
59 * are all stored in a file named db.properties in the package level
60 * directory matching this class (i.e. <code>org.enableit.db</code>). These
61 * may be overridden by the use of the <code>setProperty</code> method.</p>
62 *
63 * <p>In the second case this class is simply for encapsulation. In other words
64 * it offers a way to hide the actual mechanism
65 * of finding the database connection to the higher level (application) logic.
66 * This allows a J2EE application to use JNDI to obtain connections and a
67 * thick-client application configured by a logon screen to both employ common
68 * logic whilst this factory
69 * takes care of how to find connections at runtime.</p>
70 *
71 * <p>This class has been tested with the following database drivers:
72 * <ul>
73 * <li>ASE/ASA (Sybase jConnect 5.x)</li>
74 * <li>MySQL (MM.MySQL driver)</li>
75 * </ul>
76 * </p>
77 *
78 * @version v1.0
79 *
80 * @author __AUTHOR__
81 * @deprecated This is just the legacy code,
82 * things of ongoing use are in the new ancestor.
83 */
84 public class ConnectionFactory extends ConnFactory {
85 /*
86 * Properties
87 */
88
89 /***
90 * Holds the <code>Provider</code> instances that have been configured as
91 * data sources.
92 * @see org.enableit.db.beans.Provider
93 */
94 private static HashMap connConfigs = new HashMap();
95
96 /***
97 * The Log4J <code>Category</code> doing the logging.
98 * Same <code>Category</code> is used throughout the package.
99 */
100 protected static Category logger = Category.getInstance(ConnectionFactory.class);
101
102 /***
103 * Reference to the singleton instance
104 *
105 * NB the singleton status is not enforced via a synchronise statement
106 */
107 private static ConnectionFactory me;
108
109 /***
110 * The current database properties to make connections with
111 */
112 private static Properties props = new Properties();
113
114 /***
115 * Information on the exact CVS version accessible after compilation
116 */
117 public static final String ABOUT = "$Revision: 1.11 $";
118
119 /*
120 * Constructors
121 */
122
123 /***
124 * Default Constructor
125 */
126 private ConnectionFactory() {
127 logger.info("METHOD_ENTRY constructor");
128
129 // Need to initialise with something, use props file in case no JNDI available
130 props = new Properties();
131
132 try {
133 // Check class instance and get source properties
134 InputStream is = this.getClass().getResourceAsStream("db.properties");
135
136 props.load(is);
137
138 configureFromProps();
139 } catch (NullPointerException e) {
140 logger.warn("Unable to read db connection properties: "
141 + e.getMessage());
142 } catch (IOException e) {
143 logger.warn("Unable to read db connection properties: "
144 + e.getMessage());
145
146 // throw new DBException("ERROR: Getting db connection properties: " + e.getMessage()) ;
147 }
148
149 logger.info("METHOD_EXIT constructor");
150 }
151
152 /*
153 * Methods
154 */
155
156 /***
157 * Factory method to obtain the connection factory itself.
158 * @return The <code>ConnectionFactory</code> singleton.
159 */
160 public static synchronized ConnectionFactory getInstance() {
161 logger.info("METHOD_ENTRY getInstance");
162
163 if (me == null) {
164 me = new ConnectionFactory();
165 }
166
167 logger.info("METHOD_EXIT getInstance");
168
169 return me;
170 }
171
172 /***
173 * Set a connection property dynamically.
174 * <p>This will override defaults changing the behaviour of the
175 * <code>ConnectionFactory</code> singleton.</p>
176 */
177 public static void setProperty(String key, String value) {
178 logger.info("METHOD_ENTRY setProperty");
179
180 // Ensure we are initialised
181 getInstance();
182 props.setProperty(key, value);
183 }
184
185 /***
186 * Interpretes the props to create a Provider for each distinct data source
187 * configuration.
188 * throws DBException If the properties are invalid in some way
189 */
190 private void configureFromProps() {
191 logger.info("METHOD_ENTRY configureFromProps");
192
193 try {
194 // Find all config names, use USER to distinguish
195 for (Enumeration enum = props.propertyNames();
196 enum.hasMoreElements();) {
197 String name = (String) enum.nextElement();
198
199 if (name.indexOf("USER") > -1) {
200 String s = null;
201 int i = name.indexOf(".USER");
202
203 if (i > -1) {
204 s = name.substring(0, i);
205
206 ProviderExt prov = new ProviderExt();
207
208 prov.setConnectionProperties(props.getProperty(s
209 + ".DRIVER"), props.getProperty(s + ".URL"),
210 props.getProperty(s + ".USER"),
211 props.getProperty(s + ".PASSWORD"),
212 props.getProperty(s + ".SCHEMA"));
213 System.out.println("Found db config named: " + s + ", "
214 + ProviderExt.toString(prov));
215 connConfigs.put(s, prov);
216 } else {
217 s = "default";
218
219 // Clearly there can be only one of these!
220 ProviderExt prov = new ProviderExt();
221
222 prov.setConnectionProperties(props.getProperty("DRIVER"),
223 props.getProperty("URL"),
224 props.getProperty("USER"),
225 props.getProperty("PASSWORD"),
226 props.getProperty("SCHEMA"));
227 System.out.println("Found db config named: " + s + ", "
228 + ProviderExt.toString(prov));
229 connConfigs.put(s, prov);
230 }
231 }
232 }
233 } catch (Exception e) {
234 logger.warn(e.getMessage(), e);
235
236 //throw new DBException(e.getMessage());
237 }
238
239 logger.info("METHOD_EXIT configureFromProps");
240 }
241
242 /***
243 * Returns the names of configured database connections.
244 *
245 * <p>These are names that may be used successfully with
246 * <code> </code>.
247 *
248 * @return <code>java.util.Set</code> of connection names (of type
249 * <code>String</code>).
250 * @see #getProvider
251 */
252 public Set getConnectionNames() {
253 logger.info("METHOD_ENTRY getConnectionNames");
254
255 // TODO: Add JNDI-bound names
256 Set names = null;
257
258 if (connConfigs == null) {
259 names = new HashSet();
260 } else {
261 names = connConfigs.keySet();
262 }
263
264 logger.info("METHOD_EXIT getConnectionNames, returning =" + names);
265
266 return names;
267 }
268
269 /***
270 * Obtain connection details for the named configuration.
271 *
272 * @param name configuration name.
273 * @return Provider holding the connection details
274 * @throws DBException If the named configuration is not found.
275 * @see #getConnectionNames
276 */
277 public Provider getProvider(String name)
278 throws DBException {
279 logger.info("METHOD_ENTRY getProvider name=" + name);
280
281 Provider provider = null;
282
283 logger.debug("Configured connections: " + connConfigs);
284
285 if ((connConfigs == null) || connConfigs.isEmpty()
286 || !connConfigs.containsKey(name)) {
287 throw new DBException("No connection configuration exists "
288 + "with name: " + name);
289 } else {
290 provider = (Provider) connConfigs.get(name);
291 }
292
293 logger.info("METHOD_EXIT getProvider");
294
295 return provider;
296 }
297
298 /***
299 * Returns a connection to the database identified by the
300 * class's resource properties.
301 * <p>This is a very simplistic configuration option for applications
302 * that do not have any JNDI or user-maintained configuration options.
303 * It is not recommended.</p>
304 *
305 * @return Connection
306 *
307 * @throws DBException
308 * in the event of a problem creating the connection
309 */
310 public static Connection getConnection()
311 throws DBException {
312 logger.info("METHOD_ENTRY getConnection");
313
314 Connection conn = null;
315
316 try {
317 conn = getInstance().getConnection(props);
318 } catch (DBException dbe) {
319 // simply rethrow
320 throw dbe;
321 } catch (Exception e) {
322 logger.error("ERROR: " + e.getMessage());
323
324 throw new DBException("ERROR: " + e.getMessage());
325 }
326
327 if (conn == null) {
328 logger.error("ERROR: Unable to create connection");
329 throw new DBException("ERROR: Unable to create connection: ");
330 }
331
332 logger.info("METHOD_EXIT");
333
334 return conn;
335 }
336
337 /***
338 * Returns a connection to the database identified by the
339 * supplied properties.
340 * <p>
341 * Parameters may be empty strings, but may not be null.
342 *
343 * @param driver
344 * @param database
345 * @param server
346 * @param port
347 * @param protocol
348 * @param user
349 * @param password
350 *
351 * @return Connection
352 *
353 * @throws DBException
354 * in the event of a problem creating the connection
355 */
356 public static Connection getConnection(String driver, String database,
357 String server, String port, String protocol, String user,
358 String password)
359 throws DBException {
360 logger.info("METHOD_ENTRY getConnection, driver=" + driver
361 + ", database=" + database + ", server=" + server + ", port="
362 + port + ", protocol=" + protocol + ", user=" + user
363 + ", password=" + password);
364
365 Connection conn = null;
366
367 try {
368 // Check class instance and get propsource properties
369 getInstance();
370
371 props.put("DRIVER", driver);
372 props.put("DATABASE_NAME", database);
373 props.put("SERVER_NAME", server);
374 props.put("PORT", port);
375 props.put("PROTOCOL", protocol);
376 props.put("USER", user);
377 props.put("PASSWORD", password);
378
379 conn = getInstance().getConnection(props);
380 } catch (DBException dbe) {
381 // simply rethrow
382 throw dbe;
383 } catch (Exception e) {
384 logger.error("ERROR: " + e.getMessage());
385
386 throw new DBException("ERROR: " + e.getMessage());
387 }
388
389 if (conn == null) {
390 logger.error("ERROR: Unable to create connection");
391 throw new DBException("ERROR: Unable to create connection: ");
392 }
393
394 logger.info("METHOD_EXIT getConnection");
395
396 return conn;
397 }
398
399 /***
400 * Returns a connection to the database identified by the
401 * supplied properties.
402 * <p>
403 * Parameters may be empty strings, but may not be null.
404 *
405 * @param driver
406 * @param url
407 * @param user
408 * @param password
409 *
410 * @return Connection
411 *
412 * @throws DBException
413 * in the event of a problem creating the connection
414 */
415 public static Connection getConnection(String driver, String url,
416 String user, String password)
417 throws DBException {
418 logger.info("METHOD_ENTRY getConnection, driver=" + driver + ", url="
419 + url + ", user=" + user + ", password=" + password);
420
421 Connection conn = null;
422
423 try {
424 // Check class instance and set source properties
425 getInstance();
426
427 props.put("DRIVER", driver);
428 props.put("URL", url);
429 props.put("USER", user);
430 props.put("PASSWORD", password);
431
432 conn = getInstance().getConnection(props);
433 } catch (DBException dbe) {
434 // simply rethrow
435 throw dbe;
436
437 /*} catch (Exception e) {
438 logger.error(e.getClass().getName() + ":" + e.getMessage(), e) ;
439
440 throw new DBException("ERROR: " + e.getMessage()) ;*/
441 }
442
443 if (conn == null) {
444 logger.error("ERROR: Unable to create connection");
445 throw new DBException("ERROR: Unable to create connection: ");
446 }
447
448 logger.info("METHOD_EXIT getConnection");
449
450 return conn;
451 }
452
453 /***
454 * Returns a connection to the database identified by the
455 * <code>Properties</code> supplied
456 *
457 * @return Connection
458 *
459 * @throws DBException
460 * in the event of a problem creating the connection
461 */
462 private Connection getConnection(Properties props)
463 throws DBException {
464 logger.info("METHOD_ENTRY getConnection, Properties=");
465
466 Connection conn = null;
467
468 try {
469 if (props.getProperty("URL") != null) {
470 conn = getUrlConnection(props);
471 } else {
472 String driver = props.getProperty("DRIVER");
473
474 if (driver.equals("org.gjt.mm.mysql.Driver")) {
475 conn = getMySQLConnection(props);
476 } else if (driver.equals("com.sybase.jdbc2.jdbc.SybDriver")) {
477 conn = getSybConnection(props);
478 } else {
479 logger.error("ERROR: Unsupported driver: " + driver);
480 throw new DBException("ERROR: Unsupported driver: "
481 + driver);
482 }
483 }
484 } catch (SQLException sqle) {
485 logger.error("ERROR: Getting connection: " + sqle.getMessage());
486
487 //TODO: URL Property may be null, should retire properties based connection
488 throw new DBException("Error getting connection to: "
489 + props.getProperty("URL"), sqle);
490 } catch (DBException e) {
491 // simply rethrow
492 throw e;
493 } catch (Exception e) {
494 logger.error("ERROR: " + e.getMessage());
495
496 //e.printStackTrace() ;
497 throw new DBException("ERROR: " + e.getMessage());
498 }
499
500 if (conn == null) {
501 logger.error("ERROR: Unable to create connection");
502 throw new DBException("ERROR: Unable to create connection: ");
503 }
504
505 logger.info("METHOD_EXIT getConnection");
506
507 return conn;
508 }
509
510 private Connection getMySQLConnection(Properties props)
511 throws java.sql.SQLException, DBException {
512 logger.info("METHOD_ENTRY getConnection, Properties=" + props);
513
514 Object driver = getDriver(props.getProperty("DRIVER"));
515
516 String connectionString = "jdbc:";
517
518 connectionString += props.getProperty("PROTOCOL");
519 connectionString += "://";
520 connectionString += props.getProperty("SERVER_NAME");
521 connectionString += "/";
522 connectionString += props.getProperty("DATABASE_NAME");
523 connectionString += "?";
524 connectionString += "user=";
525 connectionString += props.getProperty("USER");
526 connectionString += "&";
527 connectionString += "password=";
528 connectionString += props.getProperty("PASSWORD");
529
530 logger.info("Connection string: " + connectionString);
531
532 Connection conn = DriverManager.getConnection(connectionString);
533
534 logger.info("METHOD_EXIT getMySQLConnection");
535
536 return conn;
537 }
538
539 private Connection getSybConnection(Properties props)
540 throws java.sql.SQLException, DBException {
541 logger.info("METHOD_ENTRY, props=" + props);
542
543 Object driver = getDriver(props.getProperty("DRIVER"));
544
545 String connectionString = null;
546
547 if (props.getProperty("URL") == null) {
548 connectionString = "jdbc:sybase:";
549 connectionString += props.getProperty("PROTOCOL");
550 connectionString += ":";
551 connectionString += props.getProperty("SERVER_NAME");
552 connectionString += ":";
553 connectionString += props.getProperty("PORT");
554 } else {
555 connectionString = props.getProperty("URL");
556 }
557
558 Properties jcprops = new Properties();
559
560 jcprops.put("user", props.getProperty("USER"));
561 jcprops.put("password", props.getProperty("PASSWORD"));
562
563 logger.info("Connection string: " + connectionString);
564
565 Connection conn = DriverManager.getConnection(connectionString, jcprops);
566
567 logger.info("METHOD_EXIT getSybConnection");
568
569 return conn;
570 }
571
572 private Connection getUrlConnection(Properties props)
573 throws java.sql.SQLException, DBException {
574 logger.info("METHOD_ENTRY getUrlConnection, props=" + props);
575
576 registerDriver(props.getProperty("DRIVER"));
577 registerDriverFromUrl(props.getProperty("URL"));
578
579 String connectionString = props.getProperty("URL");
580
581 Properties jcprops = new Properties();
582
583 jcprops.put("user", props.getProperty("USER"));
584 jcprops.put("password", props.getProperty("PASSWORD"));
585
586 logger.info("Connection string: " + connectionString);
587
588 Connection conn = DriverManager.getConnection(connectionString, jcprops);
589
590 logger.info("METHOD_EXIT getUrlConnection");
591
592 return conn;
593 }
594
595 /***
596 * Obtain a JDBC driver class.
597 */
598 protected Object getDriver(String className)
599 throws DBException {
600 logger.info("METHOD_ENTRY: getDriver, className=" + className);
601
602 Object driver = null;
603
604 try {
605 ClassLoader cl = ConnectionFactory.class.getClassLoader();
606
607 driver = cl.loadClass(className).newInstance();
608 } catch (IllegalAccessException iae) {
609 logger.error(iae.getMessage());
610 throw new DBException("Problem getting db connection properties: "
611 + iae.getMessage());
612 } catch (ClassNotFoundException cnfe) {
613 logger.error(cnfe.getMessage());
614
615 logger.debug("Searched classpath:"
616 + System.getProperty("java.class.path"));
617
618 try {
619 logger.warn("Attempting to find driver thru system classloader");
620
621 ClassLoader scl = ClassLoader.getSystemClassLoader();
622
623 driver = scl.loadClass(className).newInstance();
624 } catch (Exception e2) {
625 throw new DBException("Driver class not found: "
626 + e2.getMessage());
627 }
628 } catch (InstantiationException ie) {
629 logger.error(ie.getMessage());
630 throw new DBException("Problem getting db connection properties: "
631 + ie.getMessage());
632 }
633
634 logger.info("METHOD_EXIT: getDriver");
635
636 return driver;
637 }
638 }
This page was automatically generated by Maven