/** * Copyright (C) 2012-2013 Selventa, Inc. * * This file is part of the OpenBEL Framework. * * This program 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 3 of the License, or * (at your option) any later version. * * The OpenBEL Framework 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. * * You should have received a copy of the GNU Lesser General Public License * along with the OpenBEL Framework. If not, see <http://www.gnu.org/licenses/>. * * Additional Terms under LGPL v3: * * This license does not authorize you and you are prohibited from using the * name, trademarks, service marks, logos or similar indicia of Selventa, Inc., * or, in the discretion of other licensors or authors of the program, the * name, trademarks, service marks, logos or similar indicia of such authors or * licensors, in any marketing or advertising materials relating to your * distribution of the program or any covered product. This restriction does * not waive or limit your obligation to keep intact all copyright notices set * forth in the program as delivered to you. * * If you distribute the program in whole or in part, or any modified version * of the program, and you assume contractual liability to the recipient with * respect to the program or modified version, then you will indemnify the * authors and licensors of the program for any liabilities that these * contractual assumptions directly impose on those licensors and authors. */ package org.openbel.framework.compiler.kam; import static org.openbel.framework.common.cfg.SystemConfiguration.getSystemConfiguration; import static org.openbel.framework.core.df.AbstractJdbcDAO.SCHEMA_NAME_PLACEHOLDER; import java.io.IOException; import java.io.InputStream; import java.sql.SQLException; import org.apache.commons.io.IOUtils; import org.openbel.framework.api.internal.KAMCatalogDao; import org.openbel.framework.api.internal.KamDbObject; import org.openbel.framework.core.df.DBConnection; import org.openbel.framework.core.df.DatabaseService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * KAMStoreSchemaServiceImpl implements a service to setup a KAM schema * instance to store a single KAM. * * @author Anthony Bargnesi {@code <abargnesi@selventa.com>} */ public class KAMStoreSchemaServiceImpl implements KAMStoreSchemaService { private final String SQL_SCRIPT_DELIMITER = "##"; /** * Statically-loads the slf4j application log. */ private static Logger log = LoggerFactory .getLogger(KAMStoreSchemaServiceImpl.class); /** * The classpath location where the KAM schema .sql files are located: * {@value #KAM_SQL_PATH} */ private static final String KAM_SQL_PATH = "/kam/"; /** * The classpath location where the .sql files to delete KAM schema are located: * {@value #DELETE_KAM_SQL_PATH} */ private static final String DELETE_KAM_SQL_PATH = "/kam_delete/"; /** * The classpath location where the KAM catalog schema .sql files are * located: {@value #KAM_CATALOG_SQL_PATH} */ private static final String KAM_CATALOG_SQL_PATH = "/kam_catalog/"; /** * The database service bean dependency. */ private final DatabaseService databaseService; /** * Create the KAMStoreSchemaServiceImpl with the {@link DatabaseService} * bean. * * @param databaseService {@link DatabaseService} the database service * bean */ public KAMStoreSchemaServiceImpl(final DatabaseService databaseService) { this.databaseService = databaseService; } /** * {@inheritDoc} */ @Override public void setupKAMCatalogSchema() throws SQLException, IOException { DBConnection kamDbc = null; try { kamDbc = createConnection(); runScripts(kamDbc, "/" + kamDbc.getType() + KAM_CATALOG_SQL_PATH, getSystemConfiguration().getKamCatalogSchema(), getSchemaManagementStatus(kamDbc)); } finally { closeConnection(kamDbc); } } /** * {@inheritDoc} */ @Override public void setupKAMStoreSchema(DBConnection dbc, String schemaName) throws IOException { runScripts(dbc, "/" + dbc.getType() + KAM_SQL_PATH, schemaName, getSchemaManagementStatus(dbc)); } /** * {@inheritDoc} */ @Override public boolean deleteKAMStoreSchema(DBConnection dbc, String schemaName) throws IOException { boolean deleteSchemas = getSchemaManagementStatus(dbc); if (deleteSchemas) { runScripts(dbc, "/" + dbc.getType() + DELETE_KAM_SQL_PATH, schemaName, deleteSchemas); } else { // Truncate the schema instead of deleting it. InputStream sqlStream = null; if (dbc.isMysql()) { sqlStream = getClass().getResourceAsStream( "/" + dbc.getType() + KAM_SQL_PATH + "1.sql"); } else if (dbc.isOracle()) { sqlStream = getClass().getResourceAsStream( "/" + dbc.getType() + KAM_SQL_PATH + "0.sql"); } if (sqlStream != null) { runScript(dbc, sqlStream, schemaName); } } return deleteSchemas; } /** * Check to see if the system is managing the KAMStore schemas. The system manages Derby schemas * by default. Oracle is only DBA managed and MySQL can be either although the default is to * enable system managed * * @param dbc * @return */ private boolean getSchemaManagementStatus(DBConnection dbc) { boolean createSchemas = false; if (dbc.isDerby()) { createSchemas = true; } else if (dbc.isMysql() || dbc.isPostgresql()) { createSchemas = getSystemConfiguration().getSystemManagedSchemas(); } return createSchemas; } /** * {@inheritDoc} */ @Override public String saveToKAMCatalog(KamDbObject kamDb) throws SQLException { KAMCatalogDao catalogDAO = null; try { catalogDAO = createCatalogDao(); catalogDAO.saveToCatalog(kamDb); } finally { if (catalogDAO != null) { closeCatalogDao(catalogDAO); } } return kamDb.getSchemaName(); } /** * {@inheritDoc} */ @Override public void deleteFromKAMCatalog(final String kamName) throws SQLException { KAMCatalogDao catalogDAO = null; try { catalogDAO = createCatalogDao(); catalogDAO.deleteFromCatalog(kamName); } finally { if (catalogDAO != null) { closeCatalogDao(catalogDAO); } } } private KAMCatalogDao createCatalogDao() throws SQLException { String catalogSchema = getSystemConfiguration().getKamCatalogSchema(); String kamSchemaPrefix = getSystemConfiguration().getKamSchemaPrefix(); return new KAMCatalogDao(createConnection(), catalogSchema, kamSchemaPrefix); } private void closeCatalogDao(KAMCatalogDao catalogDAO) { if (catalogDAO != null) { catalogDAO.terminate(); } } private DBConnection createConnection() throws SQLException { return databaseService.dbConnection( getSystemConfiguration().getKamURL(), getSystemConfiguration().getKamUser(), getSystemConfiguration().getKamPassword()); } private void closeConnection(DBConnection dbc) { if (dbc != null) { try { dbc.getConnection().close(); } catch (SQLException e) {} } } /** * Finds .sql scripts in <tt>dropRoot</tt> and executes each statement * againsts the {@link DBConnection} <tt>dbc</tt>. * * @param dbc {@link DBConnection}, the database connection * @param dropRoot {@link String}, the classpath root where .sql files * are found * @param schemaName {@link String}, the schema name, which can be null * @param createSchemas {@link boolean}, true if the system should create new schemas, false otherwise * @throws IOException Thrown if an I/O error occurred reading a .sql file * from the classpath */ private void runScripts(DBConnection dbc, String dropRoot, String schemaName, boolean createSchemas) throws IOException { int fi = 0; boolean fnf = false; while (!fnf) { InputStream sqlStream = getClass().getResourceAsStream(dropRoot + fi + ".sql"); if (sqlStream == null) { fnf = true; break; } String script = IOUtils.toString(sqlStream); String[] sqlStatements = script.split(SQL_SCRIPT_DELIMITER); for (String sqlStatement : sqlStatements) { // MySQL allows schemas to by system or dba managed. If dba managed we must // skip the schema creation phase which is always the first sql script (0.sql) if (createSchemas == false && fi == 0) { continue; } if (schemaName != null) { sqlStatement = sqlStatement.replace(SCHEMA_NAME_PLACEHOLDER, schemaName); } try { databaseService.update(dbc, sqlStatement); } catch (SQLException e) { log.debug("Error running script, message:\n{}\n\n{}\n", new Object[] { e.getMessage(), sqlStatement }); //swallow since DROP statements might fail. } } fi++; } } private void runScript(DBConnection dbc, InputStream sqlStream, String schemaName) throws IOException { String script = IOUtils.toString(sqlStream); String[] sqlStatements = script.split(SQL_SCRIPT_DELIMITER); for (String sqlStatement : sqlStatements) { if (schemaName != null) { sqlStatement = sqlStatement.replace(SCHEMA_NAME_PLACEHOLDER, schemaName); } try { databaseService.update(dbc, sqlStatement); } catch (SQLException e) { log.debug("Error running script, message:\n{}\n\n{}\n", new Object[] { e.getMessage(), sqlStatement }); //swallow since DROP statements might fail. } } } }