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

com.tacitknowledge.util.migration.jdbc.DistributedJdbcMigrationLauncherFactory 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.HashMap;
import java.util.List;
import java.util.Properties;

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

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

/**
 * Creates and configures a new DistributedJdbcMigrationContext 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.contextThe context to use for orchestration
systemName.controlled.systemscomma-delimited systems to manage
*

* For each system in the controlled systems list, the properties file should contain * information as directed in the documenation for JdbcMigrationLauncher. * *

* The systemName.listeners property only applies to the top level system name which manages * all the sub-systems. *

* * If a new database node is detected in the migration.properties, the default behaviour is to * stop the patch process. To force the new node to be 'brought up to date' with the other * nodes, then set a system property named 'forcesync'. The value is not important, merely the * existance is sufficient. * * @see com.tacitknowledge.util.migration.jdbc.JdbcMigrationLauncher * @author Mike Hardy ([email protected]) * @author Alex Soto ([email protected]) */ public class DistributedJdbcMigrationLauncherFactory extends JdbcMigrationLauncherFactory { /** Class logger */ private static Log log = LogFactory.getLog(DistributedJdbcMigrationLauncherFactory.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 name of the properties file in the classpath * @return a fully configured DistributedJdbcMigrationLauncher. * @throws MigrationException if an unexpected error occurs */ public JdbcMigrationLauncher createMigrationLauncher(String systemName, String propFile) throws MigrationException { log.info("Creating DistributedJdbcMigrationLauncher for system " + systemName); DistributedJdbcMigrationLauncher launcher = getDistributedJdbcMigrationLauncher(); 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 DistributedJdbcMigrationLauncher. * @throws MigrationException if an unexpected error occurs */ public JdbcMigrationLauncher createMigrationLauncher(String systemName) throws MigrationException { log.info("Creating DistributedJdbcMigrationLauncher for system " + systemName); DistributedJdbcMigrationLauncher launcher = getDistributedJdbcMigrationLauncher(); configureFromMigrationProperties(launcher, systemName, MigrationContext.MIGRATION_CONFIG_FILE); return launcher; } /** * Get a new DistributedJdbcMigrationLauncher * * @return DistributedJdbcMigrationLauncher */ public DistributedJdbcMigrationLauncher getDistributedJdbcMigrationLauncher() { return new DistributedJdbcMigrationLauncher(); } /** * 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 properties file on the classpath * @throws MigrationException if an unexpected error occurs */ private void configureFromMigrationProperties(DistributedJdbcMigrationLauncher 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, propFile); } catch (IOException e) { throw new MigrationException("Error reading in migration properties file", e); } finally { try { is.close(); } catch (IOException ioe) { throw new MigrationException("Error closing migration properties file", ioe); } } } else { throw new MigrationException("Unable to find migration properties file '" + propFile + "'"); } } /** * Configure the launcher from the provided properties, system name * * @param launcher The launcher to configure * @param systemName The name of the system we're configuring * @param props The Properties object with our configuration information * @param propFileName the property file name for configuration * @throws IllegalArgumentException if a required parameter is missing * @throws MigrationException if there is problem setting the context into the launcher */ private void configureFromMigrationProperties(DistributedJdbcMigrationLauncher launcher, String systemName, Properties props, String propFileName) throws IllegalArgumentException, MigrationException { // Get the name of the context to use for our patch information String patchContext = ConfigurationUtil.getRequiredParam(props, systemName + ".context"); // Set up the data source NonPooledDataSource ds = new NonPooledDataSource(); ds.setDriverClass(ConfigurationUtil.getRequiredParam(props, patchContext + ".jdbc.driver")); ds.setDatabaseUrl(ConfigurationUtil.getRequiredParam(props, patchContext + ".jdbc.url")); ds.setUsername(ConfigurationUtil.getRequiredParam(props, patchContext + ".jdbc.username")); ds.setPassword(ConfigurationUtil.getRequiredParam(props, patchContext + ".jdbc.password")); // Get any post-patch task paths launcher.setPostPatchPath(props.getProperty(patchContext + ".postpatch.path")); // See if they want to run in read-only mode launcher.setReadOnly(false); if ("true".equals(props.getProperty(systemName + ".readonly"))) { launcher.setReadOnly(true); } // See if they want to override the lock after a certain amount of time String lockPollRetries = props.getProperty(systemName + ".lockPollRetries"); if (lockPollRetries != null) { launcher.setLockPollRetries(Integer.parseInt(lockPollRetries)); } // see if forcesync specified. Value doesn't matter, just presence of system property enables syncing String forceSync = ConfigurationUtil.getOptionalParam("forcesync", System.getProperties(), null, 0); if(forceSync != null) { ((DistributedMigrationProcess)launcher.getMigrationProcess()).setForceSync(true); } // Set up the JDBC migration context; accepts one of two property names DataSourceMigrationContext context = getDataSourceMigrationContext(); String databaseType = ConfigurationUtil.getRequiredParam(props, patchContext + ".jdbc.database.type", patchContext + ".jdbc.dialect"); context.setDatabaseType(new DatabaseType(databaseType)); // Finish setting up the context context.setSystemName(systemName); context.setDataSource(ds); // setup the user-defined listeners List userDefinedListeners = loadMigrationListeners(systemName, props); launcher.getMigrationProcess().addListeners(userDefinedListeners); // done reading in config, set launcher's context // FIXME only using one context here, would a distributed one ever go into multiple nodes? launcher.addContext(context); // Get our controlled systems, and instantiate their launchers HashMap controlledSystems = new HashMap(); String[] controlledSystemNames = ConfigurationUtil.getRequiredParam(props, systemName + ".controlled.systems").split(","); for (int i = 0; i < controlledSystemNames.length; i++) { log.info("Creating controlled patch executor for system " + controlledSystemNames[i]); JdbcMigrationLauncherFactory factory = JdbcMigrationLauncherFactoryLoader.createFactory(); JdbcMigrationLauncher subLauncher = factory.createMigrationLauncher(controlledSystemNames[i], propFileName); controlledSystems.put(controlledSystemNames[i], subLauncher); // Make sure the controlled migration process gets migration events launcher.getMigrationProcess().addListener(subLauncher); } // communicate our new-found controlled systems to the migration process ((DistributedMigrationProcess) launcher.getMigrationProcess()) .setControlledSystems(controlledSystems); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy