All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.tacitknowledge.util.migration.jdbc.JdbcMigrationLauncherFactory Maven / Gradle / Ivy

There is a newer version: 1.4.2
Show newest version
/* Copyright 2004 Tacit Knowledge
 *  
 * 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 com.tacitknowledge.util.migration.jdbc;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletContextEvent;
import javax.sql.DataSource;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.tacitknowledge.util.migration.MigrationContext;
import com.tacitknowledge.util.migration.MigrationException;
import com.tacitknowledge.util.migration.MigrationListener;
import com.tacitknowledge.util.migration.jdbc.util.ConfigurationUtil;
import com.tacitknowledge.util.migration.jdbc.util.NonPooledDataSource;

/**
 * Creates and configures new JdbcMigrationContext objects based on the values
 * in the migration.properties file for the given system.  This is a convenience
 * class for systems that need to initialize the autopatch framework but do not to or can not
 * configure the framework themselves.
 * 

* This factory expects a file named migration.properties to be in the root of the * class path. This file must contain these properties (where systemName is the name of * the system being patched): *

* * * * * * * * *
Keydescription
systemName.patch.path
systemName.jdbc.database.typeThe database type; also accepts systemName.jdbc.dialect
systemName.jdbc.driverThe JDBC driver to use
systemName.jdbc.urlThe JDBC URL to the database
systemName.jdbc.usernameThe database user name
systemName.jdbc.passwordThe database password
*

* Optional properties include: *

* * * * * * *
systemName.postpatch.path
systemName.readonlyboolean true to skip patch application
systemName.jdbc.systemsSet of names for multiple JDBC connections that * should all have patches applied. Names will be * looked up in the same properties file as * systemName.jdbcname.database.type, where * all of the jdbc entries above should be present
systemName.listenersComma separated list of fully qualified java class names that implement {@link MigrationListener}
* * @author Scott Askew ([email protected]) * @author Alex Soto ([email protected]) */ public class JdbcMigrationLauncherFactory { /** Class logger */ private static Log log = LogFactory.getLog(JdbcMigrationLauncherFactory.class); /** * Creates and configures a new JdbcMigrationLauncher based on the * values in the migration.properties file for the given system. * * @param systemName the system to patch * @param propFile the name of the property file to configure from * @return a fully configured JdbcMigrationLauncher. * @throws MigrationException if an unexpected error occurs */ public JdbcMigrationLauncher createMigrationLauncher(String systemName, String propFile) throws MigrationException { log.info("Creating JdbcMigrationLauncher for system " + systemName); JdbcMigrationLauncher launcher = getJdbcMigrationLauncher(); configureFromMigrationProperties(launcher, systemName, propFile); return launcher; } /** * Creates and configures a new JdbcMigrationLauncher based on the * values in the migration.properties file for the given system. * * @param systemName the system to patch * @return a fully configured JdbcMigrationLauncher. * @throws MigrationException if an unexpected error occurs */ public JdbcMigrationLauncher createMigrationLauncher(String systemName) throws MigrationException { log.info("Creating JdbcMigrationLauncher for system " + systemName); JdbcMigrationLauncher launcher = getJdbcMigrationLauncher(); configureFromMigrationProperties(launcher, systemName); return launcher; } /** * Creates and configures a new JdbcMigrationLauncher based on the * values in the servlet context and JNDI for a web-application. * * @param sce the name of the context event to use in getting properties * @return a fully configured JdbcMigrationLauncher. * @throws MigrationException if an unexpected error occurs */ public JdbcMigrationLauncher createMigrationLauncher(ServletContextEvent sce) throws MigrationException { JdbcMigrationLauncher launcher = getJdbcMigrationLauncher(); configureFromServletContext(launcher, sce); return launcher; } /** * Used to configure the migration launcher with properties from a servlet * context. You do not need migration.properties to use this method. * * @param launcher the launcher to configure * @param sce the event to get the context and associated parameters from * @throws MigrationException if a problem with the look up in JNDI occurs */ private void configureFromServletContext(JdbcMigrationLauncher launcher, ServletContextEvent sce) throws MigrationException { String readOnly = sce.getServletContext().getInitParameter("migration.readonly"); launcher.setReadOnly(false); if ("true".equals(readOnly)) { launcher.setReadOnly(true); } // See if they want to override the lock after a certain amount of time String lockPollRetries = sce.getServletContext().getInitParameter("migration.lockPollRetries"); if (lockPollRetries != null) { launcher.setLockPollRetries(Integer.parseInt(lockPollRetries)); } String patchPath = ConfigurationUtil.getRequiredParam("migration.patchpath", sce, this); launcher.setPatchPath(patchPath); String postPatchPath = sce.getServletContext().getInitParameter("migration.postpatchpath"); launcher.setPostPatchPath(postPatchPath); String databases = sce.getServletContext().getInitParameter("migration.jdbc.systems"); String[] databaseNames; if ((databases == null) || "".equals(databases)) { databaseNames = new String[1]; databaseNames[0] = ""; log.debug("jdbc.systems was null or empty, not multi-node"); } else { databaseNames = databases.split(","); log.debug("jdbc.systems was set to " + databases + ", configuring multi-node"); } for (int i = 0; i < databaseNames.length; i++) { String databaseName = databaseNames[i]; if (databaseName != "") { databaseName = databaseName + "."; } String databaseType = ConfigurationUtil.getRequiredParam("migration." + databaseName + "databasetype", sce, this); String systemName = ConfigurationUtil.getRequiredParam("migration.systemname", sce, this); String dataSource = ConfigurationUtil.getRequiredParam("migration." + databaseName + "datasource", sce, this); DataSourceMigrationContext context = getDataSourceMigrationContext(); context.setSystemName(systemName); context.setDatabaseType(new DatabaseType(databaseType)); try { Context ctx = new InitialContext(); if (ctx == null) { throw new IllegalArgumentException("A jndi context must be " + "present to use this configuration."); } DataSource ds = (DataSource) ctx.lookup("java:comp/env/" + dataSource); context.setDataSource(ds); log.debug("adding context with datasource " + dataSource + " of type " + databaseType); launcher.addContext(context); } catch (NamingException e) { throw new MigrationException("Problem with JNDI look up of " + dataSource, e); } } } /** * Loads the configuration from the migration config properties file. * * @param launcher the launcher to configure * @param systemName the name of the system * @throws MigrationException if an unexpected error occurs */ private void configureFromMigrationProperties(JdbcMigrationLauncher launcher, String systemName) throws MigrationException { configureFromMigrationProperties(launcher, systemName, MigrationContext.MIGRATION_CONFIG_FILE); } /** * Loads the configuration from the migration config properties file. * * @param launcher the launcher to configure * @param systemName the name of the system * @param propFile the name of the prop file to configure from * @throws MigrationException if an unexpected error occurs */ private void configureFromMigrationProperties(JdbcMigrationLauncher launcher, String systemName, String propFile) throws MigrationException { ClassLoader cl = Thread.currentThread().getContextClassLoader(); InputStream is = cl.getResourceAsStream(propFile); if (is != null) { try { Properties props = new Properties(); props.load(is); configureFromMigrationProperties(launcher, systemName, props); } catch (IOException e) { throw new MigrationException("Error reading in autopatch properties file", e); } finally { try { is.close(); } catch (IOException ioe) { throw new MigrationException("Error closing autopatch properties file", ioe); } } } else { throw new MigrationException("Unable to find autopatch properties file '" + propFile + "'"); } } /** * Configure the launcher from the provided properties, system name * * @param launcher The launcher to configure * @param system The name of the system we're configuring * @param props The Properties object with our configuration information * @throws IllegalArgumentException if a required parameter is missing * @throws MigrationException */ private void configureFromMigrationProperties(JdbcMigrationLauncher launcher, String system, Properties props) throws IllegalArgumentException, MigrationException { launcher.setPatchPath(ConfigurationUtil.getRequiredParam(props, system + ".patch.path")); launcher.setPostPatchPath(props.getProperty(system + ".postpatch.path")); launcher.setReadOnly(false); if ("true".equals(props.getProperty(system + ".readonly"))) { launcher.setReadOnly(true); } // See if they want to override the lock after a certain amount of time String lockPollRetries = props.getProperty(system + ".lockPollRetries"); if (lockPollRetries != null) { launcher.setLockPollRetries(Integer.parseInt(lockPollRetries)); } // TODO refactor the database name extraction from this and the servlet example String databases = props.getProperty(system + ".jdbc.systems"); String[] databaseNames; if ((databases == null) || "".equals(databases)) { databaseNames = new String[1]; databaseNames[0] = "jdbc"; } else { databaseNames = databases.split(","); } for (int i = 0; i < databaseNames.length; i++) { String db = databaseNames[i]; if (db != "") { db = "." + db; } // Set up the data source NonPooledDataSource dataSource = new NonPooledDataSource(); dataSource.setDriverClass(ConfigurationUtil.getRequiredParam(props, system + db + ".driver")); dataSource.setDatabaseUrl(ConfigurationUtil.getRequiredParam(props, system + db + ".url")); dataSource.setUsername(ConfigurationUtil.getRequiredParam(props, system + db + ".username")); dataSource.setPassword(ConfigurationUtil.getRequiredParam(props, system + db + ".password")); // Set up the JDBC migration context; accepts one of two property names DataSourceMigrationContext context = getDataSourceMigrationContext(); String databaseType = ConfigurationUtil.getRequiredParam(props, system + db + ".database.type", system + db + ".dialect"); log.debug("setting type to " + databaseType); context.setDatabaseType(new DatabaseType(databaseType)); context.setDatabaseName(databaseNames[i]); // Finish setting up the context context.setSystemName(system); context.setDataSource(dataSource); // setup the user-defined listeners List userDefinedListeners = loadMigrationListeners(system, props); launcher.getMigrationProcess().addListeners(userDefinedListeners); // done reading in config, set launcher's context launcher.addContext(context); } } /** * Get a DataSourceMigrationContext * * @return DataSourceMigrationContext for use with the launcher */ public DataSourceMigrationContext getDataSourceMigrationContext() { return new DataSourceMigrationContext(); } /** * Get a JdbcMigrationLauncher * * @return JdbcMigrationLauncher */ public JdbcMigrationLauncher getJdbcMigrationLauncher() { return new JdbcMigrationLauncher(); } /** * Returns a list of MigrationListeners for the systemName specified in the properties. * @param systemName The name of the system to load MigrationListeners for. * @param properties The properties that has migration listeners specified. * @return A List of zero or more MigrationListeners * @throws MigrationException if unable to load listeners. */ protected List loadMigrationListeners(String systemName, Properties properties) throws MigrationException { try { List listeners = new ArrayList(); String[] listenerClassNames = null; String commaSeparatedList = properties.getProperty(systemName + ".listeners"); // if it's blank, then no listeners configured if(StringUtils.isNotBlank(commaSeparatedList)) { listenerClassNames = commaSeparatedList.split(","); for(Iterator it = Arrays.asList(listenerClassNames).iterator(); it.hasNext(); ) { String className = ((String) it.next()).trim(); // if it's blank, then there is likely a leading or trailing comma if(StringUtils.isNotBlank(className)) { Class c = Class.forName(className); MigrationListener listener = (MigrationListener) c.newInstance(); listener.initialize(systemName, properties); listeners.add(listener); } } } return listeners; } catch(Exception e) { throw new MigrationException("Exception while loading migration listeners", e); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy