/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/kernel/trunk/kernel-util/src/main/java/org/sakaiproject/util/conversion/UpgradeSchema.java $
* $Id: UpgradeSchema.java 101634 2011-12-12 16:44:33Z aaronz@vt.edu $
***********************************************************************************
*
* Copyright (c) 2007, 2008 Sakai Foundation
*
* Licensed under the Educational Community 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.opensource.org/licenses/ECL-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.sakaiproject.util.conversion;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import org.apache.commons.dbcp.cpdsadapter.DriverAdapterCPDS;
import org.apache.commons.dbcp.datasources.SharedPoolDataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* @author ieb
*/
public class UpgradeSchema
{
private static final Log log = LogFactory.getLog(UpgradeSchema.class);
private SharedPoolDataSource tds;
public static void main(String[] argv)
{
UpgradeSchema cc = new UpgradeSchema();
String configFile = null;
if (argv.length > 0)
{
configFile = argv[0].trim();
}
log.info("configFile=" + configFile);
try
{
cc.convert(configFile);
}
catch (Exception ex)
{
log.info("Failed to perform conversion ", ex);
}
}
/**
* @throws Exception
* @throws Exception
*/
private void convert(String config) throws IOException
{
Properties p = new Properties();
if (config != null)
{
FileInputStream fin = null;
log.info("Using Config " + config);
try {
fin = new FileInputStream(config);
p.load(fin);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
finally {
if (fin != null) {
try {
fin.close();
} catch (IOException e) {
}
}
}
StringBuilder sb = new StringBuilder();
Object[] keys = p.keySet().toArray();
Arrays.sort(keys);
for (Object k : keys )
{
sb.append("\n " + k + ":" + p.get(k));
}
log.info("Loaded Properties from " + config + " as " + sb.toString());
}
else
{
log.info("Using Default Config: upgradeschema.config");
InputStream is = this.getClass().getResourceAsStream("upgradeschema.config");
if (is != null) {
try {
p.load(is);
StringBuilder sb = new StringBuilder();
Object[] keys = p.keySet().toArray();
Arrays.sort(keys);
for (Object k : keys )
{
sb.append("\n " + k + ":" + p.get(k));
}
log.info("Loaded Default Properties as " + sb.toString());
} catch (IOException e) {
throw new IOException();
} finally {
is.close();
}
}
}
tds = new SharedPoolDataSource();
try {
tds.setConnectionPoolDataSource(getDataSource(p));
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
tds.setMaxActive(10);
tds.setMaxWait(5);
tds.setDefaultAutoCommit(false);
// CheckConnection cc = new CheckConnection();
// cc.check(tds);
List<SchemaConversionDriver> sequence = new ArrayList<SchemaConversionDriver>();
int k = 0;
while(true) {
if ( p.get("convert."+k) != null ) {
SchemaConversionDriver s = new SchemaConversionDriver();
s.load(p, "convert."+k);
sequence.add(s);
k++;
} else {
break;
}
}
doMigrate(sequence);
try {
tds.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void doMigrate(List<SchemaConversionDriver> sequence)
{
try
{
SchemaConversionController scc = new SchemaConversionController();
boolean earlyTerminationRequested = false;
for (SchemaConversionDriver spec : sequence)
{
earlyTerminationRequested = earlyTerminationSignalled(spec.getEarlyTerminationSignal());
if(earlyTerminationRequested)
{
log.info("Early termination requested");
break;
}
Class<?> handlerClass = Class.forName(spec.getHandlerClass());
SchemaConversionHandler sch = (SchemaConversionHandler) handlerClass
.newInstance();
log.info("Migrating using Handler " + spec.getHandler());
int k = 0;
scc.init(tds, sch, spec);
log.info("UpdateRecord query == " + spec.getUpdateRecord());
while (scc.migrate(tds, sch, spec)) {
log.info("Completed Batch "+(k++));
earlyTerminationRequested = earlyTerminationSignalled(spec.getEarlyTerminationSignal());
if(earlyTerminationRequested)
{
log.info("Early termination requested");
break;
}
}
if(earlyTerminationRequested)
{
break;
}
log.info("Done Migrating using Handler " + spec.getHandler());
}
}
catch (Exception ex)
{
log.info("Failed ", ex);
}
}
/**
* Make it easy to target the local database. Data source properties
* are searched in the following order, with the first match winning:
* <ul>
* <li> A Java system property named "sakai.properties" which will be used to load a
* properties file containing property names such as "url@javax.sql.BaseDataSource".
* <li> Input configProperties named "dbDriver", "dbURL", "dbUser", and "dbPass".
* </ul>
* (Side note: this configuration logic would be easy to externalize with Spring.)
* @param configProperties
*/
private DriverAdapterCPDS getDataSource(Properties configProperties) throws ClassNotFoundException
{
String dbDriver = null;
String dbUrl = null;
String dbUser = null;
String dbPassword = null;
String sakaiPropertiesPath = System.getProperty("sakai.properties");
if (sakaiPropertiesPath != null)
{
File sakaiPropertiesFile = new File(sakaiPropertiesPath);
if (sakaiPropertiesFile.exists())
{
FileInputStream sakaiPropertiesInput = null;
try {
sakaiPropertiesInput = new FileInputStream(sakaiPropertiesFile);
Properties sakaiProperties = new Properties();
sakaiProperties.load(sakaiPropertiesInput);
sakaiPropertiesInput.close();
dbDriver = sakaiProperties.getProperty("driverClassName@javax.sql.BaseDataSource");
dbUrl = sakaiProperties.getProperty("url@javax.sql.BaseDataSource");
dbUser = sakaiProperties.getProperty("username@javax.sql.BaseDataSource");
dbPassword = sakaiProperties.getProperty("password@javax.sql.BaseDataSource");
} catch (IOException e) {
log.info("Error loading properties from " + sakaiPropertiesFile.getAbsolutePath());
}
finally {
if (sakaiPropertiesInput != null) {
try {
sakaiPropertiesInput.close();
} catch (IOException e) {
}
}
}
}
}
if (dbDriver == null) dbDriver = configProperties.getProperty("dbDriver");
if (dbUrl == null) dbUrl = configProperties.getProperty("dbURL");
if (dbUser == null)dbUser = configProperties.getProperty("dbUser");
if (dbPassword == null) dbPassword = configProperties.getProperty("dbPass");
DriverAdapterCPDS cpds = new DriverAdapterCPDS();
try {
cpds.setDriver(dbDriver);
} catch (ClassNotFoundException e) {
throw new ClassNotFoundException();
}
cpds.setUrl(dbUrl);
cpds.setUser(dbUser);
cpds.setPassword(dbPassword);
return cpds;
}
private boolean earlyTerminationSignalled(String earlyEndSignal)
{
boolean endNow = false;
if(earlyEndSignal != null)
{
File file = new File(earlyEndSignal);
log.info("Checking for early termination: " + file.getAbsolutePath());
endNow = file.exists();
}
return endNow;
}
}