package com.robonobo.core.update;
import static com.robonobo.common.util.FileUtil.*;
import java.io.*;
import java.lang.reflect.Method;
import java.sql.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.PropertyConfigurator;
import com.robonobo.common.exceptions.SeekInnerCalmException;
import com.robonobo.common.serialization.ConfigBeanSerializer;
import com.robonobo.common.util.ByteUtil;
import com.robonobo.common.util.FileUtil;
import com.robonobo.core.service.DbService;
import com.robonobo.mina.external.MinaConfig;
/** Updates the rbnb home dir to the format expected by a new version
*
* @author macavity */
@SuppressWarnings("unused")
public class Updater {
static final int CURRENT_VERSION = 5;
private File homeDir;
Log log = LogFactory.getLog(getClass());
public Updater(File homeDir) {
this.homeDir = homeDir;
}
public void runUpdate() throws IOException {
int v = getVersion();
if (v < CURRENT_VERSION) {
while (v < CURRENT_VERSION) {
int nextV = v + 1;
Method m;
try {
m = Updater.class.getDeclaredMethod("updateVersion" + v + "ToVersion" + nextV);
m.invoke(this);
} catch (Exception e) {
throw new SeekInnerCalmException(e);
}
v = nextV;
}
saveVersion();
}
}
private int getVersion() throws IOException {
File versionFile = new File(homeDir, "version");
if (!versionFile.exists())
return 0;
FileInputStream fis = new FileInputStream(versionFile);
byte[] buf = new byte[16];
int numRead = fis.read(buf);
String versionStr = new String(buf, 0, numRead);
fis.close();
return Integer.parseInt(versionStr.trim());
}
private void saveVersion() throws IOException {
File versionFile = new File(homeDir, "version");
FileOutputStream fos = new FileOutputStream(versionFile);
String versionStr = String.valueOf(CURRENT_VERSION);
fos.write(versionStr.getBytes());
fos.close();
}
private void updateVersion0ToVersion1() {
log.info("Updating robohome dir " + homeDir.getAbsolutePath() + " from version 0 to version 1");
// Just delete the config and db dirs - a bit lazy, but for version 0 it should be ok
File configDir = new File(homeDir, "config");
deleteDirectory(configDir);
File dbDir = new File(homeDir, "db");
deleteDirectory(dbDir);
// log4j props file name changed
File log4jFile = new File(homeDir, "robonobo-log4j.properties");
log4jFile.delete();
}
private void updateVersion1ToVersion2() throws IOException {
log.info("Updating robohome dir " + homeDir.getAbsolutePath() + " from version 1 to version 2");
// Update config settings
ConfigBeanSerializer cbs = new ConfigBeanSerializer();
File configDir = new File(homeDir, "config");
File minaCfgFile = new File(configDir, "mina.cfg");
if (minaCfgFile.exists()) {
MinaConfig oldCfg = cbs.deserializeConfig(MinaConfig.class, minaCfgFile);
MinaConfig newCfg = new MinaConfig();
oldCfg.setBidStrategyClass(newCfg.getBidStrategyClass());
oldCfg.setSourceRequestBatchTime(newCfg.getSourceRequestBatchTime());
cbs.serializeConfig(oldCfg, minaCfgFile);
} else
log.error("Not updating mina config file - it doesn't exist!");
// Nuke dbs - not very optimal, but otherwise we get hsqldb errors as we upgraded hsqldb in this version...
// better to do it now while we have a few users!
File dbDir = new File(homeDir, "db");
if (dbDir.exists()) {
log.info("Nuking db directory...");
FileUtil.deleteDirectory(dbDir);
}
}
private void updateVersion2ToVersion3() throws IOException {
log.info("Updating robohome dir " + homeDir.getAbsolutePath() + " from version 2 to version 3");
String[] stArr = { DbService.CREATE_LIBRARY_KNOWN_TRACKS_TBL, DbService.CREATE_LIBRARY_UNKNOWN_TRACKS_TBL, DbService.CREATE_LIBRARY_INFO_TBL };
try {
updateMetadataDb(stArr);
} catch (SQLException e) {
throw new IOException("Caught SQLException: "+e.getMessage());
}
}
private void updateVersion3ToVersion4() throws IOException {
log.info("Updating robohome dir " + homeDir.getAbsolutePath() + " from version 3 to version 4");
// Update the log4j props to make sure we're using the new rolling appender
File l4jProps = new File(homeDir, "log4j.properties");
InputStream is = getClass().getResourceAsStream("/log4j.props.skel");
OutputStream os = new FileOutputStream(l4jProps);
ByteUtil.streamDump(is, os);
PropertyConfigurator.configureAndWatch(l4jProps.getAbsolutePath());
}
private void updateVersion4ToVersion5() throws IOException {
log.info("Updating robohome dir " + homeDir.getAbsolutePath() + " from version 4 to version 5");
String[] stArr = { DbService.CREATE_SEEN_COMMENTS_TBL };
try {
updateMetadataDb(stArr);
} catch (SQLException e) {
throw new IOException("Caught SQLException: "+e.getMessage());
}
}
private void compactPagesDb() throws SQLException {
String sep = File.separator;
String dbPrefix = homeDir.getAbsolutePath() + sep + "db" + sep + "metadata";
try {
Class.forName("org.hsqldb.jdbcDriver");
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
String dbUrl = "jdbc:hsqldb:file:" + dbPrefix;
File dbPropsFile = new File(dbPrefix + ".properties");
if (dbPropsFile.exists()) {
log.info("Compacting pages db");
Connection conn = DriverManager.getConnection(dbUrl, "sa", "");
Statement st = conn.createStatement();
st.executeUpdate("SHUTDOWN COMPACT");
st.close();
} else
log.info("pages db props does not exist - not updating pages db");
}
private void updateMetadataDb(String[] sqlStatements) throws SQLException {
String sep = File.separator;
String dbPrefix = homeDir.getAbsolutePath() + sep + "db" + sep + "metadata";
try {
Class.forName("org.hsqldb.jdbcDriver");
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
String dbUrl = "jdbc:hsqldb:file:" + dbPrefix;
File dbPropsFile = new File(dbPrefix + ".properties");
if (dbPropsFile.exists()) {
log.info("Updating metadata db with " + sqlStatements.length + " statements");
Connection conn = DriverManager.getConnection(dbUrl, "sa", "");
for (String sql : sqlStatements) {
log.debug("Running: " + sql);
try {
Statement st = conn.createStatement();
st.executeUpdate(sql);
st.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
Statement st = conn.createStatement();
st.executeUpdate("SHUTDOWN COMPACT");
st.close();
} else
log.info("metadata db props does not exist - not updating metadata db");
}
}