| /** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.airavata.registry.tool; |
| |
| import org.apache.commons.cli.*; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import java.io.*; |
| import java.net.URI; |
| import java.sql.*; |
| import java.text.DecimalFormat; |
| import java.util.*; |
| import java.util.Date; |
| |
| public class DBMigrator { |
| private static final Logger logger = LoggerFactory.getLogger(DBMigrator.class); |
| private static final String delimiter = ";"; |
| private static final String MIGRATE_SQL_DERBY = "migrate_derby.sql"; |
| private static final String MIGRATE_SQL_MYSQL = "migrate_mysql.sql"; |
| private static final String REGISTRY_VERSION = "registry.version"; |
| private static final String AIRAVATA_VERSION = "0.5"; |
| private static String currentAiravataVersion; |
| private static String relativePath; |
| private static String SELECT_QUERY; |
| private static String INSERT_QUERY; |
| private static String UPDATE_QUERY; |
| private static String jdbcURL; |
| private static String jdbcUser; |
| private static String jdbcPwd; |
| |
| public static void main(String[] args) { |
| parseArguments(args); |
| generateConfigTableQueries(); |
| updateDB(jdbcURL, jdbcUser, jdbcPwd); |
| } |
| |
| public static void generateConfigTableQueries(){ |
| SELECT_QUERY = "SELECT * FROM CONFIGURATION WHERE config_key='" + REGISTRY_VERSION + "' and category_id='SYSTEM'"; |
| INSERT_QUERY = "INSERT INTO CONFIGURATION (config_key, config_val, expire_date, category_id) VALUES('" + |
| REGISTRY_VERSION + "', '" + getIncrementedVersion(currentAiravataVersion) + "', '" + getCurrentDate() + |
| "','SYSTEM')"; |
| UPDATE_QUERY = "UPDATE CONFIGURATION SET config_val='" + getIncrementedVersion(currentAiravataVersion) + "', expire_date='" + getCurrentDate() + |
| "' WHERE config_key='" + REGISTRY_VERSION + "' and category_id='SYSTEM'"; |
| } |
| |
| //we assume given database is up and running |
| public static void updateDB (String jdbcUrl, String jdbcUser, String jdbcPwd){ |
| relativePath = "db-scripts/" + getIncrementedVersion(currentAiravataVersion) + "/"; |
| InputStream sqlStream = null; |
| Scanner in = new Scanner(System.in); |
| if (jdbcUrl == null || jdbcUrl.equals("")){ |
| System.out.println("Enter JDBC URL : "); |
| jdbcUrl = in.next(); |
| } |
| if (jdbcUser == null || jdbcUser.equals("")){ |
| System.out.println("Enter JDBC Username : "); |
| jdbcUser = in.next(); |
| } |
| if (jdbcPwd == null || jdbcPwd.equals("")){ |
| System.out.println("Enter JDBC password : "); |
| jdbcPwd = in.next(); |
| } |
| |
| String dbType = getDBType(jdbcUrl); |
| String jdbcDriver = null; |
| |
| Connection connection; |
| try { |
| File file = null; |
| if (dbType.contains("derby")){ |
| jdbcDriver = "org.apache.derby.jdbc.ClientDriver"; |
| sqlStream = DBMigrator.class.getClassLoader().getResourceAsStream(relativePath + MIGRATE_SQL_DERBY); |
| } else if (dbType.contains("mysql")){ |
| jdbcDriver = "com.mysql.jdbc.Driver"; |
| sqlStream = DBMigrator.class.getClassLoader().getResourceAsStream(relativePath + MIGRATE_SQL_MYSQL); |
| } |
| Class.forName(jdbcDriver).newInstance(); |
| connection = DriverManager.getConnection(jdbcUrl, jdbcUser, jdbcPwd); |
| if (canUpdated(connection)){ |
| executeSQLScript(connection, sqlStream); |
| //update configuration table with airavata version |
| updateConfigTable(connection); |
| } |
| } catch (ClassNotFoundException e) { |
| logger.error("Unable to find SQL scripts..." , e); |
| } catch (InstantiationException e) { |
| logger.error("Error while updating the database..." , e); |
| } catch (IllegalAccessException e) { |
| logger.error("Error while updating the database..." , e); |
| } catch (SQLException e) { |
| logger.error("Error while updating the database..." , e); |
| } catch (Exception e) { |
| logger.error("Error while updating the database..." , e); |
| } |
| } |
| |
| private static boolean canUpdated (Connection conn){ |
| if (!currentAiravataVersion.equals(AIRAVATA_VERSION)){ |
| String config = executeSelectQuery(conn); |
| if (config != null){ |
| if (config.equals(getIncrementedVersion(currentAiravataVersion))) { |
| return false; |
| } else { |
| return true; |
| } |
| } |
| } else if (currentAiravataVersion.equals(AIRAVATA_VERSION)){ |
| return true; |
| } |
| return false; |
| } |
| |
| private static void updateConfigTable (Connection connection){ |
| // if existing need to update, otherwise insert |
| if (executeSelectQuery(connection) != null){ |
| executeQuery(connection, UPDATE_QUERY); |
| } else { |
| executeQuery(connection, INSERT_QUERY); |
| } |
| } |
| |
| private static Timestamp getCurrentDate (){ |
| Calendar cal = Calendar.getInstance(); |
| Date date = cal.getTime(); |
| Timestamp d = new Timestamp(date.getTime()); |
| return d; |
| } |
| |
| private static String getIncrementedVersion (String currentVersion){ |
| |
| DecimalFormat decimalFormat = new DecimalFormat("#,##0.0"); |
| Double currentVer = Double.parseDouble(currentVersion); |
| double v = currentVer + .1; |
| String formattedVal = decimalFormat.format(v); |
| return formattedVal; |
| } |
| |
| private static String executeSelectQuery (Connection conn){ |
| try { |
| Statement statement = conn.createStatement(); |
| ResultSet rs = statement.executeQuery(SELECT_QUERY); |
| if (rs != null){ |
| while (rs.next()) { |
| currentAiravataVersion = rs.getString(2); |
| return currentAiravataVersion; |
| } |
| } |
| } catch (SQLException e) { |
| logger.error(e.getMessage() , e); |
| } |
| return null; |
| } |
| |
| private static void executeQuery (Connection conn, String query){ |
| try { |
| Statement statement = conn.createStatement(); |
| statement.execute(query) ; |
| } catch (SQLException e) { |
| logger.error(e.getMessage() , e); |
| } |
| } |
| |
| private static void executeSQLScript(Connection conn, InputStream inputStream) throws Exception { |
| StringBuffer sql = new StringBuffer(); |
| BufferedReader reader = null; |
| try{ |
| reader = new BufferedReader(new InputStreamReader(inputStream)); |
| String line; |
| while ((line = reader.readLine()) != null) { |
| line = line.trim(); |
| if (line.startsWith("//")) { |
| continue; |
| } |
| if (line.startsWith("--")) { |
| continue; |
| } |
| StringTokenizer st = new StringTokenizer(line); |
| if (st.hasMoreTokens()) { |
| String token = st.nextToken(); |
| if ("REM".equalsIgnoreCase(token)) { |
| continue; |
| } |
| } |
| sql.append(" ").append(line); |
| |
| // SQL defines "--" as a comment to EOL |
| // and in Oracle it may contain a hint |
| // so we cannot just remove it, instead we must end it |
| if (line.indexOf("--") >= 0) { |
| sql.append("\n"); |
| } |
| if ((checkStringBufferEndsWith(sql, delimiter))) { |
| String sqlString = sql.substring(0, sql.length() - delimiter.length()); |
| executeSQL(sqlString, conn); |
| sql.replace(0, sql.length(), ""); |
| } |
| } |
| System.out.println(sql.toString()); |
| // Catch any statements not followed by ; |
| if (sql.length() > 0) { |
| executeSQL(sql.toString(), conn); |
| } |
| }catch (IOException e){ |
| logger.error("Error occurred while executing SQL script for creating Airavata database", e); |
| throw new Exception("Error occurred while executing SQL script for creating Airavata database", e); |
| }finally { |
| if (reader != null) { |
| reader.close(); |
| } |
| |
| } |
| } |
| |
| private static String getDBType(String jdbcURL){ |
| try{ |
| String cleanURI = jdbcURL.substring(5); |
| URI uri = URI.create(cleanURI); |
| return uri.getScheme(); |
| } catch (Exception e) { |
| logger.error(e.getMessage(), e); |
| return null; |
| } |
| } |
| |
| public static boolean checkStringBufferEndsWith(StringBuffer buffer, String suffix) { |
| if (suffix.length() > buffer.length()) { |
| return false; |
| } |
| // this loop is done on purpose to avoid memory allocation performance |
| // problems on various JDKs |
| // StringBuffer.lastIndexOf() was introduced in jdk 1.4 and |
| // implementation is ok though does allocation/copying |
| // StringBuffer.toString().endsWith() does massive memory |
| // allocation/copying on JDK 1.5 |
| // See http://issues.apache.org/bugzilla/show_bug.cgi?id=37169 |
| int endIndex = suffix.length() - 1; |
| int bufferIndex = buffer.length() - 1; |
| while (endIndex >= 0) { |
| if (buffer.charAt(bufferIndex) != suffix.charAt(endIndex)) { |
| return false; |
| } |
| bufferIndex--; |
| endIndex--; |
| } |
| return true; |
| } |
| |
| private static void executeSQL(String sql, Connection conn) throws Exception { |
| if ("".equals(sql.trim())) { |
| return; |
| } |
| Statement statement = null; |
| try { |
| logger.debug("SQL : " + sql); |
| |
| boolean ret; |
| int updateCount = 0, updateCountTotal = 0; |
| statement = conn.createStatement(); |
| ret = statement.execute(sql); |
| updateCount = statement.getUpdateCount(); |
| do { |
| if (!ret) { |
| if (updateCount != -1) { |
| updateCountTotal += updateCount; |
| } |
| } |
| ret = statement.getMoreResults(); |
| if (ret) { |
| updateCount = statement.getUpdateCount(); |
| } |
| } while (ret); |
| |
| logger.debug(sql + " : " + updateCountTotal + " rows affected"); |
| |
| SQLWarning warning = conn.getWarnings(); |
| while (warning != null) { |
| logger.warn(warning + " sql warning"); |
| warning = warning.getNextWarning(); |
| } |
| conn.clearWarnings(); |
| } catch (SQLException e) { |
| if (e.getSQLState().equals("X0Y32")) { |
| logger.info("Table Already Exists", e); |
| } else { |
| throw new Exception("Error occurred while executing : " + sql, e); |
| } |
| } finally { |
| if (statement != null) { |
| try { |
| statement.close(); |
| } catch (SQLException e) { |
| logger.error("Error occurred while closing result set.", e); |
| } |
| } |
| } |
| } |
| |
| public static void parseArguments(String[] args){ |
| try{ |
| Options options = new Options(); |
| options.addOption("url", true , "JDBC URL"); |
| options.addOption("user", true, "JDBC Username"); |
| options.addOption("pwd", true, "JDBC Password"); |
| options.addOption("v", true, "Airavata Current Version"); |
| CommandLineParser parser = new PosixParser(); |
| CommandLine cmd = parser.parse( options, args); |
| jdbcURL = cmd.getOptionValue("url"); |
| if (jdbcURL == null){ |
| logger.info("You should enter JDBC URL and JDBC Credentials as parameters..."); |
| } |
| jdbcUser = cmd.getOptionValue("user"); |
| if (jdbcUser == null){ |
| logger.info("You should enter JDBC URL and JDBC Credentials as parameters..."); |
| } |
| jdbcPwd = cmd.getOptionValue("pwd"); |
| currentAiravataVersion = cmd.getOptionValue("v"); |
| if (currentAiravataVersion == null){ |
| logger.info("You should enter current Airavata version you are using..."); |
| } |
| } catch (ParseException e) { |
| logger.error("Error while reading command line parameters" , e); |
| } |
| } |
| |
| protected static InputStream readFile(File file) { |
| StringBuilder fileContentsBuilder = new StringBuilder(); |
| BufferedReader bufferedReader = null; |
| try { |
| char[] buffer = new char[32767]; |
| bufferedReader = new BufferedReader(new FileReader(file)); |
| int read = 0; |
| |
| do { |
| read = bufferedReader.read(buffer); |
| if (read > 0) { |
| fileContentsBuilder.append(buffer, 0, read); |
| } |
| } while (read > 0); |
| } catch (Exception e) { |
| logger.error("Failed to read file " + file.getPath(), e); |
| } finally { |
| if (bufferedReader != null) { |
| try { |
| bufferedReader.close(); |
| } catch (IOException e) { |
| logger.error("Unable to close BufferedReader for " + file.getPath(), e); |
| } |
| } |
| } |
| System.out.println(fileContentsBuilder.toString()); |
| InputStream is = new ByteArrayInputStream(fileContentsBuilder.toString().getBytes()); |
| |
| return is; |
| } |
| } |