/**
* OLAT - Online Learning and Training<br>
* http://www.olat.org
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
* University of Zurich, Switzerland.
* <p>
*/
package org.olat.upgrade;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Iterator;
import java.util.Map;
import java.util.StringTokenizer;
import org.olat.core.commons.persistence.DBFactory;
import org.olat.core.helpers.Settings;
import org.olat.core.logging.StartupException;
/**
*
* <P>
* Initial Date: 15.08.2005 <br>
* @author gnaegi
* @author guido
*/
public class UpgradeManagerImpl extends UpgradeManager {
private String alterDbFilesDir;
private Map<String, String> dbProperties;
/**
* used by spring
*/
public UpgradeManagerImpl(String alterDbFilesDir, Map<String, String> dbProperties) {
this.alterDbFilesDir = alterDbFilesDir;
this.dbProperties = dbProperties;
}
/**
* Execute the pre system init code of all upgrades in the order as they were configured
* in the configuration file
*/
public void doPreSystemInitUpgrades() {
if (Settings.isJUnitTest()) return;
Iterator<OLATUpgrade> iter = upgrades.iterator();
OLATUpgrade upgrade = null;
try {
while (iter.hasNext()) {
upgrade = iter.next();
if (upgrade.doPreSystemInitUpgrade(this))
log.audit("Successfully installed PreSystemInitUpgrade::" + upgrade.getVersion());
//no DB Module is initialized in PreSystemInit State - no intermediate commit necessary.
}
} catch (Throwable e) {
log.warn("Error upgrading PreSystemInitUpgrade::" + upgrade.getVersion(), e);
abort(e);
}
}
/**
* Execute the post system init code of all upgrades in the order as they were configured
* in the configuration file
*/
public void doPostSystemInitUpgrades() {
if (Settings.isJUnitTest()) return;
Iterator<OLATUpgrade> iter = upgrades.iterator();
OLATUpgrade upgrade = null;
try {
while (iter.hasNext()) {
upgrade = iter.next();
if (upgrade.doPostSystemInitUpgrade(this))
log.audit("Successfully installed PostSystemInitUpgrade::" + upgrade.getVersion());
//just in case a doPostSystemInitUpgrade did forget it.
DBFactory.getInstance(false).commitAndCloseSession();
}
} catch (Throwable e) {
DBFactory.getInstance(false).rollbackAndCloseSession();
log.warn("Error upgrading PostSystemInitUpgrade::" + upgrade.getVersion(), e);
abort(e);
}
}
@Override
public void runAlterDbStatements() {
if (Settings.isJUnitTest()) return;
String dialect = null;
if (dbProperties.get("db.dbms").indexOf("mysql") != -1) dialect = "mysql";
if (dbProperties.get("db.dbms").indexOf("postgresql") != -1) dialect = "postgresql";
Connection con = null;
Statement statement = null;
try {
log.audit("+--------------------------------------------------------------+");
log.audit("+... DB upgrade: Starting alter DB statements ...+");
log.audit("+--------------------------------------------------------------+");
Class.forName(dbProperties.get("db.jdbc.driver"));
String dbUrl = dbProperties.get("db.jdbc.url");
String username = dbProperties.get("db.user");
String password = dbProperties.get("db.pass");
con = DriverManager.getConnection(dbUrl, username, password);
if (con == null) {
throw new StartupException("Could not connect to database. Make sure you have the right driver and your database is running. Try 'ant checkdb'", null);
}
//TODO:gs check if I can alter a db statement and report an exception if not (not all users are allowed to do this)
statement = con.createStatement();
Iterator<OLATUpgrade> iter = upgrades.iterator();
OLATUpgrade upgrade = null;
while (iter.hasNext()) {
upgrade = iter.next();
String alterDbStatementsFilename = upgrade.getAlterDbStatements();
if (alterDbStatementsFilename != null) {
UpgradeHistoryData uhd = getUpgradesHistory(upgrade.getVersion());
if (uhd == null) {
// has never been called, initialize
uhd = new UpgradeHistoryData();
}
if (!uhd.getBooleanDataValue(upgrade.TASK_DP_UPGRADE)) {
loadAndExecuteSqlStatements(statement, alterDbStatementsFilename, dialect);
uhd.setBooleanDataValue(upgrade.TASK_DP_UPGRADE, true);
setUpgradesHistory(uhd, upgrade.getVersion());
log.audit("Successfully executed alter DB statements for Version::" + upgrade.getVersion());
}
}
}
} catch (ClassNotFoundException e) {
log.warn("Could not load jdbc driver for database configured in olat_config.xml. Driver: "+ dbProperties.get("db.jdbc.driver"), e);
throw new StartupException("Could not load jdbc driver for database configured in olat_config.xml. Driver: "+ dbProperties.get("db.jdbc.driver"), e);
} catch (SQLException e) {
log.error("Could not upgrade your database!");
throw new StartupException("Could not execute alter db statements.", e);
} catch (Throwable e) {
log.warn("Error executing alter DB statements::", e);
abort(e);
} finally {
try {
if (statement != null) {
statement.close();
}
} catch (SQLException e2){
log.warn("Could not close sql statement", e2);
throw new StartupException("Could not close sql statements.", e2);
} finally {
try {
if (con != null) {
con.close();
}
} catch (SQLException e3){
log.warn("Could not close db connection.", e3);
throw new StartupException("Could not close db connection.", e3);
}
}
}
}
/**
* load file with alter statements and add to batch
* @param statements
* @param alterDbStatements
*/
private void loadAndExecuteSqlStatements(Statement statement, String alterDbStatements, String dialect) {
try {
FileInputStream file = new FileInputStream(alterDbFilesDir+"/database/"+dialect+"/"+alterDbStatements);
DataInputStream in = new DataInputStream(file);
// this might be a good way to take care of the above
//DataInputStream in = new DataInputStream(this.getClass().getClassLoader().getResourceAsStream("database/"+dialect+"/"+alterDbStatements));
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String strLine;
StringBuilder sb = new StringBuilder();
//Read File Line By Line
while ((strLine = br.readLine()) != null) {
if (strLine.length() > 1 && (!strLine.startsWith("--") && !strLine.startsWith("#"))) {
sb.append(strLine.trim());
}
}
StringTokenizer tokenizer = new StringTokenizer(sb.toString(), ";");
String sql = null;
while (tokenizer.hasMoreTokens()) {
try {
sql = tokenizer.nextToken()+";".toLowerCase();
if (sql.startsWith("update") || sql.startsWith("delete") || sql.startsWith("alter") || sql.startsWith("insert")) {
statement.executeUpdate(sql);
} else {
statement.execute(sql);
}
log.info("Successfully upgraded database with the following sql: "+sql);
} catch (SQLException e) {
String msg = e.getMessage();
//stop upgrading database if already done
if (e.getMessage()!= null && (msg.contains("already exists") || msg.contains("Duplicate") || msg.contains("Can't create table") || msg.contains("column/key exists"))) {
log.error("Error while trying to upgrade the database with:("+sql+"). We will continue with upgrading but check the errors manually! Error says:", e);
} else {
log.error("Could not upgrade you database!");
throw new StartupException("Could not add alter db statements to batch.", e);
}
}
}
in.close();
} catch (FileNotFoundException e1) {
log.error("could not find deleteDatabase.sql file!", e1);
abort(e1);
} catch (IOException e) {
log.error("could not read deleteDatabase.sql file!", e);
abort(e);
}
}
}