org.castor.jdo.engine.DatabaseRegistry.java Source code

Java tutorial

Introduction

Here is the source code for org.castor.jdo.engine.DatabaseRegistry.java

Source

/*
 * Copyright 2005 Ralf Joachim
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.castor.jdo.engine;

import java.util.Hashtable;

import javax.sql.DataSource;
import javax.transaction.TransactionManager;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.castor.core.util.AbstractProperties;
import org.castor.core.util.Messages;
import org.castor.cpa.CPAProperties;
import org.castor.cpa.persistence.sql.connection.ConnectionFactory;
import org.castor.cpa.persistence.sql.connection.DataSourceConnectionFactory;
import org.castor.cpa.persistence.sql.connection.DriverConnectionFactory;
import org.castor.cpa.persistence.sql.connection.JNDIConnectionFactory;
import org.castor.cpa.util.JDOClassDescriptorResolver;
import org.castor.jdo.conf.Database;
import org.castor.jdo.conf.DatabaseChoice;
import org.castor.jdo.conf.JdoConf;
import org.castor.jdo.util.JDOConfFactory;
import org.exolab.castor.mapping.Mapping;
import org.exolab.castor.mapping.MappingException;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;

/**
 * @author <a href="arkin@intalio.com">Assaf Arkin</a>
 * @author <a href="mailto:ferret AT frii dot com">Bruce Snyder</a>
 * @author <a href="mailto:ralf DOT joachim AT syscon DOT eu">Ralf Joachim</a>
 * @version $Revision$ $Date$
 * @since 0.9.9
 */
public final class DatabaseRegistry {

    /** The <a href="http://jakarta.apache.org/commons/logging/">Jakarta
     *  Commons Logging</a> instance used for all logging. */
    private static final Log LOG = LogFactory.getLog(DatabaseRegistry.class);

    /** Map of all registered connection factories by name. */
    private static final Hashtable CONTEXTS = new Hashtable();

    /**
     * Instantiates a DataSourceConnectionFactory with given name, engine, datasource
     * and mapping.
     * 
     * @param name       The Name of the database configuration.
     * @param engine     The Name of the persistence factory to use.
     * @param datasource The preconfigured datasource to use for creating connections.
     * @param mapping    The previously loaded mapping.
     * @param txManager  The transaction manager to use.
     * @throws MappingException If LockEngine could not be initialized.
     */
    public static synchronized void loadDatabase(final String name, final String engine,
            final DataSource datasource, final Mapping mapping, final TransactionManager txManager)
            throws MappingException {
        boolean useProxies = CPAProperties.getInstance().getBoolean(CPAProperties.USE_JDBC_PROXIES, true);

        ConnectionFactory cf = new DataSourceConnectionFactory(datasource, useProxies);
        DatabaseContext context = new DatabaseContext(name, engine, mapping, txManager, cf);

        if (CONTEXTS.put(name, context) != null) {
            LOG.warn(Messages.format("jdo.configLoadedTwice", name));
        }
    }

    /**
     * Instantiates a ConnectionFactory from the JDO configuration file.
     * 
     * @param  source   {@link InputSource} pointing to the JDO configuration. 
     * @param  resolver An entity resolver.
     * @param  loader   A class loader
     * @throws MappingException If the database cannot be instantiated/loadeed.
     */
    public static synchronized void loadDatabase(final InputSource source, final EntityResolver resolver,
            final ClassLoader loader) throws MappingException {
        loadDatabase(source, resolver, loader, null);
    }

    /**
     * Instantiates a ConnectionFactory from the JDO configuration file.
     * 
     * @param source
     *                {@link InputSource} pointing to the JDO configuration.
     * @param resolver
     *                An entity resolver.
     * @param loader
     *                A class loader
     * @param classDescriptorResolver
     *                {@link ClassDescriptorResolver} used for class to class
     *                descriptor resolution.
     * @throws MappingException
     *                 If the database cannot be instantiated/loaded.
     */
    public static synchronized void loadDatabase(final InputSource source, final EntityResolver resolver,
            final ClassLoader loader, final JDOClassDescriptorResolver classDescriptorResolver)
            throws MappingException {

        // Load the JDO configuration file from the specified input source.
        JdoConf jdoConf = null;
        jdoConf = JDOConfFactory.createJdoConf(source, resolver, loader);
        LOG.debug("Loaded jdo conf successfully");

        loadDatabase(jdoConf, resolver, loader, source.getSystemId(), classDescriptorResolver);
    }

    /**
     * Creates a entry for every database and associates them with their name in a
     * map. It then instantiates all databases if
     * 'org.exolab.castor.jdo.DatabaseInitializeAtLoad' key can not be found or is
     * set to <code>true</code> in castor.properties file. If above property is set
     * to <code>false</code> it will instantiate all databases only when they are
     * needed.
     * 
     * @param  jdoConf      An in-memory jdo configuration. 
     * @param  resolver     An entity resolver.
     * @param  loader       A class loader
     * @param  baseURI      The base URL for the mapping
     * @throws MappingException If the database cannot be instantiated/loadeed.
     */
    public static synchronized void loadDatabase(final JdoConf jdoConf, final EntityResolver resolver,
            final ClassLoader loader, final String baseURI) throws MappingException {
        loadDatabase(jdoConf, resolver, loader, baseURI, null);
    }

