com.haulmont.cuba.core.sys.utils.DbUpdaterUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.haulmont.cuba.core.sys.utils.DbUpdaterUtil.java

Source

/*
 * Copyright (c) 2008-2016 Haulmont.
 *
 * Licensed 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 com.haulmont.cuba.core.sys.utils;

import com.haulmont.cuba.core.sys.AppComponents;
import com.haulmont.cuba.core.sys.AppContext;
import com.haulmont.cuba.core.sys.DbInitializationException;
import com.haulmont.cuba.core.sys.dbupdate.DbUpdaterEngine;
import com.haulmont.cuba.core.sys.dbupdate.ScriptResource;
import org.apache.commons.cli.*;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.sql.DataSource;
import java.io.File;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.List;
import java.util.Scanner;
import java.util.stream.Collectors;

public class DbUpdaterUtil extends DbUpdaterEngine {

    private static final Logger log = LoggerFactory.getLogger(DbUpdaterUtil.class);

    private boolean executeGroovy = true;

    protected static final String MS_SQL_2005 = "2005";

    public static void main(String[] args) {
        String property = System.getProperty("logback.configurationFile");
        if (StringUtils.isBlank(property)) {
            System.setProperty("logback.configurationFile", "com/haulmont/cuba/core/sys/utils/dbutil-logback.xml");
        }

        DbUpdaterUtil runner = new DbUpdaterUtil();
        runner.execute(args);
    }

    @SuppressWarnings("AccessStaticViaInstance")
    public void execute(String[] args) {
        Options cliOptions = new Options();

        Option dbConnectionOption = OptionBuilder.withArgName("connectionString").hasArgs()
                .withDescription("JDBC Database URL").isRequired().create("dbUrl");

        Option dbUserOption = OptionBuilder.withArgName("userName").hasArgs().withDescription("Database user")
                .isRequired().create("dbUser");

        Option dbPasswordOption = OptionBuilder.withArgName("password").hasArgs()
                .withDescription("Database password").isRequired().create("dbPassword");

        Option dbDriverClassOption = OptionBuilder.withArgName("driverClassName").hasArgs()
                .withDescription("JDBC driver class name").create("dbDriver");

        Option dbDirOption = OptionBuilder.withArgName("filePath").hasArgs()
                .withDescription("Database scripts directory").isRequired().create("scriptsDir");

        Option dbTypeOption = OptionBuilder.withArgName("dbType").hasArgs()
                .withDescription("DBMS type: postgres|mssql|oracle|etc").isRequired().create("dbType");

        Option dbVersionOption = OptionBuilder.withArgName("dbVersion").hasArgs()
                .withDescription("DBMS version: 2012|etc").create("dbVersion");

        Option dbExecuteGroovyOption = OptionBuilder.withArgName("executeGroovy").hasArgs()
                .withDescription("Ignoring Groovy scripts").create("executeGroovy");

        Option showUpdatesOption = OptionBuilder.withDescription("Print update scripts").create("check");

        Option applyUpdatesOption = OptionBuilder.withDescription("Update database").create("update");

        Option createDbOption = OptionBuilder.withDescription("Create database").create("create");

        cliOptions.addOption("help", false, "Print help");
        cliOptions.addOption(dbConnectionOption);
        cliOptions.addOption(dbUserOption);
        cliOptions.addOption(dbPasswordOption);
        cliOptions.addOption(dbDirOption);
        cliOptions.addOption(dbTypeOption);
        cliOptions.addOption(dbVersionOption);
        cliOptions.addOption(dbExecuteGroovyOption);
        cliOptions.addOption(showUpdatesOption);
        cliOptions.addOption(applyUpdatesOption);
        cliOptions.addOption(createDbOption);

        CommandLineParser parser = new PosixParser();
        HelpFormatter formatter = new HelpFormatter();
        CommandLine cmd;
        try {
            cmd = parser.parse(cliOptions, args);
        } catch (ParseException exp) {
            formatter.printHelp("dbupdate", cliOptions);
            return;
        }

        if (cmd.hasOption("help") || (!cmd.hasOption(showUpdatesOption.getOpt()))
                && !cmd.hasOption(applyUpdatesOption.getOpt()) && !cmd.hasOption(createDbOption.getOpt()))
            formatter.printHelp("dbupdate", cliOptions);
        else {
            this.dbScriptsDirectory = cmd.getOptionValue(dbDirOption.getOpt());
            File directory = new File(dbScriptsDirectory);
            if (!directory.exists()) {
                log.error("Not found db update directory");
                return;
            }

            dbmsType = cmd.getOptionValue(dbTypeOption.getOpt());
            dbmsVersion = StringUtils.trimToEmpty(cmd.getOptionValue(dbVersionOption.getOpt()));

            AppContext.Internals.setAppComponents(new AppComponents("core"));

            AppContext.setProperty("cuba.dbmsType", dbmsType);
            AppContext.setProperty("cuba.dbmsVersion", dbmsVersion);

            String dbDriver;
            if (!cmd.hasOption(dbDriverClassOption.getOpt())) {
                switch (dbmsType) {
                case "postgres":
                    dbDriver = "org.postgresql.Driver";
                    break;
                case "mssql":
                    if (MS_SQL_2005.equals(dbmsVersion)) {
                        dbDriver = "net.sourceforge.jtds.jdbc.Driver";
                    } else {
                        dbDriver = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
                    }
                    break;
                case "oracle":
                    dbDriver = "oracle.jdbc.OracleDriver";
                    break;
                default:
                    log.error(
                            "Unable to determine driver class name by DBMS type. Please provide driverClassName option");
                    return;
                }
            } else {
                dbDriver = cmd.getOptionValue(dbDriverClassOption.getOpt());
            }

            try {
                Class.forName(dbDriver);
            } catch (ClassNotFoundException e) {
                log.error("Unable to load driver class " + dbDriver);
                return;
            }

            String connectionStringParam = cmd.getOptionValue(dbConnectionOption.getOpt());
            try {
                this.dataSource = new SingleConnectionDataSource(connectionStringParam,
                        cmd.getOptionValue(dbUserOption.getOpt()), cmd.getOptionValue(dbPasswordOption.getOpt()));
            } catch (SQLException e) {
                log.error("Unable to connect to db: " + connectionStringParam);
                return;
            }

            if (cmd.hasOption(createDbOption.getOpt())) {
                // create database from init scripts
                StringBuilder availableScripts = new StringBuilder();
                for (ScriptResource initScript : getInitScripts()) {
                    availableScripts.append("\t").append(getScriptName(initScript)).append("\n");
                }
                log.info("Available create scripts: \n" + availableScripts);
                log.info(String.format("Do you want to create database %s ? [y/n]", connectionStringParam));
                Scanner scanner = new Scanner(new InputStreamReader(System.in, StandardCharsets.UTF_8));
                if ("y".equals(scanner.next())) {
                    doInit();
                }
            } else {
                boolean updatesAvailable = false;
                try {
                    List<String> scripts;

                    executeGroovy = !(cmd.hasOption(dbExecuteGroovyOption.getOpt())
                            && cmd.getOptionValue(dbExecuteGroovyOption.getOpt()).equals("false"));

                    scripts = findUpdateDatabaseScripts();

                    if (!scripts.isEmpty()) {
                        StringBuilder availableScripts = new StringBuilder();
                        for (String script : scripts) {
                            availableScripts.append("\t").append(script).append("\n");
                        }
                        log.info("Available updates:\n" + availableScripts);
                        updatesAvailable = true;
                    } else
                        log.info("No available updates found for database");
                } catch (DbInitializationException e) {
                    log.warn("Database not initialized");
                    return;
                }

                if (updatesAvailable && cmd.hasOption(applyUpdatesOption.getOpt())) {
                    log.info(String.format("Do you want to apply updates to %s ? [y/n]", connectionStringParam));
                    Scanner scanner = new Scanner(new InputStreamReader(System.in, StandardCharsets.UTF_8));
                    if ("y".equals(scanner.next())) {
                        doUpdate();
                    }
                }
            }
        }
    }

    @Override
    protected List<ScriptResource> getUpdateScripts() {
        if (executeGroovy) {
            return super.getUpdateScripts();
        } else {
            return super.getUpdateScripts().stream().filter(r -> !(r.getName().endsWith("groovy")))
                    .collect(Collectors.toList());
        }
    }

    private static class SingleConnectionDataSource implements DataSource {

        private String url;
        private String user;
        private String password;
        private PrintWriter logWriter;

        private SingleConnectionDataSource(String url, String user, String password) throws SQLException {
            this.url = url;
            this.user = user;
            this.password = password;
        }

        @Override
        public Connection getConnection() throws SQLException {
            return DriverManager.getConnection(url, user, password);
        }

        @Override
        public Connection getConnection(String username, String password) throws SQLException {
            return DriverManager.getConnection(url, username, password);
        }

        @Override
        public PrintWriter getLogWriter() throws SQLException {
            return logWriter;
        }

        @Override
        public void setLogWriter(PrintWriter out) throws SQLException {
            this.logWriter = out;
        }

        @Override
        public void setLoginTimeout(int seconds) throws SQLException {
        }

        @Override
        public int getLoginTimeout() throws SQLException {
            return 0;
        }

        @Override
        public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException {
            throw new SQLFeatureNotSupportedException();
        }

        @Override
        public <T> T unwrap(Class<T> iface) throws SQLException {
            return null;
        }

        @Override
        public boolean isWrapperFor(Class<?> iface) throws SQLException {
            return false;
        }
    }
}