001: package org.apache.torque;
002:
003: /*
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021:
022: import java.sql.Connection;
023: import java.sql.SQLException;
024: import java.util.Collections;
025: import java.util.HashMap;
026: import java.util.Iterator;
027: import java.util.Map;
028:
029: import org.apache.commons.configuration.Configuration;
030: import org.apache.commons.configuration.ConfigurationException;
031: import org.apache.commons.configuration.PropertiesConfiguration;
032: import org.apache.commons.logging.Log;
033: import org.apache.commons.logging.LogFactory;
034: import org.apache.torque.adapter.DB;
035: import org.apache.torque.adapter.DBFactory;
036: import org.apache.torque.dsfactory.DataSourceFactory;
037: import org.apache.torque.manager.AbstractBaseManager;
038: import org.apache.torque.map.DatabaseMap;
039: import org.apache.torque.map.MapBuilder;
040: import org.apache.torque.oid.IDBroker;
041: import org.apache.torque.oid.IDGeneratorFactory;
042:
043: /**
044: * The core of Torque's implementation. Both the classic {@link
045: * org.apache.torque.Torque} static wrapper and the {@link
046: * org.apache.torque.avalon.TorqueComponent} <a
047: * href="http://avalon.apache.org/">Avalon</a> implementation leverage
048: * this class.
049: *
050: * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
051: * @author <a href="mailto:magnus@handtolvur.is">Magn�s ��r Torfason</a>
052: * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
053: * @author <a href="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a>
054: * @author <a href="mailto:mpoeschl@marmot.at">Martin Poeschl</a>
055: * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
056: * @author <a href="mailto:kschrader@karmalab.org">Kurt Schrader</a>
057: * @author <a href="mailto:tv@apache.org">Thomas Vandahl</a>
058: * @version $Id: TorqueInstance.java 571790 2007-09-01 12:40:44Z tv $
059: */
060: public class TorqueInstance {
061: /** Logging */
062: private static Log log = LogFactory.getLog(TorqueInstance.class);
063:
064: /** A constant for <code>default</code>. */
065: private static final String DEFAULT_NAME = "default";
066:
067: /** The db name that is specified as the default in the property file */
068: private String defaultDBName = null;
069:
070: /**
071: * The Map which contains all known databases. All iterations over the map
072: * and other operations where the databaase map needs to stay
073: * in a defined state must be synchronized to this map.
074: */
075: private Map databases = Collections.synchronizedMap(new HashMap());
076:
077: /** A repository of Manager instances. */
078: private Map managers;
079:
080: /** Torque-specific configuration. */
081: private Configuration conf;
082:
083: /** flag to set to true once this class has been initialized */
084: private boolean isInit = false;
085:
086: /**
087: * a flag which indicates whether the DataSourceFactory in the database
088: * named <code>DEFAULT</code> is a reference to another
089: * DataSourceFactory. This is important to know when closing the
090: * DataSourceFactories on shutdown();
091: */
092: private boolean defaultDsfIsReference = false;
093:
094: /**
095: * Store mapbuilder classnames for peers that have been referenced prior
096: * to Torque being initialized. This can happen if torque om/peer objects
097: * are serialized then unserialized prior to Torque being reinitialized.
098: * This condition exists in a normal catalina restart.
099: */
100: private Map mapBuilderCache = null;
101:
102: /**
103: * Creates a new instance with default configuration.
104: *
105: * @see #resetConfiguration()
106: */
107: public TorqueInstance() {
108: resetConfiguration();
109: }
110:
111: /**
112: * Initializes this instance of Torque.
113: *
114: * @see org.apache.stratum.lifecycle.Initializable
115: * @throws TorqueException Any exceptions caught during processing will be
116: * rethrown wrapped into a TorqueException.
117: */
118: private synchronized void initialize() throws TorqueException {
119: log.debug("initialize()");
120:
121: if (isInit) {
122: log.debug("Multiple initializations of Torque attempted");
123: return;
124: }
125:
126: if (conf == null || conf.isEmpty()) {
127: throw new TorqueException(
128: "Torque cannot be initialized without "
129: + "a valid configuration. Please check the log files "
130: + "for further details.");
131: }
132:
133: // Now that we have dealt with processing the log4j properties
134: // that may be contained in the configuration we will make the
135: // configuration consist only of the remain torque specific
136: // properties that are contained in the configuration. First
137: // look for properties that are in the "torque" namespace.
138:
139: Configuration subConf = conf.subset(Torque.TORQUE_KEY);
140: if (subConf == null || subConf.isEmpty()) {
141: String error = ("Invalid configuration. No keys starting with "
142: + Torque.TORQUE_KEY + " found in configuration");
143: log.error(error);
144: throw new TorqueException(error);
145: }
146: setConfiguration(subConf);
147:
148: initDefaultDbName(conf);
149: initAdapters(conf);
150: initDataSourceFactories(conf);
151:
152: // setup manager mappings
153: initManagerMappings(conf);
154:
155: isInit = true;
156:
157: // re-build any MapBuilders that may have gone lost during serialization
158: synchronized (mapBuilderCache) {
159: for (Iterator i = mapBuilderCache.entrySet().iterator(); i
160: .hasNext();) {
161: Map.Entry entry = (Map.Entry) i.next();
162:
163: if (null == entry.getValue()) {
164: try {
165: // create and build the MapBuilder
166: MapBuilder builder = (MapBuilder) Class
167: .forName((String) entry.getKey())
168: .newInstance();
169:
170: if (!builder.isBuilt()) {
171: builder.doBuild();
172: }
173:
174: entry.setValue(builder);
175: } catch (Exception e) {
176: throw new TorqueException(e);
177: }
178: }
179: }
180: }
181: }
182:
183: /**
184: * Initializes the name of the default database and
185: * associates the database with the name <code>DEFAULT_NAME</code>
186: * to the default database.
187: *
188: * @param conf the configuration representing the torque section.
189: * of the properties file.
190: * @throws TorqueException if the appropriate key is not set.
191: */
192: private void initDefaultDbName(Configuration conf)
193: throws TorqueException {
194: // Determine default database name.
195: defaultDBName = conf.getString(Torque.DATABASE_KEY + "."
196: + Torque.DEFAULT_KEY);
197: if (defaultDBName == null) {
198: String error = "Invalid configuration: Key "
199: + Torque.TORQUE_KEY + "." + Torque.DATABASE_KEY
200: + "." + Torque.DEFAULT_KEY + " not set";
201: log.error(error);
202: throw new TorqueException(error);
203: }
204: }
205:
206: /**
207: * Reads the adapter settings from the configuration and
208: * assigns the appropriate database adapters and Id Generators
209: * to the databases.
210: *
211: * @param conf the Configuration representing the torque section of the
212: * properties file
213: * @throws TorqueException Any exceptions caught during processing will be
214: * rethrown wrapped into a TorqueException.
215: */
216: private void initAdapters(Configuration conf)
217: throws TorqueException {
218: log.debug("initAdapters(" + conf + ")");
219:
220: Configuration c = conf.subset(Torque.DATABASE_KEY);
221: if (c == null || c.isEmpty()) {
222: String error = "Invalid configuration : "
223: + "No keys starting with " + Torque.TORQUE_KEY
224: + "." + Torque.DATABASE_KEY
225: + " found in configuration";
226: log.error(error);
227: throw new TorqueException(error);
228: }
229:
230: try {
231: for (Iterator it = c.getKeys(); it.hasNext();) {
232: String key = (String) it.next();
233: if (key.endsWith(DB.ADAPTER_KEY)
234: || key.endsWith(DB.DRIVER_KEY)) {
235: String adapter = c.getString(key);
236: String handle = key.substring(0, key.indexOf('.'));
237:
238: DB db;
239:
240: db = DBFactory.create(adapter);
241:
242: // Not supported, try manually defined adapter class
243: if (db == null) {
244: String adapterClassName = c.getString(key + "."
245: + adapter + ".className", null);
246: db = DBFactory
247: .create(adapter, adapterClassName);
248: }
249:
250: Database database = getOrCreateDatabase(handle);
251:
252: // register the adapter for this name
253: database.setAdapter(db);
254: log.debug("Adding " + adapter + " -> " + handle
255: + " as Adapter");
256:
257: // add Id generators
258:
259: // first make sure that the dtabaseMap exists for the name
260: // as the idGenerators are still stored in the database map
261: // TODO: change when the idGenerators are stored in the
262: // database
263: getDatabaseMap(handle);
264: for (int i = 0; i < IDGeneratorFactory.ID_GENERATOR_METHODS.length; i++) {
265: database
266: .addIdGenerator(
267: IDGeneratorFactory.ID_GENERATOR_METHODS[i],
268: IDGeneratorFactory.create(db,
269: handle));
270: }
271: }
272: }
273: } catch (InstantiationException e) {
274: log.error("Error creating a database adapter instance", e);
275: throw new TorqueException(e);
276: } catch (TorqueException e) {
277: log.error("Error reading configuration seeking database "
278: + "adapters", e);
279: throw new TorqueException(e);
280: }
281:
282: // check that at least the default database has got an adapter.
283: Database defaultDatabase = (Database) databases.get(Torque
284: .getDefaultDB());
285: if (defaultDatabase == null
286: || defaultDatabase.getAdapter() == null) {
287: String error = "Invalid configuration : "
288: + "No adapter definition found for default DB "
289: + "An adapter must be defined under "
290: + Torque.TORQUE_KEY + "." + Torque.DATABASE_KEY
291: + "." + Torque.getDefaultDB() + "."
292: + DB.ADAPTER_KEY;
293: log.error(error);
294: throw new TorqueException(error);
295: }
296: }
297:
298: /**
299: * Reads the settings for the DataSourceFactories from the configuration
300: * and creates and/or cinfigures the DataSourceFactories for the databases.
301: * If no DataSorceFactory is assigned to the database with the name
302: * <code>DEFAULT_NAME</code>, a reference to the DataSourceFactory
303: * of the default daztabase is made from the database with the name
304: * <code>DEFAULT_NAME</code>.
305: *
306: * @param conf the Configuration representing the properties file
307: * @throws TorqueException Any exceptions caught during processing will be
308: * rethrown wrapped into a TorqueException.
309: */
310: private void initDataSourceFactories(Configuration conf)
311: throws TorqueException {
312: log.debug("initDataSourceFactories(" + conf + ")");
313:
314: Configuration c = conf.subset(DataSourceFactory.DSFACTORY_KEY);
315: if (c == null || c.isEmpty()) {
316: String error = "Invalid configuration: "
317: + "No keys starting with " + Torque.TORQUE_KEY
318: + "." + DataSourceFactory.DSFACTORY_KEY
319: + " found in configuration";
320: log.error(error);
321: throw new TorqueException(error);
322: }
323:
324: try {
325: for (Iterator it = c.getKeys(); it.hasNext();) {
326: String key = (String) it.next();
327: if (key.endsWith(DataSourceFactory.FACTORY_KEY)) {
328: String classname = c.getString(key);
329: String handle = key.substring(0, key.indexOf('.'));
330: log.debug("handle: " + handle
331: + " DataSourceFactory: " + classname);
332: Class dsfClass = Class.forName(classname);
333: DataSourceFactory dsf = (DataSourceFactory) dsfClass
334: .newInstance();
335: dsf.initialize(c.subset(handle));
336:
337: Database database = getOrCreateDatabase(handle);
338: database.setDataSourceFactory(dsf);
339: }
340: }
341: } catch (RuntimeException e) {
342: log.error("Runtime Error reading adapter configuration", e);
343: throw new TorqueRuntimeException(e);
344: } catch (Exception e) {
345: log.error("Error reading adapter configuration", e);
346: throw new TorqueException(e);
347: }
348:
349: Database defaultDatabase = (Database) databases
350: .get(defaultDBName);
351: if (defaultDatabase == null
352: || defaultDatabase.getDataSourceFactory() == null) {
353: String error = "Invalid configuration : "
354: + "No DataSourceFactory definition for default DB found. "
355: + "A DataSourceFactory must be defined under the key"
356: + Torque.TORQUE_KEY + "."
357: + DataSourceFactory.DSFACTORY_KEY + "."
358: + defaultDBName + "."
359: + DataSourceFactory.FACTORY_KEY;
360: log.error(error);
361: throw new TorqueException(error);
362: }
363:
364: // As there might be a default database configured
365: // to map "default" onto an existing datasource, we
366: // must check, whether there _is_ really an entry for
367: // the "default" in the dsFactoryMap or not. If it is
368: // not, then add a dummy entry for the "default"
369: //
370: // Without this, you can't actually access the "default"
371: // data-source, even if you have an entry like
372: //
373: // database.default = bookstore
374: //
375: // in your Torque.properties
376: //
377:
378: {
379: Database databaseInfoForKeyDefault = getOrCreateDatabase(DEFAULT_NAME);
380: if ((!defaultDBName.equals(DEFAULT_NAME))
381: && databaseInfoForKeyDefault.getDataSourceFactory() == null) {
382: log
383: .debug("Adding the DatasourceFactory and DatabaseAdapter from database "
384: + defaultDBName
385: + " onto database "
386: + DEFAULT_NAME);
387: databaseInfoForKeyDefault
388: .setDataSourceFactory(defaultDatabase
389: .getDataSourceFactory());
390: databaseInfoForKeyDefault.setAdapter(defaultDatabase
391: .getAdapter());
392:
393: this .defaultDsfIsReference = true;
394: }
395: }
396:
397: }
398:
399: /**
400: * Initialization of Torque with a properties file.
401: *
402: * @param configFile The absolute path to the configuration file.
403: * @throws TorqueException Any exceptions caught during processing will be
404: * rethrown wrapped into a TorqueException.
405: */
406: public void init(String configFile) throws TorqueException {
407: log.debug("init(" + configFile + ")");
408: try {
409: Configuration configuration = new PropertiesConfiguration(
410: configFile);
411:
412: log.debug("Config Object is " + configuration);
413: init(configuration);
414: } catch (ConfigurationException e) {
415: throw new TorqueException(e);
416: }
417: }
418:
419: /**
420: * Initialization of Torque with a Configuration object.
421: *
422: * @param conf The Torque configuration.
423: * @throws TorqueException Any exceptions caught during processing will be
424: * rethrown wrapped into a TorqueException.
425: */
426: public synchronized void init(Configuration conf)
427: throws TorqueException {
428: log.debug("init(" + conf + ")");
429: setConfiguration(conf);
430: initialize();
431: }
432:
433: /**
434: * Creates a mapping between classes and their manager classes.
435: *
436: * The mapping is built according to settings present in
437: * properties file. The entries should have the
438: * following form:
439: *
440: * <pre>
441: * torque.managed_class.com.mycompany.Myclass.manager= \
442: * com.mycompany.MyManagerImpl
443: * services.managed_class.com.mycompany.Myotherclass.manager= \
444: * com.mycompany.MyOtherManagerImpl
445: * </pre>
446: *
447: * <br>
448: *
449: * Generic ServiceBroker provides no Services.
450: *
451: * @param conf the Configuration representing the properties file
452: * @throws TorqueException Any exceptions caught during processing will be
453: * rethrown wrapped into a TorqueException.
454: */
455: protected void initManagerMappings(Configuration conf)
456: throws TorqueException {
457: int pref = Torque.MANAGER_PREFIX.length();
458: int suff = Torque.MANAGER_SUFFIX.length();
459:
460: for (Iterator it = conf.getKeys(); it.hasNext();) {
461: String key = (String) it.next();
462:
463: if (key.startsWith(Torque.MANAGER_PREFIX)
464: && key.endsWith(Torque.MANAGER_SUFFIX)) {
465: String managedClassKey = key.substring(pref, key
466: .length()
467: - suff);
468: if (!managers.containsKey(managedClassKey)) {
469: String managerClass = conf.getString(key);
470: log.info("Added Manager for Class: "
471: + managedClassKey + " -> " + managerClass);
472: try {
473: initManager(managedClassKey, managerClass);
474: } catch (TorqueException e) {
475: // the exception thrown here seems to disappear.
476: // At least when initialized by Turbine, should find
477: // out why, but for now make sure it is noticed.
478: log.error("", e);
479: e.printStackTrace();
480: throw e;
481: }
482: }
483: }
484: }
485: }
486:
487: /**
488: * Initialize a manager
489: *
490: * @param name name of the manager
491: * @param className name of the manager class
492: * @throws TorqueException Any exceptions caught during processing will be
493: * rethrown wrapped into a TorqueException.
494: */
495: private synchronized void initManager(String name, String className)
496: throws TorqueException {
497: AbstractBaseManager manager = (AbstractBaseManager) managers
498: .get(name);
499:
500: if (manager == null) {
501: if (className != null && className.length() != 0) {
502: try {
503: manager = (AbstractBaseManager) Class.forName(
504: className).newInstance();
505: managers.put(name, manager);
506: } catch (Exception e) {
507: throw new TorqueException("Could not instantiate "
508: + "manager associated with class: " + name,
509: e);
510: }
511: }
512: }
513: }
514:
515: /**
516: * Determine whether Torque has already been initialized.
517: *
518: * @return true if Torque is already initialized
519: */
520: public boolean isInit() {
521: return isInit;
522: }
523:
524: /**
525: * Sets the configuration for Torque and all dependencies.
526: * The prefix <code>TORQUE_KEY</code> needs to be removed from the
527: * configuration keys for the provided configuration.
528: *
529: * @param conf the Configuration.
530: */
531: public void setConfiguration(Configuration conf) {
532: log.debug("setConfiguration(" + conf + ")");
533: this .conf = conf;
534: }
535:
536: /**
537: * Get the configuration for this component.
538: *
539: * @return the Configuration
540: */
541: public Configuration getConfiguration() {
542: log.debug("getConfiguration() = " + conf);
543: return conf;
544: }
545:
546: /**
547: * This method returns a Manager for the given name.
548: *
549: * @param name name of the manager
550: * @return a Manager
551: */
552: public AbstractBaseManager getManager(String name) {
553: AbstractBaseManager m = (AbstractBaseManager) managers
554: .get(name);
555: if (m == null) {
556: log.error("No configured manager for key " + name + ".");
557: }
558: return m;
559: }
560:
561: /**
562: * This methods returns either the Manager from the configuration file,
563: * or the default one provided by the generated code.
564: *
565: * @param name name of the manager
566: * @param defaultClassName the class to use if name has not been configured
567: * @return a Manager
568: */
569: public AbstractBaseManager getManager(String name,
570: String defaultClassName) {
571: AbstractBaseManager m = (AbstractBaseManager) managers
572: .get(name);
573: if (m == null) {
574: log.debug("Added late Manager mapping for Class: " + name
575: + " -> " + defaultClassName);
576:
577: try {
578: initManager(name, defaultClassName);
579: } catch (TorqueException e) {
580: log.error(e.getMessage(), e);
581: }
582:
583: // Try again now that the default manager should be in the map
584: m = (AbstractBaseManager) managers.get(name);
585: }
586:
587: return m;
588: }
589:
590: /**
591: * Shuts down the service.
592: *
593: * This method halts the IDBroker's daemon thread in all of
594: * the DatabaseMap's. It also closes all SharedPoolDataSourceFactories
595: * and PerUserPoolDataSourceFactories initialized by Torque.
596: * @exception TorqueException if a DataSourceFactory could not be closed
597: * cleanly. Only the first exception is rethrown, any following
598: * exceptions are logged but ignored.
599: */
600: public synchronized void shutdown() throws TorqueException {
601: // stop the idbrokers
602: synchronized (databases) {
603: for (Iterator it = databases.values().iterator(); it
604: .hasNext();) {
605: Database database = (Database) it.next();
606: IDBroker idBroker = database.getIDBroker();
607: if (idBroker != null) {
608: idBroker.stop();
609: }
610: }
611: }
612:
613: // shut down the cache managers
614: synchronized (managers) {
615: for (Iterator it = managers.entrySet().iterator(); it
616: .hasNext();) {
617: Map.Entry mentry = (Map.Entry) it.next();
618:
619: AbstractBaseManager manager = (AbstractBaseManager) mentry
620: .getValue();
621: manager.dispose();
622: it.remove();
623: }
624: }
625:
626: // shut down the data source factories
627: TorqueException exception = null;
628: synchronized (databases) {
629: for (Iterator it = databases.keySet().iterator(); it
630: .hasNext();) {
631: Object databaseKey = it.next();
632:
633: Database database = (Database) databases
634: .get(databaseKey);
635: if (DEFAULT_NAME.equals(databaseKey)
636: && defaultDsfIsReference) {
637: // the DataSourceFactory of the database with the name
638: // DEFAULT_NAME is just a reference to aynother entry.
639: // Do not close because this leads to closing
640: // the same DataSourceFactory twice.
641: database.setDataSourceFactory(null);
642: break;
643: }
644:
645: try {
646: DataSourceFactory dataSourceFactory = database
647: .getDataSourceFactory();
648: if (dataSourceFactory != null) {
649: dataSourceFactory.close();
650: database.setDataSourceFactory(null);
651: }
652: } catch (TorqueException e) {
653: log.error(
654: "Error while closing the DataSourceFactory "
655: + databaseKey, e);
656: if (exception == null) {
657: exception = e;
658: }
659: }
660: }
661: }
662: if (exception != null) {
663: throw exception;
664: }
665: resetConfiguration();
666: }
667:
668: /**
669: * Resets some internal configuration variables to
670: * their defaults.
671: */
672: private void resetConfiguration() {
673: mapBuilderCache = Collections.synchronizedMap(new HashMap());
674: managers = new HashMap();
675: isInit = false;
676: }
677:
678: /**
679: * Returns the default database map information.
680: *
681: * @return A DatabaseMap.
682: * @throws TorqueException Any exceptions caught during processing will be
683: * rethrown wrapped into a TorqueException.
684: */
685: public DatabaseMap getDatabaseMap() throws TorqueException {
686: return getDatabaseMap(getDefaultDB());
687: }
688:
689: /**
690: * Returns the database map information. Name relates to the name
691: * of the connection pool to associate with the map.
692: *
693: * @param name The name of the database corresponding to the
694: * <code>DatabaseMap</code> to retrieve.
695: * @return The named <code>DatabaseMap</code>.
696: * @throws TorqueException Any exceptions caught during processing will be
697: * rethrown wrapped into a TorqueException.
698: */
699: public DatabaseMap getDatabaseMap(String name)
700: throws TorqueException {
701: if (name == null) {
702: throw new TorqueException("DatabaseMap name was null!");
703: }
704:
705: Database database = getOrCreateDatabase(name);
706: return database.getDatabaseMap();
707: }
708:
709: /**
710: * Get the registered MapBuilders
711: *
712: * @return the MapBuilder cache
713: *
714: */
715: public Map getMapBuilders() {
716: return mapBuilderCache;
717: }
718:
719: /**
720: * Register a MapBuilder
721: *
722: * @param className the MapBuilder
723: */
724: public void registerMapBuilder(String className) {
725: mapBuilderCache.put(className, null);
726: }
727:
728: /**
729: * Register a MapBuilder
730: *
731: * @param builder the instance of the MapBuilder
732: *
733: */
734: public void registerMapBuilder(MapBuilder builder) {
735: mapBuilderCache.put(builder.getClass().getName(), builder);
736: }
737:
738: /**
739: * Get a MapBuilder
740: *
741: * @param className of the MapBuilder
742: * @return A MapBuilder, not null
743: * @throws TorqueException if the Map Builder cannot be instantiated
744: *
745: */
746: public MapBuilder getMapBuilder(String className)
747: throws TorqueException {
748: try {
749: MapBuilder mb = (MapBuilder) mapBuilderCache.get(className);
750:
751: if (mb == null) {
752: mb = (MapBuilder) Class.forName(className)
753: .newInstance();
754: // Cache the MapBuilder before it is built.
755: mapBuilderCache.put(className, mb);
756: }
757:
758: if (mb.isBuilt()) {
759: return mb;
760: }
761:
762: try {
763: mb.doBuild();
764: } catch (Exception e) {
765: // remove the MapBuilder from the cache if it can't be built correctly
766: mapBuilderCache.remove(className);
767: throw e;
768: }
769:
770: return mb;
771: } catch (Exception e) {
772: log.error("getMapBuilder failed trying to instantiate: "
773: + className, e);
774: throw new TorqueException(e);
775: }
776: }
777:
778: /**
779: * This method returns a Connection from the default pool.
780: *
781: * @return The requested connection, never null.
782: * @throws TorqueException Any exceptions caught during processing will be
783: * rethrown wrapped into a TorqueException.
784: */
785: public Connection getConnection() throws TorqueException {
786: return getConnection(getDefaultDB());
787: }
788:
789: /**
790: * Returns a database connection to the database with the key
791: * <code>name</code>.
792: * @param name The database name.
793: * @return a database connection, never null.
794: * @throws TorqueException If no DataSourceFactory is configured for the
795: * named database, the connection information is wrong, or the
796: * connection cannot be returned for any other reason.
797: */
798: public Connection getConnection(String name) throws TorqueException {
799: if (!Torque.isInit()) {
800: throw new TorqueException("Torque is not initialized");
801: }
802: try {
803: return getDatabase(name).getDataSourceFactory()
804: .getDataSource().getConnection();
805: } catch (SQLException se) {
806: throw new TorqueException(se);
807: }
808: }
809:
810: /**
811: * Returns the DataSourceFactory for the database with the name
812: * <code>name</code>.
813: *
814: * @param name The name of the database to get the DSF for.
815: * @return A DataSourceFactory object, never null.
816: * @throws TorqueException if Torque is not initiliaized, or
817: * no DatasourceFactory is configured for the given name.
818: */
819: public DataSourceFactory getDataSourceFactory(String name)
820: throws TorqueException {
821: Database database = getDatabase(name);
822:
823: DataSourceFactory dsf = null;
824: if (database != null) {
825: dsf = database.getDataSourceFactory();
826: }
827:
828: if (dsf == null) {
829: throw new TorqueException("There was no DataSourceFactory "
830: + "configured for the connection " + name);
831: }
832:
833: return dsf;
834: }
835:
836: /**
837: * This method returns a Connection using the given parameters.
838: * You should only use this method if you need user based access to the
839: * database!
840: *
841: * @param name The database name.
842: * @param username The name of the database user.
843: * @param password The password of the database user.
844: * @return A Connection.
845: * @throws TorqueException Any exceptions caught during processing will be
846: * rethrown wrapped into a TorqueException.
847: */
848: public Connection getConnection(String name, String username,
849: String password) throws TorqueException {
850: if (!Torque.isInit()) {
851: throw new TorqueException("Torque is not initialized");
852: }
853: try {
854: return getDataSourceFactory(name).getDataSource()
855: .getConnection(username, password);
856: } catch (SQLException se) {
857: throw new TorqueException(se);
858: }
859: }
860:
861: /**
862: * Returns the database adapter for a specific database.
863: *
864: * @param name the name of the database to get the adapter for.
865: * @return The corresponding database adapter, or null if no database
866: * adapter is defined for the given database.
867: * @throws TorqueException Any exceptions caught during processing will be
868: * rethrown wrapped into a TorqueException.
869: */
870: public DB getDB(String name) throws TorqueException {
871: Database database = getDatabase(name);
872: if (database == null) {
873: return null;
874: }
875: return database.getAdapter();
876: }
877:
878: ///////////////////////////////////////////////////////////////////////////
879:
880: /**
881: * Returns the name of the default database.
882: *
883: * @return name of the default DB, or null if Torque is not initialized yet
884: */
885: public String getDefaultDB() {
886: return defaultDBName;
887: }
888:
889: /**
890: * Closes a connection.
891: *
892: * @param con A Connection to close.
893: */
894: public void closeConnection(Connection con) {
895: if (con != null) {
896: try {
897: con.close();
898: } catch (SQLException e) {
899: log.error("Error occured while closing connection.", e);
900: }
901: }
902: }
903:
904: /**
905: * Sets the current schema for a database connection
906: *
907: * @param name The database name.
908: * @param schema The current schema name.
909: * @throws TorqueException Any exceptions caught during processing will be
910: * rethrown wrapped into a TorqueException.
911: */
912: public void setSchema(String name, String schema)
913: throws TorqueException {
914: getOrCreateDatabase(name).setSchema(schema);
915: }
916:
917: /**
918: * This method returns the current schema for a database connection
919: *
920: * @param name The database name.
921: * @return The current schema name. Null means, no schema has been set.
922: * @throws TorqueException Any exceptions caught during processing will be
923: * rethrown wrapped into a TorqueException.
924: */
925: public String getSchema(String name) throws TorqueException {
926: Database database = getDatabase(name);
927: if (database == null) {
928: return null;
929: }
930: return database.getSchema();
931: }
932:
933: /**
934: * Returns the database for the key <code>databaseName</code>.
935: *
936: * @param databaseName the key to get the database for.
937: * @return the database for the specified key, or null if the database
938: * does not exist.
939: * @throws TorqueException if Torque is not yet initialized.
940: */
941: public Database getDatabase(String databaseName)
942: throws TorqueException {
943: if (!isInit()) {
944: throw new TorqueException("Torque is not initialized.");
945: }
946: return (Database) databases.get(databaseName);
947: }
948:
949: /**
950: * Returns a Map containing all Databases registered to Torque.
951: * The key of the Map is the name of the database, and the value is the
952: * database instance. <br/>
953: * Note that in the very special case where a new database which
954: * is not configured in Torque's configuration gets known to Torque
955: * at a later time, the returned map may change, and there is no way to
956: * protect you against this.
957: *
958: * @return a Map containing all Databases known to Torque, never null.
959: * @throws TorqueException if Torque is not yet initialized.
960: */
961: public Map getDatabases() throws TorqueException {
962: if (!isInit()) {
963: throw new TorqueException("Torque is not initialized.");
964: }
965: return Collections.unmodifiableMap(databases);
966: }
967:
968: /**
969: * Returns the database for the key <code>databaseName</code>.
970: * If no database is associated to the specified key,
971: * a new database is created, mapped to the specified key, and returned.
972: *
973: * @param databaseName the key to get the database for.
974: * @return the database associated with specified key, or the newly created
975: * database, never null.
976: */
977: public Database getOrCreateDatabase(String databaseName) {
978: synchronized (databases) {
979: Database result = (Database) databases.get(databaseName);
980: if (result == null) {
981: result = new Database(databaseName);
982: databases.put(databaseName, result);
983: }
984: return result;
985: }
986: }
987: }
|