/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* 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.
*/
package com.liferay.portal.tools.db.upgrade.client;
import com.liferay.portal.tools.db.upgrade.client.util.GogoTelnetClient;
import com.liferay.portal.tools.db.upgrade.client.util.Properties;
import com.liferay.portal.tools.db.upgrade.client.util.StringUtil;
import com.liferay.portal.tools.db.upgrade.client.util.TeePrintStream;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import jline.console.ConsoleReader;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
/**
* @author David Truong
*/
public class UpgradeClient {
public static void main(String[] args) {
try {
Options options = _getOptions();
CommandLineParser commandLineParser = new DefaultParser();
CommandLine commandLine = commandLineParser.parse(options, args);
if (commandLine.hasOption("help")) {
HelpFormatter helpFormatter = new HelpFormatter();
helpFormatter.printHelp(
"Liferay Portal Tools Database Upgrade Client", options);
return;
}
String jvmOpts = null;
if (commandLine.hasOption("jvm-opts")) {
jvmOpts = commandLine.getOptionValue("jvm-opts");
}
else {
jvmOpts =
"-Dfile.encoding=UTF8 -Duser.country=US " +
"-Duser.language=en -Duser.timezone=GMT -Xmx2048m ";
}
File logFile = null;
if (commandLine.hasOption("log-file")) {
logFile = new File(commandLine.getOptionValue("log-file"));
}
else {
logFile = new File("upgrade.log");
}
if (logFile.exists()) {
String logFileName = logFile.getName();
logFile.renameTo(
new File(logFileName + "." + logFile.lastModified()));
logFile = new File(logFileName);
}
boolean shell = false;
if (commandLine.hasOption("shell")) {
shell = true;
}
UpgradeClient upgradeClient = new UpgradeClient(
jvmOpts, logFile, shell);
upgradeClient.upgrade();
}
catch (ParseException pe) {
System.err.println("Unable to parse command line properties");
pe.printStackTrace();
}
catch (Exception e) {
System.err.println("Error running upgrade");
e.printStackTrace();
}
}
public UpgradeClient(String jvmOpts, File logFile, boolean shell)
throws IOException {
_jvmOpts = jvmOpts;
_logFile = logFile;
_shell = shell;
_appServerPropertiesFile = new File("app-server.properties");
_appServerProperties = _readProperties(_appServerPropertiesFile);
_portalUpgradeDatabasePropertiesFile = new File(
"portal-upgrade-database.properties");
_portalUpgradeDatabaseProperties = _readProperties(
_portalUpgradeDatabasePropertiesFile);
_portalUpgradeExtPropertiesFile = new File(
"portal-upgrade-ext.properties");
_portalUpgradeExtProperties = _readProperties(
_portalUpgradeExtPropertiesFile);
}
public void upgrade() throws IOException {
verifyProperties();
System.setOut(
new TeePrintStream(new FileOutputStream(_logFile), System.out));
ProcessBuilder processBuilder = new ProcessBuilder();
List<String> commands = new ArrayList<>();
if (_JAVA_HOME != null) {
commands.add(_JAVA_HOME + "/bin/java");
}
else {
commands.add("java");
}
commands.add("-cp");
commands.add(_getClassPath());
Collections.addAll(commands, _jvmOpts.split(" "));
commands.add("-Dexternal-properties=portal-upgrade.properties");
commands.add(
"-Dserver.detector.server.id=" +
_appServer.getServerDetectorServerId());
commands.add("com.liferay.portal.tools.DBUpgrader");
processBuilder.command(commands);
processBuilder.redirectErrorStream(true);
Process process = processBuilder.start();
try (InputStreamReader inputStreamReader = new InputStreamReader(
process.getInputStream());
BufferedReader bufferedReader = new BufferedReader(
inputStreamReader)) {
String line = null;
while ((line = bufferedReader.readLine()) != null) {
if (line.equals(
"Running modules upgrades. Connect to Gogo shell to " +
"check the status.")) {
break;
}
else {
System.out.println(line);
}
}
System.out.flush();
}
catch (IOException ioe) {
ioe.printStackTrace();
}
try (GogoTelnetClient gogoTelnetClient = new GogoTelnetClient()) {
if (_shell || !_isFinished(gogoTelnetClient)) {
System.out.println("You are connected to Gogo shell.");
_printHelp();
_consoleReader.setPrompt("g! ");
String line;
while ((line = _consoleReader.readLine()) != null) {
if (line.equals("exit") || line.equals("quit")) {
break;
}
else if (line.equals("upgrade:help")) {
_printHelp();
}
else {
System.out.println(gogoTelnetClient.send(line));
}
}
}
}
catch (Exception e) {
}
_close(process.getErrorStream());
_close(process.getInputStream());
_close(process.getOutputStream());
process.destroy();
}
public void verifyProperties() {
try {
_verifyAppServerProperties();
_verifyPortalUpgradeDatabaseProperties();
_verifyPortalUpgradeExtProperties();
_saveProperties();
}
catch (IOException ioe) {
ioe.printStackTrace();
}
}
private static Options _getOptions() {
Options options = new Options();
options.addOption(
new Option("h", "help", false, "Print this message."));
options.addOption(
new Option(
"j", "jvm-opts", true,
"Set the JVM_OPTS used for the upgrade."));
options.addOption(
new Option("l", "log-file", true, "Set the name of log file."));
options.addOption(
new Option(
"s", "shell", false, "Automatically connect to GoGo shell."));
return options;
}
private void _appendClassPath(StringBuilder sb, File dir)
throws IOException {
if (dir.exists() && dir.isDirectory()) {
for (File file : dir.listFiles()) {
String fileName = file.getName();
if (file.isFile() && fileName.endsWith("jar")) {
sb.append(file.getCanonicalPath());
sb.append(File.pathSeparator);
}
else if (file.isDirectory()) {
_appendClassPath(sb, file);
}
}
}
}
private void _appendClassPath(StringBuilder sb, List<File> dirs)
throws IOException {
for (File dir : dirs) {
_appendClassPath(sb, dir);
}
}
private void _close(Closeable closeable) throws IOException {
closeable.close();
}
private String _getClassPath() throws IOException {
StringBuilder sb = new StringBuilder();
String liferayClassPath = System.getenv("LIFERAY_CLASSPATH");
if ((liferayClassPath != null) && !liferayClassPath.isEmpty()) {
sb.append(liferayClassPath);
sb.append(File.pathSeparator);
}
_appendClassPath(sb, new File("lib"));
_appendClassPath(sb, new File("."));
_appendClassPath(sb, _appServer.getGlobalLibDir());
_appendClassPath(sb, _appServer.getExtraLibDirs());
File portalClassesDir = _appServer.getPortalClassesDir();
sb.append(portalClassesDir.getCanonicalPath());
sb.append(File.pathSeparator);
_appendClassPath(sb, _appServer.getPortalLibDir());
return sb.toString();
}
private String _getRelativeFileName(File baseFile, File pathFile) {
return _getRelativeFileName(baseFile.toPath(), pathFile.toPath());
}
private String _getRelativeFileName(Path basePath, Path path) {
Path relativePath = basePath.relativize(path);
return relativePath.toString();
}
private List<String> _getRelativeFileNames(
File baseFile, List<File> pathFiles) {
List<String> relativeFileNames = new ArrayList<>(pathFiles.size());
for (File pathFile : pathFiles) {
relativeFileNames.add(
_getRelativeFileName(baseFile.toPath(), pathFile.toPath()));
}
return relativeFileNames;
}
private boolean _isFinished(GogoTelnetClient gogoTelnetClient)
throws IOException {
System.out.print("Checking to see if all upgrades have completed...");
String upgradeCheck = gogoTelnetClient.send("upgrade:check");
String upgradeSteps = gogoTelnetClient.send(
"upgrade:list | grep Registered | grep step");
if (!upgradeCheck.equals("upgrade:check") ||
upgradeSteps.contains("true")) {
System.out.println(
" your upgrades have failed, have not started, or are still " +
"running.");
return false;
}
else {
System.out.println(" done.");
return true;
}
}
private void _printHelp() {
System.out.println("\nUpgrade commands:");
System.out.println("exit or quit - Exit Gogo Shell");
System.out.println(
"upgrade:check - List upgrades that have failed, have not " +
"started, or are still running");
System.out.println(
"upgrade:execute {module_name} - Execute upgrade for specified " +
"module");
System.out.println("upgrade:help - Show upgrade commands");
System.out.println("upgrade:list - List registered upgrades");
System.out.println(
"upgrade:list {module_name} - List upgrade steps required for " +
"specified module");
System.out.println(
"upgrade:list | grep Registered - List registered upgrades and " +
"their current version");
System.out.println(
"upgrade:list | grep Registered | grep steps - List upgrades in " +
"progress");
System.out.println(
"verify:execute {module_name} - Execute verifier for specified " +
"module");
System.out.println("verify:list - List registered verifiers");
}
private Properties _readProperties(File file) {
Properties properties = new Properties();
if (file.exists()) {
try {
properties.load(file);
}
catch (IOException ioe) {
System.err.println("Unable to load " + file);
}
}
return properties;
}
private void _saveProperties() throws IOException {
_appServerProperties.store(_appServerPropertiesFile);
_portalUpgradeDatabaseProperties.store(
_portalUpgradeDatabasePropertiesFile);
_portalUpgradeExtProperties.store(_portalUpgradeExtPropertiesFile);
}
private void _verifyAppServerProperties() throws IOException {
String value = _appServerProperties.getProperty(
"server.detector.server.id");
if ((value == null) || value.isEmpty()) {
String response = null;
while (_appServer == null) {
System.out.print("[ ");
for (String appServer : _appServers.keySet()) {
System.out.print(appServer + " ");
}
System.out.println("]");
System.out.println(
"Please enter your application server (tomcat): ");
response = _consoleReader.readLine();
if (response.isEmpty()) {
response = "tomcat";
}
_appServer = _appServers.get(response);
if (_appServer == null) {
System.err.println(
response + " is an unsupported application server.");
}
}
File dir = _appServer.getDir();
File globalLibDir = _appServer.getGlobalLibDir();
File portalDir = _appServer.getPortalDir();
System.out.println(
"Please enter your application server directory (" + dir +
"): ");
response = _consoleReader.readLine();
if (!response.isEmpty()) {
_appServer.setDirName(response);
}
System.out.println(
"Please enter your extra library directories (" +
_appServer.getExtraLibDirNames() + "): ");
response = _consoleReader.readLine();
if (!response.isEmpty()) {
_appServer.setExtraLibDirNames(response);
}
System.out.println(
"Please enter your global library directory (" + globalLibDir +
"): ");
response = _consoleReader.readLine();
if (!response.isEmpty()) {
_appServer.setGlobalLibDirName(response);
}
System.out.println(
"Please enter your portal directory (" + portalDir + "): ");
response = _consoleReader.readLine();
if (!response.isEmpty()) {
_appServer.setPortalDirName(response);
}
_appServerProperties.setProperty("dir", dir.getCanonicalPath());
_appServerProperties.setProperty(
"extra.lib.dirs",
StringUtil.join(
_getRelativeFileNames(dir, _appServer.getExtraLibDirs()),
','));
_appServerProperties.setProperty(
"global.lib.dir", _getRelativeFileName(dir, globalLibDir));
_appServerProperties.setProperty(
"portal.dir", _getRelativeFileName(dir, portalDir));
_appServerProperties.setProperty(
"server.detector.server.id",
_appServer.getServerDetectorServerId());
}
else {
_appServer = new AppServer(
_appServerProperties.getProperty("dir"),
_appServerProperties.getProperty("extra.lib.dirs"),
_appServerProperties.getProperty("global.lib.dir"),
_appServerProperties.getProperty("portal.dir"), value);
}
}
private void _verifyPortalUpgradeDatabaseProperties() throws IOException {
String value = _portalUpgradeDatabaseProperties.getProperty(
"jdbc.default.driverClassName");
if ((value == null) || value.isEmpty()) {
String response = null;
Database dataSource = null;
while (dataSource == null) {
System.out.print("[ ");
for (String database : _databases.keySet()) {
System.out.print(database + " ");
}
System.out.println("]");
System.out.println("Please enter your database (mysql): ");
response = _consoleReader.readLine();
if (response.isEmpty()) {
response = "mysql";
}
dataSource = _databases.get(response);
if (dataSource == null) {
System.err.println(
response + " is an unsupported database.");
}
}
System.out.println(
"Please enter your database JDBC driver class name (" +
dataSource.getClassName() + "): ");
response = _consoleReader.readLine();
if (!response.isEmpty()) {
dataSource.setClassName(response);
}
System.out.println(
"Please enter your database JDBC driver protocol (" +
dataSource.getProtocol() + "): ");
response = _consoleReader.readLine();
if (!response.isEmpty()) {
dataSource.setProtocol(response);
}
System.out.println(
"Please enter your database host (" + dataSource.getHost() +
"): ");
response = _consoleReader.readLine();
if (!response.isEmpty()) {
dataSource.setHost(response);
}
String port = null;
if (dataSource.getPort() > 0) {
port = String.valueOf(dataSource.getPort());
}
else {
port = "none";
}
System.out.println(
"Please enter your database port (" + port + "): ");
response = _consoleReader.readLine();
if (!response.isEmpty()) {
if (response.equals("none")) {
dataSource.setPort(0);
}
else {
dataSource.setPort(Integer.parseInt(response));
}
}
System.out.println(
"Please enter your database name (" +
dataSource.getDatabaseName() + "): ");
response = _consoleReader.readLine();
if (!response.isEmpty()) {
dataSource.setDatabaseName(response);
}
System.out.println("Please enter your database username: ");
String username = _consoleReader.readLine();
System.out.println("Please enter your database password: ");
String password = _consoleReader.readLine('*');
_portalUpgradeDatabaseProperties.setProperty(
"jdbc.default.driverClassName", dataSource.getClassName());
_portalUpgradeDatabaseProperties.setProperty(
"jdbc.default.password", password);
_portalUpgradeDatabaseProperties.setProperty(
"jdbc.default.url", dataSource.getURL());
_portalUpgradeDatabaseProperties.setProperty(
"jdbc.default.username", username);
}
}
private void _verifyPortalUpgradeExtProperties() throws IOException {
String value = _portalUpgradeExtProperties.getProperty("liferay.home");
if ((value == null) || value.isEmpty()) {
System.out.println("Please enter your Liferay home (../../): ");
String response = _consoleReader.readLine();
if (response.isEmpty()) {
response = "../../";
}
File liferayHome = new File(response);
_portalUpgradeExtProperties.setProperty(
"liferay.home", liferayHome.getCanonicalPath());
}
}
private static final String _JAVA_HOME = System.getenv("JAVA_HOME");
private static final Map<String, AppServer> _appServers =
new LinkedHashMap<>();
private static final Map<String, Database> _databases =
new LinkedHashMap<>();
static {
_appServers.put("jboss", AppServer.getJBossEAPAppServer());
_appServers.put("jonas", AppServer.getJOnASAppServer());
_appServers.put("resin", AppServer.getResinAppServer());
_appServers.put("tcserver", AppServer.getTCServerAppServer());
_appServers.put("tomcat", AppServer.getTomcatAppServer());
_appServers.put("weblogic", AppServer.getWebLogicAppServer());
_appServers.put("websphere", AppServer.getWebSphereAppServer());
_appServers.put("wildfly", AppServer.getWildFlyAppServer());
_databases.put("db2", Database.getDB2Database());
_databases.put("mariadb", Database.getMariaDBDatabase());
_databases.put("mysql", Database.getMySQLDatabase());
_databases.put("oracle", Database.getOracleDataSource());
_databases.put("postgresql", Database.getPostgreSQLDatabase());
_databases.put("sqlserver", Database.getSQLServerDatabase());
_databases.put("sybase", Database.getSybaseDatabase());
}
private AppServer _appServer;
private final Properties _appServerProperties;
private final File _appServerPropertiesFile;
private final ConsoleReader _consoleReader = new ConsoleReader();
private final String _jvmOpts;
private final File _logFile;
private final Properties _portalUpgradeDatabaseProperties;
private final File _portalUpgradeDatabasePropertiesFile;
private final Properties _portalUpgradeExtProperties;
private final File _portalUpgradeExtPropertiesFile;
private final boolean _shell;
}