/******************************************************************************* * Copyright (c) 2019, 2020 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v20.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.codewind.core.internal.cli; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.Properties; import java.util.concurrent.TimeoutException; import org.eclipse.codewind.core.CodewindCorePlugin; import org.eclipse.codewind.core.internal.CodewindManager; import org.eclipse.codewind.core.internal.CodewindManager.InstallerStatus; import org.eclipse.codewind.core.internal.Logger; import org.eclipse.codewind.core.internal.ProcessHelper; import org.eclipse.codewind.core.internal.ProcessHelper.ProcessResult; import org.eclipse.codewind.core.internal.connection.CodewindConnection; import org.eclipse.codewind.core.internal.connection.CodewindConnectionManager; import org.eclipse.codewind.core.internal.constants.CoreConstants; import org.eclipse.codewind.core.internal.messages.Messages; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.osgi.util.NLS; import org.json.JSONException; import org.json.JSONObject; public class InstallUtil { public static final String STOP_APP_CONTAINERS_PREFSKEY = "stopAppContainers"; public static final String STOP_APP_CONTAINERS_ALWAYS = "stopAppContainersAlways"; public static final String STOP_APP_CONTAINERS_NEVER = "stopAppContainersNever"; public static final String STOP_APP_CONTAINERS_PROMPT = "stopAppContainersPrompt"; public static final String STOP_APP_CONTAINERS_DEFAULT = STOP_APP_CONTAINERS_PROMPT; public static final int INSTALL_TIMEOUT_DEFAULT = 300; public static final int UNINSTALL_TIMEOUT_DEFAULT = 60; public static final int START_TIMEOUT_DEFAULT = 60; public static final int STOP_TIMEOUT_DEFAULT = 300; private static final String[] INSTALL_CMD = new String[] {"install"}; private static final String[] START_CMD = new String[] {"start"}; private static final String[] STOP_CMD = new String[] {"stop"}; private static final String[] STOP_ALL_CMD = new String[] {"stop-all"}; private static final String[] STATUS_CMD = new String[] {"status"}; private static final String[] REMOVE_CMD = new String[] {"remove", "local"}; private static final String[] UPGRADE_CMD = new String[] {"upgrade"}; private static final String TAG_OPTION = "-t"; private static final String INSTALL_VERSION_VAR = "INSTALL_VERSION"; private static final String CW_TAG_VAR = "CW_TAG"; private static final String WORKSPACE_OPTION = "--workspace"; private static final String INSTALL_VERSION_PROPS = "install-version.properties"; private static final String INSTALL_VERSION_PROPS_PATH = "resources/" + INSTALL_VERSION_PROPS; private static final String INSTALL_VERSION_KEY = "install-version"; private static String installVersion = null; private static String requestedVersion = null; private static String defaultInstallVersion = null; public static InstallStatus getInstallStatus(IProgressMonitor monitor) throws IOException, JSONException, TimeoutException { SubMonitor mon = SubMonitor.convert(monitor, Messages.CodewindStatusJobLabel, 100); Process process = null; try { process = CLIUtil.runCWCTL(CLIUtil.GLOBAL_JSON, STATUS_CMD, null); ProcessResult result = ProcessHelper.waitForProcess(process, 500, 120, mon); CLIUtil.checkResult(STATUS_CMD, result, true); JSONObject status = new JSONObject(result.getOutput()); return new InstallStatus(status); } finally { if (process != null && process.isAlive()) { process.destroy(); } } } public static ProcessResult startCodewind(String version, IProgressMonitor monitor) throws IOException, TimeoutException { SubMonitor mon = SubMonitor.convert(monitor, Messages.StartCodewindJobLabel, 100); Process process = null; try { CodewindManager.getManager().setInstallerStatus(InstallerStatus.STARTING); process = CLIUtil.runCWCTL(null, START_CMD, new String[] {TAG_OPTION, version}); ProcessResult result = ProcessHelper.waitForProcess(process, 500, getPrefs().getInt(CodewindCorePlugin.CW_START_TIMEOUT), mon.split(90)); return result; } finally { if (process != null && process.isAlive()) { process.destroy(); } CodewindManager.getManager().refreshInstallStatus(mon.isCanceled() ? new NullProgressMonitor() : mon.split(10)); CodewindManager.getManager().setInstallerStatus(null); } } public static ProcessResult stopCodewind(boolean stopAll, IProgressMonitor monitor) throws IOException, TimeoutException { SubMonitor mon = SubMonitor.convert(monitor, Messages.StopCodewindJobLabel, 100); Process process = null; try { // Disconnect the local connection(s). If there's an exception, // log it and continue to stop Codewind. CodewindConnectionManager.activeConnections().stream() .filter(CodewindConnection::isLocal) .forEach(connection -> { try { connection.disconnect(); } catch (Exception e) { Logger.logError("Error disconnecting " + connection.getName() + " connection", e); } }); // Yield to give the connections the chance to close try { Thread.sleep(250); } catch (InterruptedException e) { // ignore } CodewindManager.getManager().setInstallerStatus(InstallerStatus.STOPPING); process = CLIUtil.runCWCTL(null, stopAll ? STOP_ALL_CMD : STOP_CMD, null); ProcessResult result = ProcessHelper.waitForProcess(process, 500, getPrefs().getInt(CodewindCorePlugin.CW_STOP_TIMEOUT), mon.split(95)); return result; } finally { if (process != null && process.isAlive()) { process.destroy(); } CodewindManager.getManager().refreshInstallStatus(mon.isCanceled() ? new NullProgressMonitor() : mon.split(5)); CodewindManager.getManager().setInstallerStatus(null); } } public static ProcessResult installCodewind(String version, IProgressMonitor monitor) throws IOException, TimeoutException { SubMonitor mon = SubMonitor.convert(monitor, Messages.InstallCodewindJobLabel, 100); Process process = null; try { CodewindManager.getManager().setInstallerStatus(InstallerStatus.INSTALLING); process = CLIUtil.runCWCTL(null, INSTALL_CMD, new String[] {TAG_OPTION, version}); ProcessResult result = ProcessHelper.waitForProcess(process, 1000, getPrefs().getInt(CodewindCorePlugin.CW_INSTALL_TIMEOUT), mon.split(95)); return result; } finally { if (process != null && process.isAlive()) { process.destroy(); } CodewindManager.getManager().refreshInstallStatus(mon.isCanceled() ? new NullProgressMonitor() : mon.split(5)); CodewindManager.getManager().setInstallerStatus(null); } } public static ProcessResult removeCodewind(String version, IProgressMonitor monitor) throws IOException, TimeoutException { SubMonitor mon = SubMonitor.convert(monitor, Messages.RemovingCodewindJobLabel, 100); Process process = null; try { CodewindManager.getManager().setInstallerStatus(InstallerStatus.UNINSTALLING); if (version != null) { process = CLIUtil.runCWCTL(null, REMOVE_CMD, new String[] {TAG_OPTION, version}); } else { process = CLIUtil.runCWCTL(null, REMOVE_CMD, null); } ProcessResult result = ProcessHelper.waitForProcess(process, 500, getPrefs().getInt(CodewindCorePlugin.CW_UNINSTALL_TIMEOUT), mon.split(90)); return result; } finally { if (process != null && process.isAlive()) { process.destroy(); } CodewindManager.getManager().refreshInstallStatus(mon.isCanceled() ? new NullProgressMonitor() : mon.split(10)); CodewindManager.getManager().setInstallerStatus(null); } } public static ProcessResult upgradeWorkspace(String path, IProgressMonitor monitor) throws IOException, TimeoutException { SubMonitor mon = SubMonitor.convert(monitor, NLS.bind(Messages.UpgradeWorkspaceJobLabel, path), 100); Process process = null; try { process = CLIUtil.runCWCTL(null, UPGRADE_CMD, new String[] {WORKSPACE_OPTION, path}); ProcessResult result = ProcessHelper.waitForProcess(process, 500, 300, mon); return result; } finally { if (process != null && process.isAlive()) { process.destroy(); } } } public static String getRequestedVersion() { if (requestedVersion == null) { String value = System.getenv(CW_TAG_VAR); if (value == null || value.isEmpty()) { // Try the old env var value = System.getenv(INSTALL_VERSION_VAR); } if (value != null && !value.isEmpty()) { requestedVersion = value; } } return requestedVersion; } public static String getVersion() { if (installVersion == null) { String requestedVersion = getRequestedVersion(); installVersion = requestedVersion != null ? requestedVersion : getDefaultInstallVersion(); } return installVersion; } public static String getDefaultInstallVersion() { if (defaultInstallVersion == null) { URL url = CodewindCorePlugin.getDefault().getBundle().getEntry(INSTALL_VERSION_PROPS_PATH); if (url != null) { InputStream input = null; try { input = url.openStream(); Properties properties = new Properties(); properties.load(input); String version = properties.getProperty(INSTALL_VERSION_KEY); if (version != null && !version.isEmpty()) { defaultInstallVersion = version; } } catch (IOException e) { Logger.logError("Failed to read the properties file: " + url, e); } finally { if (input != null) { try { input.close(); } catch (IOException e) { Logger.logError("Failed to close input stream for: " + url, e); } } } } if (defaultInstallVersion == null) { defaultInstallVersion = CoreConstants.VERSION_LATEST; } } return defaultInstallVersion; } private static IPreferenceStore getPrefs() { return CodewindCorePlugin.getDefault().getPreferenceStore(); } }