/* * This library is part of OpenCms - * the Open Source Content Management System * * Copyright (c) Alkacon Software GmbH (http://www.alkacon.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * For further information about Alkacon Software GmbH, please see the * company website: http://www.alkacon.com * * For further information about OpenCms, please see the * project website: http://www.opencms.org * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.opencms.setup.db; import org.opencms.configuration.CmsParameterConfiguration; import org.opencms.setup.CmsSetupDBWrapper; import org.opencms.setup.CmsSetupDb; import org.opencms.setup.CmsUpdateBean; import org.opencms.util.CmsStringUtil; import org.opencms.util.CmsUUID; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; /** * This manager controls the update of the database from OpenCms 6 to OpenCms 7.<p> * * @since 7.0.0 */ public class CmsUpdateDBManager { /** The database name. */ private String m_dbName; /** The pools connection data. */ private Map<String, Map<String, String>> m_dbPools = new HashMap<String, Map<String, String>>(); /** The detected mayor version, based on DB structure. */ private int m_detectedVersion; /** List of xml update plugins. */ private List<I_CmsUpdateDBPart> m_plugins; /** * Default constructor.<p> */ public CmsUpdateDBManager() { // no-op } /** * Returns the configured jdbc driver for the given pool.<p> * * @param pool the db pool to get the driver for * * @return the driver class name */ public String getDbDriver(String pool) { return m_dbPools.get(pool).get("driver"); } /** * Returns the database name.<p> * * @return the database name */ public String getDbName() { return m_dbName; } /** * Returns the configured jdbc url parameters for the given pool.<p> * * @param pool the db pool to get the params for * * @return the jdbc url parameters */ public String getDbParams(String pool) { return m_dbPools.get(pool).get("params"); } /** * Returns the configured jdbc connection url for the given pool.<p> * * @param pool the db pool to get the url for * * @return the jdbc connection url */ public String getDbUrl(String pool) { return m_dbPools.get(pool).get("url"); } /** * Returns the configured database user for the given pool.<p> * * @param pool the db pool to get the user for * * @return the database user */ public String getDbUser(String pool) { return m_dbPools.get(pool).get("user"); } /** * Returns the detected mayor version, based on DB structure.<p> * * @return the detected mayor version */ public int getDetectedVersion() { if (m_detectedVersion == 0) { needUpdate(); } return m_detectedVersion; } /** * Returns all configured database pools.<p> * * @return a list of {@link String} objects */ public List<String> getPools() { return new ArrayList<String>(m_dbPools.keySet()); } /** * Generates html code for the given db pool.<p> * * @param pool the db pool to generate html for * * @return html code * * @throws Exception if something goes wrong */ public String htmlPool(String pool) throws Exception { StringBuffer html = new StringBuffer(256); html.append("<a href=\"javascript:switchview('").append(pool).append("');\">"); html.append(pool).append("</a><br>\n"); html.append("\t<div id='").append(pool).append("' style='display: none;'>\n"); html.append("\t\t<table border='0'>\n"); html.append("\t\t\t<tr><td>JDBC Driver:</td><td>" + getDbDriver(pool) + "</td></tr>\n"); html.append("\t\t\t<tr><td>JDBC Connection Url:</td><td>" + getDbUrl(pool) + "</td></tr>\n"); html.append("\t\t\t<tr><td>JDBC Connection Url Params:</td><td>" + getDbParams(pool) + "</td></tr>\n"); html.append("\t\t\t<tr><td>Database User:</td><td>" + getDbUser(pool) + "</td></tr>\n"); html.append("\t\t</table>\n"); html.append("\t</div>\n"); return html.toString(); } /** * Initializes the Update Manager object with the updateBean to get the database connection.<p> * * @param updateBean the update bean with the database connection * * @throws Exception if the setup bean is not initialized */ public void initialize(CmsUpdateBean updateBean) throws Exception { if (updateBean.isInitialized()) { CmsParameterConfiguration props = updateBean.getProperties(); // Initialize the CmsUUID generator. CmsUUID.init(props.get("server.ethernet.address")); m_dbName = props.get("db.name"); List<String> pools = CmsStringUtil.splitAsList(props.get("db.pools"), ','); for (Iterator<String> it = pools.iterator(); it.hasNext();) { String pool = it.next(); Map<String, String> data = new HashMap<String, String>(); data.put("driver", props.get("db.pool." + pool + ".jdbcDriver")); data.put("url", props.get("db.pool." + pool + ".jdbcUrl")); data.put("params", props.get("db.pool." + pool + ".jdbcUrl.params")); data.put("user", props.get("db.pool." + pool + ".user")); data.put("pwd", props.get("db.pool." + pool + ".password")); data.put("keepHistory", String.valueOf(updateBean.isKeepHistory())); m_dbPools.put(pool, data); } } else { throw new Exception("setup bean not initialized"); } } /** * Checks if an update is needed.<p> * * @return if an update is needed */ public boolean needUpdate() { String pool = "default"; int currentVersion = 8; m_detectedVersion = 8; CmsSetupDb setupDb = new CmsSetupDb(null); try { setupDb.setConnection(getDbDriver(pool), getDbUrl(pool), getDbParams(pool), getDbUser(pool), m_dbPools.get( pool).get("pwd")); if (!setupDb.hasTableOrColumn("CMS_USERS", "USER_OU")) { m_detectedVersion = 6; } else if (!setupDb.hasTableOrColumn("CMS_LOG", null)) { m_detectedVersion = 7; } } finally { setupDb.closeConnection(); } return (currentVersion > m_detectedVersion); } /** * Updates all database pools.<p> */ public void run() { try { // add a list of plugins to execute // be sure to use the right order m_plugins = new ArrayList<I_CmsUpdateDBPart>(); if (getDetectedVersion() < 7) { m_plugins.add(new org.opencms.setup.db.update6to7.CmsUpdateDBDropOldIndexes()); m_plugins.add(new org.opencms.setup.db.update6to7.CmsUpdateDBUpdateOU()); m_plugins.add(new org.opencms.setup.db.update6to7.CmsUpdateDBCmsUsers()); m_plugins.add(new org.opencms.setup.db.update6to7.CmsUpdateDBProjectId()); m_plugins.add(new org.opencms.setup.db.update6to7.CmsUpdateDBNewTables()); m_plugins.add(new org.opencms.setup.db.update6to7.CmsUpdateDBHistoryTables()); m_plugins.add(new org.opencms.setup.db.update6to7.CmsUpdateDBHistoryPrincipals()); m_plugins.add(new org.opencms.setup.db.update6to7.CmsUpdateDBDropUnusedTables()); m_plugins.add(new org.opencms.setup.db.update6to7.CmsUpdateDBContentTables()); m_plugins.add(new org.opencms.setup.db.update6to7.CmsUpdateDBAlterTables()); m_plugins.add(new org.opencms.setup.db.update6to7.CmsUpdateDBDropBackupTables()); m_plugins.add(new org.opencms.setup.db.update6to7.CmsUpdateDBCreateIndexes7()); } if (getDetectedVersion() < 8) { m_plugins.add(new org.opencms.setup.db.update7to8.CmsUpdateDBNewTables()); } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } Iterator<String> it = getPools().iterator(); while (it.hasNext()) { String dbPool = it.next(); System.out.println("Starting DB Update for pool " + dbPool + "... "); try { updateDatabase(dbPool); } catch (Throwable t) { t.printStackTrace(); } System.out.println("... DB Update finished for " + dbPool + "."); } } /** * Updates the database.<p> * * @param pool the database pool to update */ public void updateDatabase(String pool) { Map<String, String> dbPoolData = new HashMap<String, String>(m_dbPools.get(pool)); // display info System.out.println("JDBC Driver: " + getDbDriver(pool)); System.out.println("JDBC Connection Url: " + getDbUrl(pool)); System.out.println("JDBC Connection Url Params: " + getDbParams(pool)); System.out.println("Database User: " + getDbUser(pool)); // get the db implementation name String dbName = getDbName(); String name = null; if (dbName.indexOf("mysql") > -1) { getMySqlEngine(dbPoolData); name = "mysql"; } else if (dbName.indexOf("oracle") > -1) { getOracleTablespaces(dbPoolData); name = "oracle"; } else if (dbName.indexOf("postgresql") > -1) { getPostgreSqlTablespaces(dbPoolData); name = "postgresql"; } else { System.out.println("db " + dbName + " not supported"); return; } // execute update Iterator<I_CmsUpdateDBPart> it = m_plugins.iterator(); while (it.hasNext()) { I_CmsUpdateDBPart updatePart = it.next(); I_CmsUpdateDBPart dbUpdater = getInstanceForDb(updatePart, name); if (dbUpdater != null) { dbUpdater.execute(dbPoolData); } } } /** * Creates a new instance for the given database and setting the db pool data.<p> * * @param dbUpdater the generic updater part * @param dbName the database to get a new instance for * * @return right instance instance for the given database */ protected I_CmsUpdateDBPart getInstanceForDb(I_CmsUpdateDBPart dbUpdater, String dbName) { String clazz = dbUpdater.getClass().getName(); int pos = clazz.lastIndexOf('.'); clazz = clazz.substring(0, pos) + "." + dbName + clazz.substring(pos); try { return (I_CmsUpdateDBPart)Class.forName(clazz).newInstance(); } catch (Exception e) { e.printStackTrace(); return null; } } /** * Retrieves the mysql engine name.<p> * * @param dbPoolData the database pool data */ protected void getMySqlEngine(Map<String, String> dbPoolData) { String engine = "MYISAM"; CmsSetupDb setupDb = new CmsSetupDb(null); CmsSetupDBWrapper db = null; try { setupDb.setConnection( dbPoolData.get("driver"), dbPoolData.get("url"), dbPoolData.get("params"), dbPoolData.get("user"), dbPoolData.get("pwd")); db = setupDb.executeSqlStatement("SHOW TABLE STATUS LIKE 'CMS_GROUPS';", null); if (db.getResultSet().next()) { engine = db.getResultSet().getString("Engine").toUpperCase(); } } catch (SQLException e) { e.printStackTrace(); } finally { if (db != null) { db.close(); } setupDb.closeConnection(); } dbPoolData.put("engine", engine); System.out.println("Table engine: " + engine); } /** * Retrieves the oracle tablespace names.<p> * * @param dbPoolData the database pool data */ protected void getOracleTablespaces(Map<String, String> dbPoolData) { String dataTablespace = "users"; String indexTablespace = "users"; CmsSetupDb setupDb = new CmsSetupDb(null); try { setupDb.setConnection( dbPoolData.get("driver"), dbPoolData.get("url"), dbPoolData.get("params"), dbPoolData.get("user"), dbPoolData.get("pwd")); // read tablespace for data CmsSetupDBWrapper db = null; try { db = setupDb.executeSqlStatement("SELECT DISTINCT tablespace_name FROM user_tables", null); if (db.getResultSet().next()) { dataTablespace = db.getResultSet().getString(1).toLowerCase(); } } finally { if (db != null) { db.close(); } } // read tablespace for indexes try { db = setupDb.executeSqlStatement("SELECT DISTINCT tablespace_name FROM user_indexes", null); if (db.getResultSet().next()) { indexTablespace = db.getResultSet().getString(1).toLowerCase(); } } finally { if (db != null) { db.close(); } } } catch (SQLException e) { e.printStackTrace(); } finally { setupDb.closeConnection(); } dbPoolData.put("indexTablespace", indexTablespace); System.out.println("Index Tablespace: " + indexTablespace); dbPoolData.put("dataTablespace", dataTablespace); System.out.println("Data Tablespace: " + dataTablespace); } /** * Retrieves the postgresql tablespace names.<p> * * @param dbPoolData the database pool data */ protected void getPostgreSqlTablespaces(Map<String, String> dbPoolData) { String dataTablespace = "pg_default"; String indexTablespace = "pg_default"; CmsSetupDb setupDb = new CmsSetupDb(null); try { setupDb.setConnection( dbPoolData.get("driver"), dbPoolData.get("url"), dbPoolData.get("params"), dbPoolData.get("user"), dbPoolData.get("pwd")); // read tablespace for data CmsSetupDBWrapper db = null; try { db = setupDb.executeSqlStatement( "SELECT DISTINCT pg_tablespace.spcname FROM pg_class, pg_tablespace WHERE pg_class.relname='cms_user' AND pg_class.reltablespace = pg_tablespace.oid", null); if (db.getResultSet().next()) { dataTablespace = db.getResultSet().getString(1).toLowerCase(); } } finally { if (db != null) { db.close(); } } // read tablespace for indexes try { db = setupDb.executeSqlStatement( "SELECT DISTINCT pg_tablespace.spcname FROM pg_class, pg_tablespace WHERE pg_class.relname='cms_users_pkey' AND pg_class.reltablespace = pg_tablespace.oid", null); if (db.getResultSet().next()) { indexTablespace = db.getResultSet().getString(1).toLowerCase(); } } finally { if (db != null) { db.close(); } } } catch (SQLException e) { e.printStackTrace(); } finally { setupDb.closeConnection(); } dbPoolData.put("indexTablespace", indexTablespace); System.out.println("Index Tablespace: " + indexTablespace); dbPoolData.put("dataTablespace", dataTablespace); System.out.println("Data Tablespace: " + dataTablespace); } }