    /**
     * Creates a entry for every database and associates them with their name in
     * a map. It then instantiates all databases if
     * 'org.exolab.castor.jdo.DatabaseInitializeAtLoad' key can not be found or
     * is set to <code>true</code> in castor.properties file. If above
     * property is set to <code>false</code> it will instantiate all databases
     * only when they are needed.
     * 
     * @param jdoConf
     *                An in-memory jdo configuration.
     * @param resolver
     *                An entity resolver.
     * @param loader
     *                A class loader
     * @param baseURI
     *                The base URL for the mapping
     * @param classDescriptorResolver
     *                {@link ClassDescriptorResolver} used for class to class
     *                descriptor resolution.
     * @throws MappingException
     *                 If the database cannot be instantiated/loadeed.
     */
    public static synchronized void loadDatabase(final JdoConf jdoConf, final EntityResolver resolver,
            final ClassLoader loader, final String baseURI,
            final JDOClassDescriptorResolver classDescriptorResolver) throws MappingException {
        // Do we need to initialize database now or should we
        // wait until we want to use it.
        AbstractProperties properties = CPAProperties.getInstance();
        boolean init = properties.getBoolean(CPAProperties.INITIALIZE_AT_LOAD, true);

        // Load the JDO configuration file from the specified input source.
        // databases = JDOConfLoader.getDatabases(baseURI, resolver);
        Database[] databases = jdoConf.getDatabase();
        DatabaseContext context;
        for (int i = 0; i < databases.length; i++) {
            // Load the mapping file from the URL specified in the database
            // configuration file, relative to the configuration file.
            // Fail if cannot load the mapping for whatever reason.
            Mapping mapping = new Mapping(loader);
            if (resolver != null) {
                mapping.setEntityResolver(resolver);
            }
            if (baseURI != null) {
                mapping.setBaseURL(baseURI);
            }

            context = DatabaseRegistry.createDatabaseContext(jdoConf, i, mapping);
            context.setClassDescriptorResolver(classDescriptorResolver);
            if (init) {
                context.initialize();
            }
            String name = databases[i].getName();
            if (CONTEXTS.put(name, context) != null) {
                LOG.warn(Messages.format("jdo.configLoadedTwice", name));
            }
        }
    }

    /**
     * Factory methode to create a ConnectionFactory for given database configuration
     * and given mapping.
     * 
     * @param jdoConf   An in-memory jdo configuration. 
     * @param index     Index of the database configuration inside the jdo configuration.
     * @param mapping   The mapping to load.
     * @return The ConnectionFactory.
     * @throws MappingException If the database cannot be instantiated/loadeed.
     */
    private static DatabaseContext createDatabaseContext(final JdoConf jdoConf, final int index,
            final Mapping mapping) throws MappingException {
        boolean useProxies = CPAProperties.getInstance().getBoolean(CPAProperties.USE_JDBC_PROXIES, true);

        ConnectionFactory factory;

        DatabaseChoice choice = jdoConf.getDatabase(index).getDatabaseChoice();
        if (choice == null) {
            String name = jdoConf.getDatabase(index).getName();
            String msg = Messages.format("jdo.missingDataSource", name);
            LOG.error(msg);
            throw new MappingException(msg);
        }

        if (choice.getDriver() != null) {
            // JDO configuration file specifies a driver, use the driver
            // properties to create a new registry object.
            factory = new DriverConnectionFactory(choice.getDriver(), useProxies);
        } else if (choice.getDataSource() != null) {
            // JDO configuration file specifies a DataSource object, use the
            // DataSource which was configured from the JDO configuration file
            // to create a new registry object.
            ClassLoader loader = mapping.getClassLoader();
            factory = new DataSourceConnectionFactory(choice.getDataSource(), useProxies, loader);
        } else if (choice.getJndi() != null) {
            // JDO configuration file specifies a DataSource lookup through JNDI, 
            // locate the DataSource object frome the JNDI namespace and use it.
            factory = new JNDIConnectionFactory(choice.getJndi(), useProxies);
        } else {
            String name = jdoConf.getDatabase(index).getName();
            String msg = Messages.format("jdo.missingDataSource", name);
            LOG.error(msg);
            throw new MappingException(msg);
        }

        return new DatabaseContext(jdoConf, index, mapping, factory);
    }

    /**
     * Check if any database configuration has been loaded.
     * 
     * @return <code>true</code> if a databases configuration has been loaded.
     */
    public static boolean hasDatabaseRegistries() {
        return (!CONTEXTS.isEmpty());
    }

    /**
     * Check if database configuration with given name has been loaded.
     * 
     * @param  name     Name of the database to check if loaded.
     * @return <code>true</code> if databases configuration has been loaded.
     */
    public static boolean isDatabaseRegistred(final String name) {
        return CONTEXTS.containsKey(name);
    }

    /**
     * Get the ConnectionFactory for the given database name.
     * 
     * @param  name     Name of the database configuration.
     * @return The ConnectionFactory for the given database name.
     * @throws MappingException If database can not be instantiated.
     */
    public static DatabaseContext getDatabaseContext(final String name) throws MappingException {
        if (LOG.isDebugEnabled()) {
            LOG.debug("Fetching ConnectionFactory: " + name);
        }

        DatabaseContext context = (DatabaseContext) CONTEXTS.get(name);

        if (context == null) {
            String msg = Messages.format("jdo.missingDataSource", name);
            LOG.error(msg);
            throw new MappingException(msg);
        }

        context.initialize();
        return context;
    }

    /**
     * Reset all database configurations.
     */
    public static void clear() {
        CONTEXTS.clear();
    }

    /**
     * Unload the database configuration with given name.
     * 
     * @param  name     Name of the database to be unloaded.
     */
    public static void unloadDatabase(final String name) {
        CONTEXTS.remove(name);
    }

    /**
     * Hide constructor of utility class.
     */
    private DatabaseRegistry() {
    }

}