/** * 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. * <hr> * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * This file has been modified by the OpenOLAT community. Changes are licensed * under the Apache 2.0 license as the original file. */ package org.olat.upgrade; import java.io.File; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.sql.DataSource; import org.olat.core.commons.persistence.DBFactory; import org.olat.core.configuration.Initializable; import org.olat.core.gui.control.Event; import org.olat.core.logging.AssertException; import org.olat.core.logging.StartupException; import org.olat.core.manager.BasicManager; import org.olat.core.util.WebappHelper; import org.olat.core.util.event.FrameworkStartedEvent; import org.olat.core.util.event.FrameworkStartupEventChannel; import org.olat.core.util.event.GenericEventListener; import org.olat.core.util.xml.XStreamHelper; /** * * Description:<br> * Class to execute upgrade code during system startup. The idea is to * have a place in the code where you can manage your migration code that is * necessary because of new code or because of buggy old code that left some dead * stuff in the database or the fileSystem. * * * <P> * Initial Date: 11.09.2008 <br> * @author guido */ public abstract class UpgradeManager extends BasicManager implements Initializable, GenericEventListener { protected String INSTALLED_UPGRADES_XML = "installed_upgrades.xml"; public static final String SYSTEM_DIR = "system"; private DataSource dataSource; protected List<OLATUpgrade> upgrades; protected Map<String, UpgradeHistoryData> upgradesHistories; protected UpgradesDefinitions upgradesDefinitions; protected boolean needsUpgrade = true; public DataSource getDataSource() { return dataSource; } /** * [used by spring] * @param dataSource */ public void setDataSource (DataSource dataSource) { this.dataSource = dataSource; } /** * [used by spring] * @param upgradesDefinitions */ public void setUpgradesDefinitions(UpgradesDefinitions upgradesDefinitions) { this.upgradesDefinitions = upgradesDefinitions; } /** * Initialize the upgrade manager: get all upgrades from the configuration file and load * the upgrade history from the olatdata directory */ public void init() { //register for framework starup event FrameworkStartupEventChannel.registerForStartupEvent(this); // load upgrades using spring framework upgrades = upgradesDefinitions.getUpgrades(); // load history of previous upgrades using xstream initUpgradesHistories(); if (needsUpgrade) { boolean sevenOrNewer = false; for(OLATUpgrade upgrade:upgradesDefinitions.getUpgrades()) { if(upgrade.getVersion().startsWith("OLAT_7") || upgrade.getVersion().startsWith("OLAT_8")) { sevenOrNewer = true; } } if(!sevenOrNewer) { throw new AssertException("Upgrade first your installtion to OLAT 7.0 and after go with OpenOLAT"); } doPreSystemInitUpgrades(); //post system init task are triggered by an event DBFactory.getInstance().commitAndCloseSession(); } } /** * Execute the pre system init code of all upgrades in the order as they were configured * in the configuration file */ public abstract void doPreSystemInitUpgrades(); /** * Execute the post system init code of all upgrades in the order as they were configured * in the configuration file */ public abstract void doPostSystemInitUpgrades(); /** * @param version identifier of UpgradeHistoryData * @return UpgradeHistoryData of the given version or null if no such history object exists */ public UpgradeHistoryData getUpgradesHistory(String version) { return upgradesHistories.get(version); } /** * Persists the UpgradeHistoryData on the file system * @param upgradeHistoryData UpgradeHistoryData of the given version * @param version identifier of UpgradeHistoryData */ public void setUpgradesHistory(UpgradeHistoryData upgradeHistoryData, String version) { this.upgradesHistories.put(version, upgradeHistoryData); File upgradesDir = new File(WebappHelper.getUserDataRoot(), SYSTEM_DIR); upgradesDir.mkdirs(); // create if not exists File upgradesHistoriesFile = new File(upgradesDir, INSTALLED_UPGRADES_XML); XStreamHelper.writeObject(upgradesHistoriesFile, this.upgradesHistories); } /** * Load all persisted UpgradeHistoryData objects from the fileSystem */ @SuppressWarnings("unchecked") protected void initUpgradesHistories() { File upgradesDir = new File(WebappHelper.getUserDataRoot(), SYSTEM_DIR); File upgradesHistoriesFile = new File(upgradesDir, INSTALLED_UPGRADES_XML); if (upgradesHistoriesFile.exists()) { this.upgradesHistories = (Map<String, UpgradeHistoryData>) XStreamHelper.createXStreamInstance().fromXML(upgradesHistoriesFile); } else { if (this.upgradesHistories == null) { this.upgradesHistories = new HashMap<String, UpgradeHistoryData>(); } needsUpgrade = false; //looks like a new install, no upgrade necessary logInfo("This looks like a new install or droped data, will not do any upgrades."); createUpgradeData(); } } /** * create fake upgrade data as this is a new installation */ protected void createUpgradeData() { for (OLATUpgrade upgrade: upgrades) { UpgradeHistoryData uhd = new UpgradeHistoryData(); uhd.setInstallationComplete(true); uhd.setBooleanDataValue(OLATUpgrade.TASK_DP_UPGRADE, true); setUpgradesHistory(uhd, upgrade.getVersion()); } } /** * On any RuntimeExceptions during init. Abort loading of application. * Modules should throw RuntimeExceptions if they can't live with a the * given state of configuration. * @param e */ protected void abort(Throwable e) { if (e instanceof StartupException) { StartupException se = (StartupException) e; logWarn("Message: " + se.getLogMsg(), se); Throwable cause = se.getCause(); logWarn("Cause: " + (cause != null ? cause.getMessage() : "n/a"), se); } throw new RuntimeException("*** CRITICAL ERROR IN UPGRADE MANAGER. Loading aborted.", e); } @Override public void event(Event event) { if (event instanceof FrameworkStartedEvent) { doPostSystemInitUpgrades(); } } }