/** * (C) Copyright IBM Corporation 2014, 2015. * * 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 net.wasdev.wlp.ant; import java.io.File; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; import java.util.Properties; import java.util.concurrent.atomic.AtomicBoolean; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; /** * server operations task: start/stop/package/create/status/debug */ public class ServerTask extends AbstractTask { private String operation; private String timeout; private String wlp; private static final String START_MESSAGE_CODE = "CWWKF0011I"; private static final String STOP_MESSAGE_CODE = "CWWKE0036I"; private static final long SERVER_START_TIMEOUT_DEFAULT = 30 * 1000; private static final long SERVER_STOP_TIMEOUT_DEFAULT = 30 * 1000; // used with 'start' and 'debug' operations private boolean clean = false; // used with 'status' operation private String resultProperty; // used with 'dump', and 'package' operations private File archive; // used with 'dump', 'javadump', and 'package' operations private String include; // used with 'create' operation private String template; // used with 'package' operation private String os; @Override protected void initTask() { super.initTask(); if (isWindows) { wlp = "\"" + installDir + "\\bin\\server.bat\""; processBuilder.environment().put("EXIT_ALL", "1"); } else { wlp = installDir + "/bin/server"; } Properties sysp = System.getProperties(); String javaHome = sysp.getProperty("java.home"); // Set active directory (install dir) processBuilder.directory(installDir); processBuilder.environment().put("JAVA_HOME", javaHome); processBuilder.redirectErrorStream(true); } @Override public void execute() { initTask(); if (getRuntimeConfigurableWrapper().getAttributeMap().get("id") == null) { if ((operation == null || operation.length() <= 0)) { throw new BuildException(MessageFormat.format(messages.getString("error.server.operation.validate"), "operation")); } } if (operation != null) { try { if ("create".equals(operation)) { doCreate(); } else if ("run".equals(operation)) { doRun(); } else if ("start".equals(operation)) { doStart(); } else if ("stop".equals(operation)) { doStop(); } else if ("status".equals(operation)) { doStatus(); } else if ("debug".equals(operation)) { // Debug seems useless in ant tasks, but still keep it. doDebug(); } else if ("package".equals(operation)) { doPackage(); } else if ("dump".equals(operation)) { doDump(); } else if ("javadump".equals(operation)) { doJavaDump(); } else { throw new BuildException("Unsupported operation: " + operation); } } catch (BuildException e) { throw e; } catch (Exception e) { throw new BuildException(e); } } } private void doStart() throws Exception { // create server first if it doesn't exist if (!serverConfigDir.exists()) { log(MessageFormat.format(messages.getString("info.server.create"), serverName)); doCreate(); } List<String> command = getInitialCommand(operation); addCleanOption(command); processBuilder.command(command); Process p = processBuilder.start(); checkReturnCode(p, processBuilder.command().toString(), ReturnCode.OK.getValue(), ReturnCode.REDUNDANT_ACTION_STATUS.getValue()); // check server started message code. long startTimeout = SERVER_START_TIMEOUT_DEFAULT; if (timeout != null && !timeout.equals("")) { startTimeout = Long.valueOf(timeout); } validateServerStarted(getLogFile(), startTimeout); } private void validateServerStarted(File outputFile, long startTimeout) throws Exception { boolean serverStarted = false; log("Waiting up to " + (startTimeout / 1000) + " seconds for server confirmation: " + START_MESSAGE_CODE.toString() + " to be found in " + outputFile); try { final String startMessage = waitForStringInLog(START_MESSAGE_CODE, startTimeout, outputFile); serverStarted = (startMessage != null); } catch (Exception e) { throw new BuildException(e); } if (!!!serverStarted) { throw new BuildException(messages.getString("error.server.fail")); } } private void doRun() throws Exception { // create server first if it doesn't exist if (!serverConfigDir.exists()) { log(MessageFormat.format(messages.getString("info.server.create"), serverName)); doCreate(); } List<String> command = getInitialCommand(operation); addCleanOption(command); processBuilder.command(command); final Process p = processBuilder.start(); final AtomicBoolean shutdown = new AtomicBoolean(false); Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { shutdown.set(true); List<String> stopCommand = getInitialCommand("stop"); processBuilder.command(stopCommand); try { Process p = processBuilder.start(); p.waitFor(); } catch (Exception e) { log("Error stopping server", e, Project.MSG_WARN); } } }); int exitCode = getReturnCode(p, processBuilder.command().toString()); if (!shutdown.get() && exitCode != ReturnCode.OK.getValue()) { throw new BuildException(MessageFormat.format(messages.getString("error.invoke.command"), processBuilder.command().toString(), exitCode, ReturnCode.OK.getValue())); } } private void doStop() throws Exception { List<String> command = getInitialCommand(operation); processBuilder.command(command); Process p = processBuilder.start(); checkReturnCode(p, processBuilder.command().toString(), ReturnCode.OK.getValue(), ReturnCode.REDUNDANT_ACTION_STATUS.getValue()); } private void doStatus() throws Exception { List<String> command = getInitialCommand(operation); processBuilder.command(command); Process p = processBuilder.start(); int exitCode = getReturnCode(p, processBuilder.command().toString()); if (resultProperty == null) { resultProperty = "wlp." + serverName + ".status"; } getProject().setUserProperty(resultProperty, String.valueOf(exitCode)); } private void doDump() throws Exception { List<String> command = getInitialCommand(operation); addArchiveOption(command); addIncludeOption(command); processBuilder.command(command); Process p = processBuilder.start(); checkReturnCode(p, processBuilder.command().toString(), ReturnCode.OK.getValue()); } private void doJavaDump() throws Exception { List<String> command = getInitialCommand(operation); addIncludeOption(command); processBuilder.command(command); Process p = processBuilder.start(); checkReturnCode(p, processBuilder.command().toString(), ReturnCode.OK.getValue()); } private void doPackage() throws Exception { List<String> command = getInitialCommand(operation); addArchiveOption(command); addIncludeOption(command); addOsOption(command); processBuilder.command(command); Process p = processBuilder.start(); checkReturnCode(p, processBuilder.command().toString(), ReturnCode.OK.getValue()); } private void doCreate() throws Exception { List<String> command = getInitialCommand("create"); if (template != null) { command.add("--template=" + template); } processBuilder.command(command); Process p = processBuilder.start(); checkReturnCode(p, processBuilder.command().toString(), ReturnCode.OK.getValue()); } private void doDebug() throws Exception { List<String> command = getInitialCommand(operation); addCleanOption(command); processBuilder.command(command); Process p = processBuilder.start(); checkReturnCode(p, processBuilder.command().toString(), ReturnCode.OK.getValue()); } private List<String> getInitialCommand(String operation) { List<String> commands = new ArrayList<String>(); commands.add(wlp); commands.add(operation); if (serverName != null && !serverName.equals("")) { commands.add(serverName); } return commands; } private void addArchiveOption(List<String> command) { if (archive != null) { if (archive.isDirectory()) { throw new BuildException("The archive attribute must specify a file"); } command.add("--archive=" + archive); } } private void addIncludeOption(List<String> command) { if (include != null) { command.add("--include=" + include); } } private void addOsOption(List<String> command) { if (os != null) { command.add("--os=" + os); } } private void addCleanOption(List<String> command) { if (clean) { command.add("--clean"); } } /** * @return the operation */ public String getOperation() { return operation; } /** * @param operation * the operation to set */ public void setOperation(String operation) { this.operation = operation; } /** * @return the archive */ public File getArchive() { return archive; } /** * @param archive * the archive to set */ public void setArchive(File archive) { this.archive = archive; } /** * @return the clean */ public boolean isClean() { return clean; } /** * @param clean * the clean to set */ public void setClean(boolean clean) { this.clean = clean; } /** * @return the timeout */ public String getTimeout() { return timeout; } /** * @param timeout the timeout to set */ public void setTimeout(String timeout) { this.timeout = timeout; } /** * @return the os */ public String getOs() { return os; } /** * @param os the os to set */ public void setOs(String os) { this.os = os; } public String getResultProperty() { return resultProperty; } public void setResultProperty(String resultProperty) { this.resultProperty = resultProperty; } public String getInclude() { return include; } public void setInclude(String include) { this.include = include; } public String getTemplate() { return template; } public void setTemplate(String template) { this.template = template; } /* server's exit codes */ public enum ReturnCode { OK(0), // started/stopped is set based on operation. // process will return this code if start is called when server is already running // or will return this code for stop/status when the server is not running REDUNDANT_ACTION_STATUS(1), SERVER_NOT_EXIST_STATUS(2), SERVER_ACTIVE_STATUS( 3), SERVER_INACTIVE_STATUS(4), // Jump a few numbers for error return codes-- see readInitialConfig BAD_ARGUMENT(20), ERROR_SERVER_STOP(21), ERROR_SERVER_START(22), LOCATION_EXCEPTION( 23), LAUNCH_EXCEPTION(24), RUNTIME_EXCEPTION(25), UNKNOWN_EXCEPTION( 26), PROCESS_CLIENT_EXCEPTION(27), ERROR_SERVER_PACKAGE(28), ERROR_SERVER_DUMP( 29), ERROR_SERVER_ATTACH(30); final int val; ReturnCode(int val) { this.val = val; } public int getValue() { return val; } } }