/** * (C) Copyright IBM Corporation 2014. * * 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.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.ResourceBundle; import java.util.Scanner; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; public abstract class AbstractTask extends Task { protected File installDir; protected File userDir; protected File outputDir; protected File serverConfigDir = null; protected File serverOutputDir = null; protected String serverName; protected String ref; protected static String osName; protected static boolean isWindows; protected ProcessBuilder processBuilder; protected static final String DEFAULT_SERVER = "defaultServer"; protected static final String DEFAULT_LOG_FILE = "logs/messages.log"; protected static final String WLP_USER_DIR_VAR = "WLP_USER_DIR"; protected static final String WLP_OUTPUT_DIR_VAR = "WLP_OUTPUT_DIR"; protected static final ResourceBundle messages = ResourceBundle.getBundle("net.wasdev.wlp.ant.AntMessages"); protected void initTask() { if (ref != null) { Object serverRef = getProject().getReference(ref); if (serverRef != null && (serverRef instanceof ServerTask)) { setInstallDir(((ServerTask) serverRef).getInstallDir()); setServerName(((ServerTask) serverRef).getServerName()); setUserDir(((ServerTask) serverRef).getUserDir()); setOutputDir(((ServerTask) serverRef).getOutputDir()); } } try { if (installDir != null) { installDir = installDir.getCanonicalFile(); // Quick sanity check File file = new File(installDir, "lib/ws-launch.jar"); if (!file.exists()) { throw new BuildException(messages.getString("error.installDir.set")); } log(MessageFormat.format(messages.getString("info.variable"), "installDir", installDir.getCanonicalPath()), Project.MSG_VERBOSE); } else { throw new BuildException("Liberty installation directory must be set."); } if (serverName == null) { setServerName(DEFAULT_SERVER); } processBuilder = new ProcessBuilder(); if (userDir != null) { log(MessageFormat.format(messages.getString("info.variable"), "userDir", userDir.getCanonicalPath()), Project.MSG_VERBOSE); processBuilder.environment().put(WLP_USER_DIR_VAR, userDir.getCanonicalPath()); serverConfigDir = new File(userDir, "servers/" + serverName); } else { String wlpUserDir = processBuilder.environment().get(WLP_USER_DIR_VAR); if (wlpUserDir != null) { log(MessageFormat.format(messages.getString("info.variable"), "WLP_USER_DIR", wlpUserDir), Project.MSG_VERBOSE); serverConfigDir = new File(wlpUserDir, "servers/" + serverName); } else { serverConfigDir = new File(installDir, "usr/servers/" + serverName); } } log(MessageFormat.format(messages.getString("info.variable"), "server.config.dir", serverConfigDir.getCanonicalPath())); if (outputDir != null) { log(MessageFormat.format(messages.getString("info.variable"), "outputDir", outputDir.getCanonicalPath()), Project.MSG_VERBOSE); processBuilder.environment().put(WLP_OUTPUT_DIR_VAR, outputDir.getCanonicalPath()); serverOutputDir = new File(outputDir, serverName); } else { String wlpOutputDir = processBuilder.environment().get(WLP_OUTPUT_DIR_VAR); if (wlpOutputDir != null) { log(MessageFormat.format(messages.getString("info.variable"), "WLP_OUTPUT_DIR", wlpOutputDir), Project.MSG_VERBOSE); serverOutputDir = new File(wlpOutputDir, serverName); } else { serverOutputDir = serverConfigDir; } } log(MessageFormat.format(messages.getString("info.variable"), "server.output.dir", serverOutputDir.getCanonicalPath())); } catch (IOException e) { throw new BuildException(e); } // Check for windows.. osName = System.getProperty("os.name", "unknown").toLowerCase(); isWindows = osName.indexOf("windows") >= 0; } public File getInstallDir() { return installDir; } public void setInstallDir(File installDir) { this.installDir = installDir; } public File getUserDir() { return userDir; } public void setUserDir(File userDir) { this.userDir = userDir; } public File getOutputDir() { return outputDir; } public void setOutputDir(File outputDir) { this.outputDir = outputDir; } /** * @return the serverName */ public String getServerName() { return serverName; } /** * @param serverName * the serverName to set */ public void setServerName(String serverName) { this.serverName = serverName; } public File getLogFile() { return new File(serverOutputDir, DEFAULT_LOG_FILE); } /** * @return the ref */ public String getRef() { return ref; } /** * @param ref the ref to set */ public void setRef(String ref) { this.ref = ref; } protected int getReturnCode(Process p, String commandLine) throws InterruptedException { log(MessageFormat.format(messages.getString("info.variable"), "Invoke command", commandLine, Project.MSG_VERBOSE)); StreamCopier copier = new StreamCopier(p.getInputStream()); copier.start(); int exitVal = p.waitFor(); copier.doJoin(); return exitVal; } public void checkReturnCode(Process p, String commandLine, int... expectedExitCodes) throws InterruptedException { int exitVal = getReturnCode(p, commandLine); for (int expectedExitCode : expectedExitCodes) { if (exitVal == expectedExitCode) { return; } } throw new BuildException(MessageFormat.format(messages.getString("error.invoke.command"), commandLine, exitVal, Arrays.toString(expectedExitCodes))); } private class StreamCopier extends Thread { private final BufferedReader reader; private boolean joined; private boolean terminated; StreamCopier(InputStream input) { this.reader = new BufferedReader(new InputStreamReader(input)); setDaemon(true); } @Override public void run() { try { for (String line; (line = reader.readLine()) != null;) { synchronized (this) { if (joined) { // The main thread was notified that the process // ended and has already given up waiting for // output from the foreground process. break; } log(line); } } } catch (IOException ex) { throw new BuildException(ex); } finally { if (isWindows) { synchronized (this) { terminated = true; notifyAll(); } } } } public void doJoin() throws InterruptedException { if (isWindows) { // Windows doesn't disconnect background processes (start /b) // from the console of foreground processes, so waiting until // the end of output from server.bat means waiting until the // server process itself ends. We can't wait that long, so we // wait one second after .waitFor() ends. Hopefully this will // be long enough to copy all the output from the script. synchronized (this) { long begin = System.nanoTime(); long end = begin + TimeUnit.NANOSECONDS.convert(1, TimeUnit.SECONDS); long duration = end - begin; while (!terminated && duration > 0) { TimeUnit.NANOSECONDS.timedWait(this, duration); duration = end - System.nanoTime(); } // If the thread didn't end after waiting for a second, // then assume it's stuck in a blocking read. Oh well, // it's a daemon thread, so it'll go away eventually. Let // it know that we gave up to avoid spurious output in case // it eventually wakes up. joined = true; } } else { super.join(); } } } /** * Check for a number of strings in a potentially remote file * * @param regexp * a regular expression to search for * @param timeout * a timeout, in milliseconds * @param outputFile * file to check * @return line that matched the regexp */ public String waitForStringInLog(String regexp, long timeout, File outputFile) { int waited = 0; final int waitIncrement = 500; log(MessageFormat.format(messages.getString("info.search.string"), regexp, outputFile.getAbsolutePath(), timeout / 1000)); try { while (waited <= timeout) { String string = findStringInFile(regexp, outputFile); if (string == null) { try { Thread.sleep(waitIncrement); } catch (InterruptedException e) { // Ignore and carry on } waited += waitIncrement; } else { return string; } } log(MessageFormat.format(messages.getString("error.serch.string.timeout"), regexp, outputFile.getAbsolutePath())); } catch (Exception e) { // I think we can assume if we can't read the file it doesn't // contain our string throw new BuildException(e); } return null; } /** * Searches the given file for the given regular expression. * * @param regexp * a regular expression (or just a text snippet) to search for * @param fileToSearch * the file to search * @return The first line which includes the pattern, or null if the pattern * isn't found or if the file doesn't exist * @throws Exception */ protected String findStringInFile(String regexp, File fileToSearch) throws Exception { String foundString = null; List<String> matches = findStringsInFileCommon(regexp, true, -1, fileToSearch); if (matches != null && !matches.isEmpty()) { foundString = matches.get(0); } return foundString; } /** * Searches the given file for the given regular expression. * * @param regexp * a regular expression (or just a text snippet) to search for * @param fileToSearch * the file to search * @return List of Strings which match the pattern. No match results in an * empty list. * @throws Exception */ protected List<String> findStringsInFileCommon(String regexp, boolean stopOnFirst, int searchLimit, File fileToSearch) throws Exception { if (fileToSearch == null) { log(messages.getString("info.file.validated")); return null; } if (!fileToSearch.exists()) { log(MessageFormat.format(messages.getString("info.file.validate.noexist"), fileToSearch.getCanonicalPath())); return null; } InputStream serverOutput = null; InputStreamReader in = null; Scanner s = null; List<String> matches = null; try { // Read file and search serverOutput = new FileInputStream(fileToSearch); in = new InputStreamReader(serverOutput); s = new Scanner(in); log(MessageFormat.format(messages.getString("info.look.string.infile"), regexp, fileToSearch.getName()), Project.MSG_VERBOSE); String foundString = null; Pattern pattern = Pattern.compile(regexp); matches = new ArrayList<String>(); while (s.hasNextLine()) { if (foundString != null && stopOnFirst) { break; } if (searchLimit <= 0 && searchLimit >= matches.size()) { break; } String line = s.nextLine(); if (pattern.matcher(line).find()) { foundString = line; matches.add(line); log(MessageFormat.format(messages.getString("info.match.string"), matches.size(), line)); } } } catch (Exception e) { log(e.toString()); } finally { try { s.close(); } catch (Exception e) { // Ignore } try { serverOutput.close(); } catch (Exception e) { // Ignore } try { in.close(); } catch (Exception e) { //Ignore } } return matches; } /* * Returns file name without the extension. */ protected String getFileName(String fileName) { int index = fileName.lastIndexOf('.'); return (index == -1) ? fileName : fileName.substring(0, index); } protected void stopServer(String timeout) { //Stop server if exception happens. ServerTask st = new ServerTask(); st.setProject(getProject()); st.setInstallDir(getInstallDir()); st.setUserDir(getUserDir()); st.setOutputDir(getOutputDir()); st.setServerName(getServerName()); st.setTimeout(timeout); st.setOperation("stop"); st.execute(); } protected String getMessage(String key, Object... args) { return MessageFormat.format(messages.getString(key), args); } }