1 package org.apache.torque;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.sql.Connection;
23 import java.sql.SQLException;
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.Iterator;
27 import java.util.Map;
28
29 import org.apache.commons.configuration.Configuration;
30 import org.apache.commons.configuration.ConfigurationException;
31 import org.apache.commons.configuration.PropertiesConfiguration;
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34 import org.apache.torque.adapter.DB;
35 import org.apache.torque.adapter.DBFactory;
36 import org.apache.torque.dsfactory.DataSourceFactory;
37 import org.apache.torque.manager.AbstractBaseManager;
38 import org.apache.torque.map.DatabaseMap;
39 import org.apache.torque.map.MapBuilder;
40 import org.apache.torque.oid.IDBroker;
41 import org.apache.torque.oid.IDGeneratorFactory;
42
43 /***
44 * The core of Torque's implementation. Both the classic {@link
45 * org.apache.torque.Torque} static wrapper and the {@link
46 * org.apache.torque.avalon.TorqueComponent} <a
47 * href="http://avalon.apache.org/">Avalon</a> implementation leverage
48 * this class.
49 *
50 * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
51 * @author <a href="mailto:magnus@handtolvur.is">MagnÔø?s Ôø?Ôø?r Torfason</a>
52 * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
53 * @author <a href="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a>
54 * @author <a href="mailto:mpoeschl@marmot.at">Martin Poeschl</a>
55 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
56 * @author <a href="mailto:kschrader@karmalab.org">Kurt Schrader</a>
57 * @author <a href="mailto:tv@apache.org">Thomas Vandahl</a>
58 * @version $Id: TorqueInstance.java 500332 2007-01-26 20:30:34Z tfischer $
59 */
60 public class TorqueInstance
61 {
62 /*** Logging */
63 private static Log log = LogFactory.getLog(TorqueInstance.class);
64
65 /*** A constant for <code>default</code>. */
66 private static final String DEFAULT_NAME = "default";
67
68 /*** The db name that is specified as the default in the property file */
69 private String defaultDBName = null;
70
71 /***
72 * The Map which contains all known databases. All iterations over the map
73 * and other operations where the databaase map needs to stay
74 * in a defined state must be synchronized to this map.
75 */
76 private Map databases = Collections.synchronizedMap(new HashMap());
77
78 /*** A repository of Manager instances. */
79 private Map managers;
80
81 /*** Torque-specific configuration. */
82 private Configuration conf;
83
84 /*** flag to set to true once this class has been initialized */
85 private boolean isInit = false;
86
87 /***
88 * a flag which indicates whether the DataSourceFactory in the database
89 * named <code>DEFAULT</code> is a reference to another
90 * DataSourceFactory. This is important to know when closing the
91 * DataSourceFactories on shutdown();
92 */
93 private boolean defaultDsfIsReference = false;
94
95 /***
96 * Store mapbuilder classnames for peers that have been referenced prior
97 * to Torque being initialized. This can happen if torque om/peer objects
98 * are serialized then unserialized prior to Torque being reinitialized.
99 * This condition exists in a normal catalina restart.
100 */
101 private Map mapBuilderCache = null;
102
103 /***
104 * Creates a new instance with default configuration.
105 *
106 * @see #resetConfiguration()
107 */
108 public TorqueInstance()
109 {
110 resetConfiguration();
111 }
112
113 /***
114 * Initializes this instance of Torque.
115 *
116 * @see org.apache.stratum.lifecycle.Initializable
117 * @throws TorqueException Any exceptions caught during processing will be
118 * rethrown wrapped into a TorqueException.
119 */
120 private synchronized void initialize() throws TorqueException
121 {
122 log.debug("initialize()");
123
124 if (isInit)
125 {
126 log.debug("Multiple initializations of Torque attempted");
127 return;
128 }
129
130 if (conf == null || conf.isEmpty())
131 {
132 throw new TorqueException("Torque cannot be initialized without "
133 + "a valid configuration. Please check the log files "
134 + "for further details.");
135 }
136
137
138
139
140
141
142
143 Configuration subConf = conf.subset(Torque.TORQUE_KEY);
144 if (subConf == null || subConf.isEmpty())
145 {
146 String error = ("Invalid configuration. No keys starting with "
147 + Torque.TORQUE_KEY
148 + " found in configuration");
149 log.error(error);
150 throw new TorqueException(error);
151 }
152 setConfiguration(subConf);
153
154 initDefaultDbName(conf);
155 initAdapters(conf);
156 initDataSourceFactories(conf);
157
158
159 initManagerMappings(conf);
160
161 isInit = true;
162
163
164 synchronized (mapBuilderCache)
165 {
166 for (Iterator i = mapBuilderCache.entrySet().iterator(); i.hasNext();)
167 {
168 Map.Entry entry = (Map.Entry)i.next();
169
170 if (null == entry.getValue())
171 {
172 try
173 {
174
175 MapBuilder builder = (MapBuilder) Class.forName((String) entry.getKey()).newInstance();
176
177 if (!builder.isBuilt())
178 {
179 builder.doBuild();
180 }
181
182 entry.setValue(builder);
183 }
184 catch (Exception e)
185 {
186 throw new TorqueException(e);
187 }
188 }
189 }
190 }
191 }
192
193
194 /***
195 * Initializes the name of the default database and
196 * associates the database with the name <code>DEFAULT_NAME</code>
197 * to the default database.
198 *
199 * @param conf the configuration representing the torque section.
200 * of the properties file.
201 * @throws TorqueException if the appropriate key is not set.
202 */
203 private void initDefaultDbName(Configuration conf)
204 throws TorqueException
205 {
206
207 defaultDBName =
208 conf.getString(
209 Torque.DATABASE_KEY
210 + "."
211 + Torque.DEFAULT_KEY);
212 if (defaultDBName == null)
213 {
214 String error = "Invalid configuration: Key "
215 + Torque.TORQUE_KEY
216 + "."
217 + Torque.DATABASE_KEY
218 + "."
219 + Torque.DEFAULT_KEY
220 + " not set";
221 log.error(error);
222 throw new TorqueException(error);
223 }
224 }
225
226 /***
227 * Reads the adapter settings from the configuration and
228 * assigns the appropriate database adapters and Id Generators
229 * to the databases.
230 *
231 * @param conf the Configuration representing the torque section of the
232 * properties file
233 * @throws TorqueException Any exceptions caught during processing will be
234 * rethrown wrapped into a TorqueException.
235 */
236 private void initAdapters(Configuration conf)
237 throws TorqueException
238 {
239 log.debug("initAdapters(" + conf + ")");
240
241 Configuration c = conf.subset(Torque.DATABASE_KEY);
242 if (c == null || c.isEmpty())
243 {
244 String error = "Invalid configuration : "
245 + "No keys starting with "
246 + Torque.TORQUE_KEY
247 + "."
248 + Torque.DATABASE_KEY
249 + " found in configuration";
250 log.error(error);
251 throw new TorqueException(error);
252 }
253
254 try
255 {
256 for (Iterator it = c.getKeys(); it.hasNext();)
257 {
258 String key = (String) it.next();
259 if (key.endsWith(DB.ADAPTER_KEY)
260 || key.endsWith(DB.DRIVER_KEY))
261 {
262 String adapter = c.getString(key);
263 String handle = key.substring(0, key.indexOf('.'));
264
265 DB db;
266
267 db = DBFactory.create(adapter);
268
269
270 if (db == null)
271 {
272 String adapterClassName = c.getString(key + "." + adapter + ".className", null);
273 db = DBFactory.create(adapter, adapterClassName);
274 }
275
276 Database database = getOrCreateDatabase(handle);
277
278
279 database.setAdapter(db);
280 log.debug("Adding " + adapter + " -> "
281 + handle + " as Adapter");
282
283
284
285
286
287
288
289 getDatabaseMap(handle);
290 for (int i = 0;
291 i < IDGeneratorFactory.ID_GENERATOR_METHODS.length;
292 i++)
293 {
294 database.addIdGenerator(
295 IDGeneratorFactory.ID_GENERATOR_METHODS[i],
296 IDGeneratorFactory.create(db, handle));
297 }
298 }
299 }
300 }
301 catch (InstantiationException e)
302 {
303 log.error("Error creating a database adapter instance", e);
304 throw new TorqueException(e);
305 }
306 catch (TorqueException e)
307 {
308 log.error("Error reading configuration seeking database "
309 + "adapters", e);
310 throw new TorqueException(e);
311 }
312
313
314 Database defaultDatabase
315 = (Database) databases.get(Torque.getDefaultDB());
316 if (defaultDatabase == null
317 || defaultDatabase.getAdapter() == null)
318 {
319 String error = "Invalid configuration : "
320 + "No adapter definition found for default DB "
321 + "An adapter must be defined under "
322 + Torque.TORQUE_KEY
323 + "."
324 + Torque.DATABASE_KEY
325 + "."
326 + Torque.getDefaultDB()
327 + "."
328 + DB.ADAPTER_KEY;
329 log.error(error);
330 throw new TorqueException(error);
331 }
332 }
333
334 /***
335 * Reads the settings for the DataSourceFactories from the configuration
336 * and creates and/or cinfigures the DataSourceFactories for the databases.
337 * If no DataSorceFactory is assigned to the database with the name
338 * <code>DEFAULT_NAME</code>, a reference to the DataSourceFactory
339 * of the default daztabase is made from the database with the name
340 * <code>DEFAULT_NAME</code>.
341 *
342 * @param conf the Configuration representing the properties file
343 * @throws TorqueException Any exceptions caught during processing will be
344 * rethrown wrapped into a TorqueException.
345 */
346 private void initDataSourceFactories(Configuration conf)
347 throws TorqueException
348 {
349 log.debug("initDataSourceFactories(" + conf + ")");
350
351 Configuration c = conf.subset(DataSourceFactory.DSFACTORY_KEY);
352 if (c == null || c.isEmpty())
353 {
354 String error = "Invalid configuration: "
355 + "No keys starting with "
356 + Torque.TORQUE_KEY
357 + "."
358 + DataSourceFactory.DSFACTORY_KEY
359 + " found in configuration";
360 log.error(error);
361 throw new TorqueException(error);
362 }
363
364 try
365 {
366 for (Iterator it = c.getKeys(); it.hasNext();)
367 {
368 String key = (String) it.next();
369 if (key.endsWith(DataSourceFactory.FACTORY_KEY))
370 {
371 String classname = c.getString(key);
372 String handle = key.substring(0, key.indexOf('.'));
373 log.debug("handle: " + handle
374 + " DataSourceFactory: " + classname);
375 Class dsfClass = Class.forName(classname);
376 DataSourceFactory dsf =
377 (DataSourceFactory) dsfClass.newInstance();
378 dsf.initialize(c.subset(handle));
379
380 Database database = getOrCreateDatabase(handle);
381 database.setDataSourceFactory(dsf);
382 }
383 }
384 }
385 catch (RuntimeException e)
386 {
387 log.error("Runtime Error reading adapter configuration", e);
388 throw new TorqueRuntimeException(e);
389 }
390 catch (Exception e)
391 {
392 log.error("Error reading adapter configuration", e);
393 throw new TorqueException(e);
394 }
395
396 Database defaultDatabase
397 = (Database) databases.get(defaultDBName);
398 if (defaultDatabase == null
399 || defaultDatabase.getDataSourceFactory() == null)
400 {
401 String error = "Invalid configuration : "
402 + "No DataSourceFactory definition for default DB found. "
403 + "A DataSourceFactory must be defined under the key"
404 + Torque.TORQUE_KEY
405 + "."
406 + DataSourceFactory.DSFACTORY_KEY
407 + "."
408 + defaultDBName
409 + "."
410 + DataSourceFactory.FACTORY_KEY;
411 log.error(error);
412 throw new TorqueException(error);
413 }
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429 {
430 Database databaseInfoForKeyDefault
431 = getOrCreateDatabase(DEFAULT_NAME);
432 if ((!defaultDBName.equals(DEFAULT_NAME))
433 && databaseInfoForKeyDefault.getDataSourceFactory() == null)
434 {
435 log.debug("Adding the DatasourceFactory from database "
436 + defaultDBName
437 + " onto database " + DEFAULT_NAME);
438 databaseInfoForKeyDefault.setDataSourceFactory(
439 defaultDatabase.getDataSourceFactory());
440 this.defaultDsfIsReference = true;
441 }
442 }
443
444 }
445
446 /***
447 * Initialization of Torque with a properties file.
448 *
449 * @param configFile The absolute path to the configuration file.
450 * @throws TorqueException Any exceptions caught during processing will be
451 * rethrown wrapped into a TorqueException.
452 */
453 public void init(String configFile)
454 throws TorqueException
455 {
456 log.debug("init(" + configFile + ")");
457 try
458 {
459 Configuration configuration
460 = new PropertiesConfiguration(configFile);
461
462 log.debug("Config Object is " + configuration);
463 init(configuration);
464 }
465 catch (ConfigurationException e)
466 {
467 throw new TorqueException(e);
468 }
469 }
470
471 /***
472 * Initialization of Torque with a Configuration object.
473 *
474 * @param conf The Torque configuration.
475 * @throws TorqueException Any exceptions caught during processing will be
476 * rethrown wrapped into a TorqueException.
477 */
478 public synchronized void init(Configuration conf)
479 throws TorqueException
480 {
481 log.debug("init(" + conf + ")");
482 setConfiguration(conf);
483 initialize();
484 }
485
486
487 /***
488 * Creates a mapping between classes and their manager classes.
489 *
490 * The mapping is built according to settings present in
491 * properties file. The entries should have the
492 * following form:
493 *
494 * <pre>
495 * torque.managed_class.com.mycompany.Myclass.manager= \
496 * com.mycompany.MyManagerImpl
497 * services.managed_class.com.mycompany.Myotherclass.manager= \
498 * com.mycompany.MyOtherManagerImpl
499 * </pre>
500 *
501 * <br>
502 *
503 * Generic ServiceBroker provides no Services.
504 *
505 * @param conf the Configuration representing the properties file
506 * @throws TorqueException Any exceptions caught during processing will be
507 * rethrown wrapped into a TorqueException.
508 */
509 protected void initManagerMappings(Configuration conf)
510 throws TorqueException
511 {
512 int pref = Torque.MANAGER_PREFIX.length();
513 int suff = Torque.MANAGER_SUFFIX.length();
514
515 for (Iterator it = conf.getKeys(); it.hasNext();)
516 {
517 String key = (String) it.next();
518
519 if (key.startsWith(Torque.MANAGER_PREFIX)
520 && key.endsWith(Torque.MANAGER_SUFFIX))
521 {
522 String managedClassKey = key.substring(pref,
523 key.length() - suff);
524 if (!managers.containsKey(managedClassKey))
525 {
526 String managerClass = conf.getString(key);
527 log.info("Added Manager for Class: " + managedClassKey
528 + " -> " + managerClass);
529 try
530 {
531 initManager(managedClassKey, managerClass);
532 }
533 catch (TorqueException e)
534 {
535
536
537
538 log.error("", e);
539 e.printStackTrace();
540 throw e;
541 }
542 }
543 }
544 }
545 }
546
547 /***
548 * Initialize a manager
549 *
550 * @param name name of the manager
551 * @param className name of the manager class
552 * @throws TorqueException Any exceptions caught during processing will be
553 * rethrown wrapped into a TorqueException.
554 */
555 private synchronized void initManager(String name, String className)
556 throws TorqueException
557 {
558 AbstractBaseManager manager = (AbstractBaseManager) managers.get(name);
559
560 if (manager == null)
561 {
562 if (className != null && className.length() != 0)
563 {
564 try
565 {
566 manager = (AbstractBaseManager)
567 Class.forName(className).newInstance();
568 managers.put(name, manager);
569 }
570 catch (Exception e)
571 {
572 throw new TorqueException("Could not instantiate "
573 + "manager associated with class: "
574 + name, e);
575 }
576 }
577 }
578 }
579
580 /***
581 * Determine whether Torque has already been initialized.
582 *
583 * @return true if Torque is already initialized
584 */
585 public boolean isInit()
586 {
587 return isInit;
588 }
589
590 /***
591 * Sets the configuration for Torque and all dependencies.
592 * The prefix <code>TORQUE_KEY</code> needs to be removed from the
593 * configuration keys for the provided configuration.
594 *
595 * @param conf the Configuration.
596 */
597 public void setConfiguration(Configuration conf)
598 {
599 log.debug("setConfiguration(" + conf + ")");
600 this.conf = conf;
601 }
602
603 /***
604 * Get the configuration for this component.
605 *
606 * @return the Configuration
607 */
608 public Configuration getConfiguration()
609 {
610 log.debug("getConfiguration() = " + conf);
611 return conf;
612 }
613
614 /***
615 * This method returns a Manager for the given name.
616 *
617 * @param name name of the manager
618 * @return a Manager
619 */
620 public AbstractBaseManager getManager(String name)
621 {
622 AbstractBaseManager m = (AbstractBaseManager) managers.get(name);
623 if (m == null)
624 {
625 log.error("No configured manager for key " + name + ".");
626 }
627 return m;
628 }
629
630 /***
631 * This methods returns either the Manager from the configuration file,
632 * or the default one provided by the generated code.
633 *
634 * @param name name of the manager
635 * @param defaultClassName the class to use if name has not been configured
636 * @return a Manager
637 */
638 public AbstractBaseManager getManager(String name,
639 String defaultClassName)
640 {
641 AbstractBaseManager m = (AbstractBaseManager) managers.get(name);
642 if (m == null)
643 {
644 log.debug("Added late Manager mapping for Class: "
645 + name + " -> " + defaultClassName);
646
647 try
648 {
649 initManager(name, defaultClassName);
650 }
651 catch (TorqueException e)
652 {
653 log.error(e.getMessage(), e);
654 }
655
656
657 m = (AbstractBaseManager) managers.get(name);
658 }
659
660 return m;
661 }
662
663 /***
664 * Shuts down the service.
665 *
666 * This method halts the IDBroker's daemon thread in all of
667 * the DatabaseMap's. It also closes all SharedPoolDataSourceFactories
668 * and PerUserPoolDataSourceFactories initialized by Torque.
669 * @exception TorqueException if a DataSourceFactory could not be closed
670 * cleanly. Only the first exception is rethrown, any following
671 * exceptions are logged but ignored.
672 */
673 public synchronized void shutdown()
674 throws TorqueException
675 {
676
677 synchronized (databases)
678 {
679 for (Iterator it = databases.values().iterator(); it.hasNext();)
680 {
681 Database database = (Database) it.next();
682 IDBroker idBroker = database.getIDBroker();
683 if (idBroker != null)
684 {
685 idBroker.stop();
686 }
687 }
688 }
689
690
691 TorqueException exception = null;
692 synchronized (databases)
693 {
694 for (Iterator it = databases.keySet().iterator(); it.hasNext();)
695 {
696 Object databaseKey = it.next();
697
698 Database database
699 = (Database) databases.get(databaseKey);
700 if (DEFAULT_NAME.equals(databaseKey) && defaultDsfIsReference)
701 {
702
703
704
705
706 database.setDataSourceFactory(null);
707 break;
708 }
709
710 try
711 {
712 DataSourceFactory dataSourceFactory
713 = database.getDataSourceFactory();
714 if (dataSourceFactory != null)
715 {
716 dataSourceFactory.close();
717 database.setDataSourceFactory(null);
718 }
719 }
720 catch (TorqueException e)
721 {
722 log.error("Error while closing the DataSourceFactory "
723 + databaseKey,
724 e);
725 if (exception == null)
726 {
727 exception = e;
728 }
729 }
730 }
731 }
732 if (exception != null)
733 {
734 throw exception;
735 }
736 resetConfiguration();
737 }
738
739 /***
740 * Resets some internal configuration variables to
741 * their defaults.
742 */
743 private void resetConfiguration()
744 {
745 mapBuilderCache = Collections.synchronizedMap(new HashMap());
746 managers = new HashMap();
747 isInit = false;
748 }
749
750 /***
751 * Returns the default database map information.
752 *
753 * @return A DatabaseMap.
754 * @throws TorqueException Any exceptions caught during processing will be
755 * rethrown wrapped into a TorqueException.
756 */
757 public DatabaseMap getDatabaseMap()
758 throws TorqueException
759 {
760 return getDatabaseMap(getDefaultDB());
761 }
762
763 /***
764 * Returns the database map information. Name relates to the name
765 * of the connection pool to associate with the map.
766 *
767 * @param name The name of the database corresponding to the
768 * <code>DatabaseMap</code> to retrieve.
769 * @return The named <code>DatabaseMap</code>.
770 * @throws TorqueException Any exceptions caught during processing will be
771 * rethrown wrapped into a TorqueException.
772 */
773 public DatabaseMap getDatabaseMap(String name)
774 throws TorqueException
775 {
776 if (name == null)
777 {
778 throw new TorqueException ("DatabaseMap name was null!");
779 }
780
781 Database database = getOrCreateDatabase(name);
782 return database.getDatabaseMap();
783 }
784
785 /***
786 * Get the registered MapBuilders
787 *
788 * @return the MapBuilder cache
789 *
790 */
791 public Map getMapBuilders()
792 {
793 return mapBuilderCache;
794 }
795
796 /***
797 * Register a MapBuilder
798 *
799 * @param className the MapBuilder
800 */
801 public void registerMapBuilder(String className)
802 {
803 mapBuilderCache.put(className, null);
804 }
805
806 /***
807 * Register a MapBuilder
808 *
809 * @param builder the instance of the MapBuilder
810 *
811 */
812 public void registerMapBuilder(MapBuilder builder)
813 {
814 mapBuilderCache.put(builder.getClass().getName(), builder);
815 }
816
817 /***
818 * Get a MapBuilder
819 *
820 * @param className of the MapBuilder
821 * @return A MapBuilder, not null
822 * @throws TorqueException if the Map Builder cannot be instantiated
823 *
824 */
825 public MapBuilder getMapBuilder(String className)
826 throws TorqueException
827 {
828 try
829 {
830 MapBuilder mb = (MapBuilder)mapBuilderCache.get(className);
831
832 if (mb == null)
833 {
834 mb = (MapBuilder) Class.forName(className).newInstance();
835
836 mapBuilderCache.put(className, mb);
837 }
838
839 if (mb.isBuilt())
840 {
841 return mb;
842 }
843
844 try
845 {
846 mb.doBuild();
847 }
848 catch (Exception e)
849 {
850
851 mapBuilderCache.remove(className);
852 throw e;
853 }
854
855 return mb;
856 }
857 catch (Exception e)
858 {
859 log.error("getMapBuilder failed trying to instantiate: "
860 + className, e);
861 throw new TorqueException(e);
862 }
863 }
864
865 /***
866 * This method returns a Connection from the default pool.
867 *
868 * @return The requested connection, never null.
869 * @throws TorqueException Any exceptions caught during processing will be
870 * rethrown wrapped into a TorqueException.
871 */
872 public Connection getConnection()
873 throws TorqueException
874 {
875 return getConnection(getDefaultDB());
876 }
877
878 /***
879 * Returns a database connection to the database with the key
880 * <code>name</code>.
881 * @param name The database name.
882 * @return a database connection, never null.
883 * @throws TorqueException If no DataSourceFactory is configured for the
884 * named database, the connection information is wrong, or the
885 * connection cannot be returned for any other reason.
886 */
887 public Connection getConnection(String name)
888 throws TorqueException
889 {
890 if (!Torque.isInit())
891 {
892 throw new TorqueException("Torque is not initialized");
893 }
894 try
895 {
896 return getDatabase(name)
897 .getDataSourceFactory()
898 .getDataSource()
899 .getConnection();
900 }
901 catch (SQLException se)
902 {
903 throw new TorqueException(se);
904 }
905 }
906
907 /***
908 * Returns the DataSourceFactory for the database with the name
909 * <code>name</code>.
910 *
911 * @param name The name of the database to get the DSF for.
912 * @return A DataSourceFactory object, never null.
913 * @throws TorqueException if Torque is not initiliaized, or
914 * no DatasourceFactory is configured for the given name.
915 */
916 public DataSourceFactory getDataSourceFactory(String name)
917 throws TorqueException
918 {
919 Database database = getDatabase(name);
920
921 DataSourceFactory dsf = null;
922 if (database != null)
923 {
924 dsf = database.getDataSourceFactory();
925 }
926
927 if (dsf == null)
928 {
929 throw new TorqueException(
930 "There was no DataSourceFactory "
931 + "configured for the connection " + name);
932 }
933
934 return dsf;
935 }
936
937 /***
938 * This method returns a Connection using the given parameters.
939 * You should only use this method if you need user based access to the
940 * database!
941 *
942 * @param name The database name.
943 * @param username The name of the database user.
944 * @param password The password of the database user.
945 * @return A Connection.
946 * @throws TorqueException Any exceptions caught during processing will be
947 * rethrown wrapped into a TorqueException.
948 */
949 public Connection getConnection(String name, String username,
950 String password)
951 throws TorqueException
952 {
953 if (!Torque.isInit())
954 {
955 throw new TorqueException("Torque is not initialized");
956 }
957 try
958 {
959 return getDataSourceFactory(name)
960 .getDataSource().getConnection(username, password);
961 }
962 catch (SQLException se)
963 {
964 throw new TorqueException(se);
965 }
966 }
967
968 /***
969 * Returns the database adapter for a specific database.
970 *
971 * @param name the name of the database to get the adapter for.
972 * @return The corresponding database adapter, or null if no database
973 * adapter is defined for the given database.
974 * @throws TorqueException Any exceptions caught during processing will be
975 * rethrown wrapped into a TorqueException.
976 */
977 public DB getDB(String name) throws TorqueException
978 {
979 Database database = getDatabase(name);
980 if (database == null)
981 {
982 return null;
983 }
984 return database.getAdapter();
985 }
986
987
988
989 /***
990 * Returns the name of the default database.
991 *
992 * @return name of the default DB, or null if Torque is not initialized yet
993 */
994 public String getDefaultDB()
995 {
996 return defaultDBName;
997 }
998
999 /***
1000 * Closes a connection.
1001 *
1002 * @param con A Connection to close.
1003 */
1004 public void closeConnection(Connection con)
1005 {
1006 if (con != null)
1007 {
1008 try
1009 {
1010 con.close();
1011 }
1012 catch (SQLException e)
1013 {
1014 log.error("Error occured while closing connection.", e);
1015 }
1016 }
1017 }
1018
1019 /***
1020 * Sets the current schema for a database connection
1021 *
1022 * @param name The database name.
1023 * @param schema The current schema name.
1024 * @throws TorqueException Any exceptions caught during processing will be
1025 * rethrown wrapped into a TorqueException.
1026 */
1027 public void setSchema(String name, String schema)
1028 throws TorqueException
1029 {
1030 getOrCreateDatabase(name).setSchema(schema);
1031 }
1032
1033 /***
1034 * This method returns the current schema for a database connection
1035 *
1036 * @param name The database name.
1037 * @return The current schema name. Null means, no schema has been set.
1038 * @throws TorqueException Any exceptions caught during processing will be
1039 * rethrown wrapped into a TorqueException.
1040 */
1041 public String getSchema(String name)
1042 throws TorqueException
1043 {
1044 Database database = getDatabase(name);
1045 if (database == null)
1046 {
1047 return null;
1048 }
1049 return database.getSchema();
1050 }
1051
1052 /***
1053 * Returns the database for the key <code>databaseName</code>.
1054 *
1055 * @param databaseName the key to get the database for.
1056 * @return the database for the specified key, or null if the database
1057 * does not exist.
1058 * @throws TorqueException if Torque is not yet initialized.
1059 */
1060 public Database getDatabase(String databaseName) throws TorqueException
1061 {
1062 if (!isInit())
1063 {
1064 throw new TorqueException("Torque is not initialized.");
1065 }
1066 return (Database) databases.get(databaseName);
1067 }
1068
1069 /***
1070 * Returns a Map containing all Databases registered to Torque.
1071 * The key of the Map is the name of the database, and the value is the
1072 * database instance. <br/>
1073 * Note that in the very special case where a new database which
1074 * is not configured in Torque's configuration gets known to Torque
1075 * at a later time, the returned map may change, and there is no way to
1076 * protect you against this.
1077 *
1078 * @return a Map containing all Databases known to Torque, never null.
1079 * @throws TorqueException if Torque is not yet initialized.
1080 */
1081 public Map getDatabases() throws TorqueException
1082 {
1083 if (!isInit())
1084 {
1085 throw new TorqueException("Torque is not initialized.");
1086 }
1087 return Collections.unmodifiableMap(databases);
1088 }
1089
1090 /***
1091 * Returns the database for the key <code>databaseName</code>.
1092 * If no database is associated to the specified key,
1093 * a new database is created, mapped to the specified key, and returned.
1094 *
1095 * @param databaseName the key to get the database for.
1096 * @return the database associated with specified key, or the newly created
1097 * database, never null.
1098 */
1099 public Database getOrCreateDatabase(String databaseName)
1100 {
1101 synchronized (databases)
1102 {
1103 Database result = (Database) databases.get(databaseName);
1104 if (result == null)
1105 {
1106 result = new Database(databaseName);
1107 databases.put(databaseName, result);
1108 }
1109 return result;
1110 }
1111 }
1112 }