001package fr.ifremer.adagio.core.action; 002 003/* 004 * #%L 005 * SIH-Adagio :: Shared 006 * $Id:$ 007 * $HeadURL:$ 008 * %% 009 * Copyright (C) 2012 - 2014 Ifremer 010 * %% 011 * This program is free software: you can redistribute it and/or modify 012 * it under the terms of the GNU Affero General Public License as published by 013 * the Free Software Foundation, either version 3 of the License, or 014 * (at your option) any later version. 015 * 016 * This program is distributed in the hope that it will be useful, 017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 019 * GNU General Public License for more details. 020 * 021 * You should have received a copy of the GNU Affero General Public License 022 * along with this program. If not, see <http://www.gnu.org/licenses/>. 023 * #L% 024 */ 025 026import java.io.File; 027import java.io.IOException; 028import java.sql.Connection; 029import java.sql.PreparedStatement; 030import java.sql.SQLException; 031import java.util.List; 032import java.util.Properties; 033import java.util.Set; 034 035import org.apache.commons.io.FileUtils; 036import org.apache.commons.lang3.ArrayUtils; 037import org.apache.commons.logging.Log; 038import org.apache.commons.logging.LogFactory; 039import org.nuiton.i18n.I18n; 040 041import com.google.common.base.Charsets; 042import com.google.common.base.Preconditions; 043import com.google.common.base.Predicate; 044import com.google.common.collect.Lists; 045import com.google.common.collect.Sets; 046import com.google.common.io.Files; 047 048import fr.ifremer.adagio.core.config.AdagioConfiguration; 049import fr.ifremer.adagio.synchro.SynchroTechnicalException; 050import fr.ifremer.adagio.synchro.dao.DaoUtils; 051 052public class AllegroCoreNewEmptyDbAction { 053 /* Logger */ 054 private static final Log log = LogFactory.getLog(AllegroCoreNewEmptyDbAction.class); 055 056 private static String HSQLDB_SRC_DATABASE_CREATE_SCRIPT = "changelog/allegro.script"; 057 058 public void run() { 059 AdagioConfiguration config = AdagioConfiguration.getInstance(); 060 061 // Log target connection 062 if (log.isInfoEnabled()) { 063 log.info("Creating a new empty database..."); 064 } 065 066 // Check output directory validity 067 File outputDirectory = config.getLiquibaseOutputFile(); 068 if (outputDirectory == null) { 069 log.error("No output directory. Please use the option: --output <OUTPUT_DIRECTORY>"); 070 System.exit(1); 071 } 072 if (log.isInfoEnabled()) { 073 log.info(" Output directory: " + outputDirectory); 074 } 075 if (outputDirectory.exists() && !outputDirectory.isDirectory()) { 076 log.error("Not a directory: " + outputDirectory); 077 System.exit(1); 078 } 079 080 // Make sure the directory could be created 081 try { 082 FileUtils.forceMkdir(outputDirectory); 083 } catch (IOException e) { 084 throw new SynchroTechnicalException( 085 I18n.t("adagio.persistence.newEmptyDatabase.mkdir.error", outputDirectory), 086 e); 087 } 088 089 if (ArrayUtils.isNotEmpty(outputDirectory.listFiles())) { 090 log.error("The output directory should be empty: " + outputDirectory); 091 System.exit(1); 092 } 093 094 // Set the database directory into the configuration 095 config.setDbDirectory(outputDirectory); 096 097 // Get connections properties : 098 Properties targetConnectionProperties = config.getConnectionProperties(); 099 100 // Check connections 101 if (!checkConnection(config, targetConnectionProperties)) { 102 return; 103 } 104 105 try { 106 // Create the database 107 createEmptyDb(targetConnectionProperties); 108 } catch (SQLException e) { 109 throw new SynchroTechnicalException( 110 I18n.t("adagio.persistence.newEmptyDatabase.create.error"), 111 e); 112 } catch (IOException e) { 113 throw new SynchroTechnicalException( 114 I18n.t("adagio.persistence.newEmptyDatabase.create.error"), 115 e); 116 } 117 118 try { 119 // Shutdown database at end 120 DaoUtils.shutdownDatabase(targetConnectionProperties); 121 } catch (SQLException e) { 122 throw new SynchroTechnicalException( 123 I18n.t("adagio.persistence.newEmptyDatabase.shutdown.error"), 124 e); 125 } 126 } 127 128 protected boolean checkConnection( 129 AdagioConfiguration config, 130 Properties targetConnectionProperties) { 131 132 // Log target connection 133 if (log.isInfoEnabled()) { 134 log.info("Connecting to target database..."); 135 log.info(String.format(" Database directory: %s", config.getDbDirectory())); 136 log.info(String.format(" JDBC Driver: %s", config.getJdbcDriver())); 137 log.info(String.format(" JDBC URL: %s", config.getJdbcURL())); 138 log.info(String.format(" JDBC Username: %s", config.getJdbcUsername())); 139 } 140 141 // Check target connection 142 boolean isValidConnection = DaoUtils.isValidConnectionProperties(targetConnectionProperties); 143 if (!isValidConnection) { 144 log.error("Connection error: could not connect to target database."); 145 return false; 146 } 147 148 return true; 149 } 150 151 public void createEmptyDb(Properties targetConnectionProperties) throws SQLException, IOException { 152 153 File scriptFile = new File(HSQLDB_SRC_DATABASE_CREATE_SCRIPT); 154 Preconditions.checkState(scriptFile.exists(), "Could not find db script at " + scriptFile); 155 156 if (log.isInfoEnabled()) { 157 log.info("Will use create script: " + scriptFile); 158 } 159 Connection connection = DaoUtils.createConnection(targetConnectionProperties); 160 try { 161 List<String> importScriptSql = getImportScriptSql(scriptFile); 162 for (String sql : importScriptSql) { 163 PreparedStatement statement = null; 164 try { 165 statement = connection.prepareStatement(sql); 166 statement.execute(); 167 } catch (SQLException sqle) { 168 log.warn("SQL command failed : " + sql, sqle); 169 throw sqle; 170 } finally { 171 DaoUtils.closeSilently(statement); 172 } 173 174 } 175 connection.commit(); 176 } finally { 177 DaoUtils.closeSilently(connection); 178 } 179 } 180 181 protected List<String> getImportScriptSql(File scriptFile) throws IOException { 182 List<String> lines = Files.readLines(scriptFile, Charsets.UTF_8); 183 184 List<String> result = Lists.newArrayListWithCapacity(lines.size()); 185 186 Predicate<String> predicate = new Predicate<String>() { 187 188 Set<String> forbiddenStarts = Sets.newHashSet( 189 "SET ", 190 "CREATE USER ", 191 "CREATE SCHEMA ", 192 "GRANT DBA TO "); 193 194 @Override 195 public boolean apply(String input) { 196 boolean accept = true; 197 for (String forbiddenStart : forbiddenStarts) { 198 if (input.startsWith(forbiddenStart)) { 199 accept = false; 200 break; 201 } 202 } 203 return accept; 204 } 205 }; 206 for (String line : lines) { 207 if (predicate.apply(line.trim().toUpperCase())) { 208 if (line.contains("\\u000a")) { 209 line = line.replaceAll("\\\\u000a", "\n"); 210 } 211 result.add(line); 212 } 213 } 214 return result; 215 } 216}