Commits

ship-it  committed d85d54f

NONE: getting rid of nested 'processutils' directory that made mvn:release unhappy

  • Participants
  • Parent commits 3fd4b80
  • Branches 1.3.1

Comments (0)

Files changed (64)

+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" output="target/classes" path="src/main/java"/>
+	<classpathentry kind="src" path="src/test/java"/>
+	<classpathentry kind="src" path="src/test/resources"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+	<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
+	<classpathentry kind="output" path="target/classes"/>
+</classpath>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <parent>
+        <groupId>com.atlassian.pom</groupId>
+        <artifactId>atlassian-public-pom</artifactId>
+        <version>23</version>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>com.atlassian.utils</groupId>
+    <artifactId>atlassian-processutils</artifactId>
+    <version>1.3.2-SNAPSHOT</version>
+
+  <scm>
+      <connection>scm:hg:${basedir}</connection>
+      <developerConnection>scm:hg:${basedir}</developerConnection>
+      <url>scm:hg:${basedir}</url>
+  </scm>
+
+
+    <dependencies>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>1.4</version>
+        </dependency>
+        <dependency>
+            <groupId>log4j</groupId>
+            <artifactId>log4j</artifactId>
+            <version>1.2.15</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.sun.jdmk</groupId>
+                    <artifactId>jmxtools</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>com.sun.jmx</groupId>
+                    <artifactId>jmxri</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>javax.jms</groupId>
+                    <artifactId>jms</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.5</version>
+            <scope>test</scope>
+	    </dependency>
+    </dependencies>
+</project>

File processutils/.classpath

-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
-	<classpathentry kind="src" output="target/classes" path="src/main/java"/>
-	<classpathentry kind="src" path="src/test/java"/>
-	<classpathentry kind="src" path="src/test/resources"/>
-	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
-	<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
-	<classpathentry kind="output" path="target/classes"/>
-</classpath>

File processutils/pom.xml

-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-    <parent>
-        <groupId>com.atlassian.pom</groupId>
-        <artifactId>atlassian-public-pom</artifactId>
-        <version>23</version>
-    </parent>
-
-    <modelVersion>4.0.0</modelVersion>
-    <groupId>com.atlassian.utils</groupId>
-    <artifactId>atlassian-processutils</artifactId>
-    <version>1.3.2-SNAPSHOT</version>
-
-  <scm>
-      <connection>scm:hg:${basedir}</connection>
-      <developerConnection>scm:hg:${basedir}</developerConnection>
-      <url>scm:hg:${basedir}</url>
-  </scm>
-
-
-    <dependencies>
-        <dependency>
-            <groupId>commons-io</groupId>
-            <artifactId>commons-io</artifactId>
-            <version>1.4</version>
-        </dependency>
-        <dependency>
-            <groupId>log4j</groupId>
-            <artifactId>log4j</artifactId>
-            <version>1.2.15</version>
-            <exclusions>
-                <exclusion>
-                    <groupId>com.sun.jdmk</groupId>
-                    <artifactId>jmxtools</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>com.sun.jmx</groupId>
-                    <artifactId>jmxri</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>javax.jms</groupId>
-                    <artifactId>jms</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-        <dependency>
-            <groupId>junit</groupId>
-            <artifactId>junit</artifactId>
-            <version>4.5</version>
-            <scope>test</scope>
-	    </dependency>
-    </dependencies>
-</project>

File processutils/src/main/java/com/atlassian/utils/process/BaseInputHandler.java

-package com.atlassian.utils.process;
-
-/**
- */
-public abstract class BaseInputHandler implements InputHandler {
-    private Watchdog watchdog;
-
-    public void complete() {
-        // do nothing
-    }
-
-    public void setWatchdog(Watchdog watchdog) {
-        this.watchdog = watchdog;
-    }
-
-    public void cancelProcess() {
-        watchdog.cancel();
-    }
-
-    protected void resetWatchdog() {
-        watchdog.resetWatchdog();
-    }
-}

File processutils/src/main/java/com/atlassian/utils/process/BaseOutputHandler.java

-package com.atlassian.utils.process;
-
-/**
- */
-public abstract class BaseOutputHandler implements OutputHandler {
-    private Watchdog watchdog;
-
-    public void setWatchdog(Watchdog watchdog) {
-        this.watchdog = watchdog;
-    }
-
-    protected void resetWatchdog() {
-        if (watchdog != null) {
-            watchdog.resetWatchdog();
-        }
-    }
-
-    public void cancelProcess() {
-        watchdog.cancel();
-    }
-
-    public void complete() throws ProcessException {
-    }
-}

File processutils/src/main/java/com/atlassian/utils/process/BaseProcessHandler.java

-package com.atlassian.utils.process;
-
-/**
- */
-public abstract class BaseProcessHandler implements ProcessHandler {
-    private Watchdog watchdog;
-
-    public void setWatchdog(Watchdog watchdog) {
-        this.watchdog = watchdog;
-    }
-
-    public Watchdog getWatchdog() {
-        return watchdog;
-    }
-}

File processutils/src/main/java/com/atlassian/utils/process/BaseProcessMonitor.java

-package com.atlassian.utils.process;
-
-/**
- * Base implementation of {@link ProcessMonitor}. Useful for subclassing if you only want to implement a single
- * callback method.
- */
-public class BaseProcessMonitor implements ProcessMonitor {
-
-    public void onAfterFinished(ExternalProcess process) {
-        // does nothing
-    }
-
-    public void onBeforeStart(ExternalProcess process) {
-        // does nothing
-    }
-
-}

File processutils/src/main/java/com/atlassian/utils/process/CopyOutputHandler.java

-package com.atlassian.utils.process;
-
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.InterruptedIOException;
-
-/**
- * An Output Handler which copies the process output to a give output stream
- */
-public class CopyOutputHandler extends BaseOutputHandler {
-    private final OutputStream dest;
-
-    /**
-     * Create a CopyOutputHandler to redirect output from the process to the given stream
-     *
-     * @param dest the stream to which output is to be written
-     */
-    public CopyOutputHandler(OutputStream dest) {
-        this.dest = dest;
-    }
-
-    public void process(InputStream output) throws ProcessException {
-        try {
-            byte buffer[] = new byte[1024];
-            int num;
-            while ((num = output.read(buffer)) != -1) {
-                resetWatchdog();
-                dest.write(buffer, 0, num);
-            }
-        } catch (InterruptedIOException e) {
-            // This means the process was asked to stop which can be normal so we just finish
-        } catch (IOException e) {
-            throw new ProcessException(e);
-        }
-    }
-}

File processutils/src/main/java/com/atlassian/utils/process/ExternalProcess.java

-package com.atlassian.utils.process;
-
-public interface ExternalProcess extends Watchdog {
-
-    public ProcessHandler getHandler();
-
-    public Long getStartTime();
-
-    public void start();
-
-    public void finish();
-
-    public boolean finish(int maxWait);
-
-    public void execute();
-
-    public void executeWhile(Runnable runnable);
-
-    public String getCommandLine();
-}

File processutils/src/main/java/com/atlassian/utils/process/ExternalProcessBuilder.java

-package com.atlassian.utils.process;
-
-import org.apache.log4j.Logger;
-import org.apache.log4j.Priority;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-
-/**
- * Utility class to simplify the building of an ExternalProcess instance
- *
- */
-public class ExternalProcessBuilder {
-    private ProcessHandler handler;
-    private InputHandler input;
-    private OutputHandler output;
-    private OutputHandler error;
-    private List<ProcessMonitor> monitors = new ArrayList<ProcessMonitor>();
-    private List<String> command;
-    private Map<String, String> environment = new HashMap<String, String>();
-    private File workingDir;
-    private long timeout;
-    private boolean suppressSpecialWindowsBehaviour = false;
-    private static ExternalProcessFactory externalProcessFactory = new ExternalProcessFactory.Default();
-
-    public ExternalProcessBuilder handlers(InputHandler input, OutputHandler output, OutputHandler error) {
-        this.input = input;
-        this.output = output;
-        this.error = error;
-        return this;
-    }
-
-    public ExternalProcessBuilder handler(ProcessHandler handler) {
-        this.handler = handler;
-        return this;
-    }
-
-    public ExternalProcessBuilder handlers(OutputHandler output, OutputHandler error) {
-        return this.handlers(null, output, error);
-    }
-
-    public ExternalProcessBuilder handlers(OutputHandler output) {
-        return this.handlers(null, output, null);
-    }
-
-    public ExternalProcessBuilder handlers(InputHandler input, OutputHandler output) {
-        return this.handlers(input, output, null);
-    }
-
-    public ExternalProcessBuilder command(List<String> command, File workingDir, long timeout) {
-        this.command = command;
-        this.workingDir = workingDir;
-        this.timeout = timeout;
-        return this;
-    }
-
-    public ExternalProcessBuilder command(List<String> command, File workingDir) {
-        this.command = command;
-        this.workingDir = workingDir;
-        return this;
-    }
-
-    public ExternalProcessBuilder command(List<String> command) {
-        this.command = command;
-        return this;
-    }
-
-    public ExternalProcessBuilder timeout(long timeout) {
-        this.timeout = timeout;
-        return this;
-    }
-
-    public ExternalProcessBuilder log(Logger logger, Priority priority) {
-        addMonitor(new LoggingProcessMonitor(logger, priority));
-        return this;
-    }
-
-    public ExternalProcessBuilder log(Logger logger, Priority priority, StringObfuscator obfuscator) {
-        addMonitor(new LoggingProcessMonitor(logger, priority, obfuscator));
-        return this;
-    }
-
-    public ExternalProcessBuilder addMonitor(ProcessMonitor... monitors) {
-        for (ProcessMonitor mon : monitors) {
-            this.monitors.add(mon);
-        }
-        return this;
-    }
-
-    public ExternalProcessBuilder env(String variable, String value) {
-        environment.put(variable, value);
-        return this;
-    }
-
-    public ExternalProcessBuilder env(Map<String, String> env) {
-        environment.putAll(env);
-        return this;
-    }
-
-    /**
-     * Processes created using processutils on Windows platforms default to performing a special workaround for lossy
-     * code page conversion issues. See the implementation of {@link ExternalProcessImpl#createWinProcess(String[], String[], File)}}
-     * for the gory details. This method can be used to suppress this 'special' behaviour and behave as if it were
-     * executing on a non-Windows platform.
-     *
-     * @param suppress whether to suppress special windows behaviour
-     * @return this {@link ExternalProcessBuilder} instance
-     */
-    public ExternalProcessBuilder suppressSpecialWindowsBehaviour(boolean suppress) {
-        suppressSpecialWindowsBehaviour = suppress;
-        return this;
-    }
-
-    public ExternalProcess build() {
-        ProcessHandler h = this.handler;
-        if (this.handler == null) {
-            // no processHandler defined, create a pluggableprocesshandler
-            PluggableProcessHandler plugHandler = new PluggableProcessHandler();
-            plugHandler.setInputHandler(this.input);
-            plugHandler.setOutputHandler(this.output);
-            if (this.error != null) {
-                plugHandler.setErrorHandler(this.error);
-            } else {
-                plugHandler.setErrorHandler(new StringOutputHandler());
-            }
-
-            h = plugHandler;
-        }
-
-        return externalProcessFactory.createExternalProcess(command, timeout, workingDir, monitors, environment, suppressSpecialWindowsBehaviour, h);
-    }
-
-
-    public static void setExternalProcessFactory(ExternalProcessFactory factory) {
-        externalProcessFactory = factory;
-    }
-
-    public static void resetExternalProcessFactory() {
-        externalProcessFactory = new ExternalProcessFactory.Default();
-    }
-
-}

File processutils/src/main/java/com/atlassian/utils/process/ExternalProcessFactory.java

-package com.atlassian.utils.process;
-
-import java.io.File;
-import java.util.List;
-import java.util.Map;
-
-public interface ExternalProcessFactory {
-
-
-    ExternalProcess createExternalProcess(List<String> command, long timeout, File workingDir,
-                                          List<ProcessMonitor> monitors, Map<String, String> environment,
-                                          boolean suppressSpecialWindowsBehaviour, ProcessHandler handler);
-
-    void shutdown();
-
-    public static class Default implements ExternalProcessFactory {
-
-        public ExternalProcess createExternalProcess(List<String> command, long timeout, File workingDir,
-                                                     List<ProcessMonitor> monitors, Map<String, String> environment,
-                                                     boolean suppressSpecialWindowsBehaviour, ProcessHandler handler) {
-            ExternalProcessImpl process =  new ExternalProcessImpl(command, handler);
-            return configureProcess(process, timeout, workingDir, monitors, environment, suppressSpecialWindowsBehaviour);
-        }
-
-        public void shutdown() {
-            ExternalProcessImpl.shutdown();
-        }
-
-        protected ExternalProcess configureProcess(ExternalProcessImpl process, long timeout, File workingDir,
-                                                   List<ProcessMonitor> monitors, Map<String, String> environment,
-                                                   boolean suppressSpecialWindowsBehaviour) {
-            if (timeout > 0L) {
-                process.setTimeout(timeout);
-            }
-            process.setWorkingDir(workingDir);
-            for (ProcessMonitor monitor: monitors) {
-                if (monitor != null) {
-                    process.addMonitor(monitor);
-                }
-            }
-            if (!environment.isEmpty()) {
-                String[] env = new String[environment.size()];
-                int index = 0;
-                for (Map.Entry<String, String> entry : environment.entrySet()) {
-                    env[index++] = entry.getKey() + "=" + entry.getValue();
-                }
-                process.setEnvironment(env);
-            }
-            process.setSuppressSpecialWindowsBehaviour(suppressSpecialWindowsBehaviour);
-            return process;
-        }
-
-
-    }
-
-
-
-}

File processutils/src/main/java/com/atlassian/utils/process/ExternalProcessImpl.java

-package com.atlassian.utils.process;
-
-import org.apache.log4j.Logger;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.SynchronousQueue;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-
-/**
- * This class manages the execution of an external process, using separate threads to process
- * the process' IO requirements.
- */
-public class ExternalProcessImpl implements ExternalProcess {
-    private String[] cmdArray;
-    private File workingDir;
-    private String[] environment;
-    private ProcessHandler handler;
-    private Process process;
-    private boolean suppressSpecialWindowsBehaviour;
-
-    private List<ProcessMonitor> monitors = new ArrayList<ProcessMonitor>();
-
-    private ProcessException processException;
-
-    private LatchedRunnable outputPump;
-    private LatchedRunnable errorPump;
-    private LatchedRunnable inputPump;
-
-    private static final ExecutorService pumpThreadPool;
-
-    private long lastWatchdogReset;
-    private long timeout = 60000L;
-    private Long startTime;
-    private boolean cancelled;
-
-    public void resetWatchdog() {
-        lastWatchdogReset = System.currentTimeMillis();
-    }
-
-    public long getTimeoutTime() {
-        return lastWatchdogReset + timeout;
-    }
-
-    public boolean isTimedOut() {
-        return getTimeoutTime() < System.currentTimeMillis();
-    }
-
-    static {
-        ThreadFactory threadFactory = new ThreadFactory() {
-            public Thread newThread(Runnable r) {
-                return new Thread(r, "ExtProcess IO Pump");
-            }
-        };
-        pumpThreadPool = new ThreadPoolExecutor(6, Integer.MAX_VALUE, 120, TimeUnit.SECONDS,
-                                                new SynchronousQueue<Runnable>(), threadFactory);
-    }
-
-    /**
-     * Process an external command.
-     * @param cmdArray the command and its arguments as separate elements
-     * @param handler The handler for this execution. The handler supports the required IO
-     *                operations
-     */
-    public ExternalProcessImpl(String[] cmdArray, ProcessHandler handler) {
-        setCommand(cmdArray);
-        setHandler(handler);
-    }
-
-    /**
-     * Process an external command (the command and arguments are given as a list)
-     * @param command A list containing the command and its arguments
-     * @param handler The process handler to manage the execution of this process.
-     */
-    public ExternalProcessImpl(List<String> command, ProcessHandler handler) {
-        setCommand(command.toArray(new String[command.size()]));
-        setHandler(handler);
-    }
-
-    /**
-     * Process an external command. The command is given as a single command line and parsed into
-     * the command and its arguments. Spaces are used as argument delimiters so if any command arguments
-     * need to contain spaces, the array or list based constructors should be used.
-     *
-     * @param commandLine the command and its arguments in a single line. If any arguments
-     *                    need to contain spaces, the array or list based constructors should be used.
-     * @param handler The handler for this execution. The handler supports the required IO
-     *                operations
-     */
-    public ExternalProcessImpl(String commandLine, ProcessHandler handler) {
-        String[] cmdArray = ProcessUtils.tokenizeCommand(commandLine);
-        setCommand(cmdArray);
-        setHandler(handler);
-    }
-
-    private void setHandler(ProcessHandler handler) {
-        this.handler = handler;
-    }
-
-    private void setCommand(String[] cmdArray) {
-        this.cmdArray = cmdArray;
-    }
-
-    public void setWorkingDir(File workingDir) {
-        this.workingDir = workingDir;
-    }
-
-    public void setEnvironment(String[] environment) {
-        this.environment = environment;
-    }
-
-    public void setSuppressSpecialWindowsBehaviour(final boolean suppressSpecialWindowsBehaviour) {
-        this.suppressSpecialWindowsBehaviour = suppressSpecialWindowsBehaviour;
-    }
-
-    private boolean arePumpsRunning() {
-        return outputPump.isRunning() || errorPump.isRunning()
-                || (inputPump != null && inputPump.isRunning());
-    }
-
-    /**
-     * Get the process handler for this process execution
-     *
-     * @return the ProcessHandler instance associated with this process execution.
-     */
-    public ProcessHandler getHandler() {
-        return handler;
-    }
-
-    /**
-     * @return the time process execution started. null if the process has not yet started.
-     */
-    public Long getStartTime() {
-        return this.startTime;
-    }
-
-    public void addMonitor(ProcessMonitor monitor) {
-        this.monitors.add(monitor);
-    }
-
-    public void removeMonitor(ProcessMonitor monitor) {
-        this.monitors.remove(monitor);
-    }
-
-    private boolean isWindows() {
-    	return System.getProperty("os.name").toLowerCase().contains("windows");
-    }
-
-    private String quoteString(String value) {
-        StringBuilder builder = new StringBuilder()
-            .append("\"")
-            .append(value.replace("\"", "\\\""))
-            .append("\"");
-        return builder.toString();
-    }
-
-    /*
-      * This method provides a workaround for a JVM bug on windows (see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4947220). The bug
-      * is that the Sun/Oracle JVM uses the (8 bit) OEM codepage for encoding commandline arguments that are passed to an external process.  Any
-      * characters in a command line argument that can't be represented in the OEM codepage will be replaced by the '?' character, which will probably
-      * cause the command that's being called to fail.
-      *
-      * A bit of background information is helpful to understand what's going on. Windows uses 2 code pages: the OEM code page and the ANSI code page
-      * (or 'Windows code page'). The OEM code page is always limited to 8 bit character encodings, whereas some windows code pages are 8 bit and some
-      * are larger. The OEM code page is typically used for console applications, whereas the windows code pages are used for native non-Unicode application
-      * using a GUI on Windows systems.  The system-wide settings can be found in the windows registry:
-      *
-      *
-      * More info about the history of OEM vs ANSI code pages: http://blogs.msdn.com/b/michkap/archive/2005/02/08/369197.aspx
-      *
-      * The workaround is to store the command-line arguments in environment variables and refer to the environment vars on the command line. Windows
-      * cmd will expand the command line arguments without using to the OEM code page, which usually has more correlation with the locale of the
-      * producer of the hardware (it's derived from the BIOS code page) than with the regional settings configured in Windows. The ANSI code page is derived from
-      * the regional settings.
-      *
-      * When cmd expands the %JENV_XXX% vars on the command line it uses the ANSI code page instead of the OEM code page (or that is what testing
-      * seems to indicate, can't find any definitive answer in the cmd docos). While this still isn't a true fix to the problem, for most situations this will be sufficient
-      * as the user typically won't use characters that aren't defined for his locale. But then again, they might..
-     */
-    private Process createWinProcess(String[] cmdArray, String[] environment, File workingDir) throws IOException {
-        Map<String, String> newEnv = new HashMap<String, String>();
-        if (environment == null) {
-            // inherit the environment of the current process
-            newEnv.putAll(System.getenv());
-        } else {
-            // add the env entries
-            for (String env: environment) {
-                String[] values = env.split("=");
-                if (values.length > 1) {
-                    newEnv.put(values[0], values[1]);
-                }
-            }
-        }
-        int extraArgs = 3;
-        String[] i18n = new String[cmdArray.length + extraArgs];
-        i18n[0] = "cmd";
-        i18n[1] = "/A"; // use ANSI encoding
-        i18n[2] = "/C";
-        i18n[extraArgs] = cmdArray[0];
-        for (int counter = 1; counter < cmdArray.length; counter++) {
-            String envName = "JENV_" + counter;
-            i18n[counter + extraArgs] = "%" + envName + "%";
-            newEnv.put(envName, quoteString(cmdArray[counter]));
-        }
-        cmdArray = i18n;
-
-        ProcessBuilder pb = new ProcessBuilder(cmdArray);
-        pb.directory(workingDir);
-        Map<String, String> env = pb.environment();
-        env.putAll(newEnv);
-        return pb.start();
-    }
-
-    protected Process createProcess(String[] cmdArray, String[] environment, File workingDir) throws IOException {
-        if (isWindows() && !suppressSpecialWindowsBehaviour) {
-            return createWinProcess(cmdArray, environment, workingDir);
-        } else {
-            return Runtime.getRuntime().exec(cmdArray, environment, workingDir);
-        }
-    }
-
-    /**
-     * Start the external process and setup the IO pump threads needed to
-     * manage the process IO. If you call this method you must eventually call the
-     * finish() method. Using this method you may execute additional code between process
-     * start and finish.
-     */
-    public void start() {
-        try {
-            this.startTime = System.currentTimeMillis();
-            this.process = createProcess(cmdArray, environment, workingDir);
-            setupIOPumps();
-        } catch (IOException e) {
-            processException = new ProcessException(e);
-        }
-    }
-
-    private void setupIOPumps() {
-        // set up threads to feed data to and extract data from the process
-        if (handler.hasInput()) {
-            inputPump = new LatchedRunnable() {
-                protected void doTask() {
-                    handler.provideInput(process.getOutputStream());
-                }
-            };
-        }
-
-        errorPump = new LatchedRunnable() {
-            protected void doTask() {
-                try {
-                    handler.processError(process.getErrorStream());
-                } catch (Throwable e) {
-                    if (!isCancelled()) {
-                        processException = new ProcessException(e);
-                    }
-                }
-            }
-        };
-
-        outputPump = new LatchedRunnable() {
-            protected void doTask() {
-                try {
-                    handler.processOutput(process.getInputStream());
-                } catch (Throwable e) {
-                    if (!isCancelled()) {
-                        processException = new ProcessException(e);
-                    }
-                }
-            }
-        };
-
-        // tickle the dog initially
-        resetWatchdog();
-        handler.setWatchdog(this);
-
-        pumpThreadPool.execute(errorPump);
-        pumpThreadPool.execute(outputPump);
-        if (inputPump != null) {
-            pumpThreadPool.execute(inputPump);
-        }
-    }
-
-    /**
-     * Finish process execution. This method should be called after you have called the
-     * start() method.
-     */
-    public void finish() {
-        if (process != null) {
-            try {
-                do {
-                    long checkTime = getTimeoutTime();
-                    awaitPump(outputPump, checkTime);
-                    awaitPump(inputPump, checkTime);
-                    awaitPump(errorPump, checkTime);
-                } while (!isTimedOut() && arePumpsRunning());
-            } finally {
-                int exitCode = 0;
-                if (!cancelled) {
-                    exitCode = wrapUpProcess();
-                }
-                handler.complete(exitCode, processException);
-            }
-        } else {
-            handler.complete(-1, processException);
-        }
-    }
-
-    /**
-     * Notifies all ProcessMonitors of the 'beforeStart' event.
-     */
-    private void notifyBeforeStart() {
-        for (ProcessMonitor monitor: monitors) {
-            try {
-                monitor.onBeforeStart(this);
-            } catch (Exception e) {
-                // catch and log error, but continue
-                Logger.getLogger(ExternalProcessImpl.class).error("Error while processing 'beforeStarted' event:", e);
-            }
-        }
-    }
-
-    /**
-     * Notifies all ProcessMonitors of the 'afterFinished' event.
-     */
-    private void notifyAfterFinished() {
-        for (ProcessMonitor monitor: monitors) {
-            try {
-                monitor.onAfterFinished(this);
-            } catch (Exception e) {
-                Logger.getLogger(ExternalProcessImpl.class).error("Error while processing 'afterFinished' event:", e);
-            }
-        }
-    }
-
-    /**
-     * Execute the external command. When this method returns, the process handler
-     * provided at construction time should be consulted to collect exit code, exceptions,
-     * process output, etc.
-     */
-    public void execute() {
-        notifyBeforeStart();
-        try {
-            start();
-            finish();
-        } finally {
-            notifyAfterFinished();
-        }
-    }
-
-    /**
-     * Executes the external command. While it is running, the given runnable is executed.
-     * The external command is not checked until the runnable completes
-     *
-     * @param runnable A task to perform while the external command is running.
-     */
-    public void executeWhile(Runnable runnable) {
-        start();
-        if (runnable != null) {
-            runnable.run();
-        }
-        finish();
-    }
-
-    public String getCommandLine() {
-        StringBuilder sb = new StringBuilder();
-        for (String s : cmdArray) {
-            sb.append(s);
-            sb.append(" ");
-        }
-        return sb.toString();
-    }
-
-    /**
-     * Wait a given time for the process to finish
-     *
-     * @param maxWait the maximum amount of time in milliseconds to wait for the process to finish
-     *
-     * @return true if the process has finished.
-     */
-    public boolean finish(int maxWait) {
-        if (process != null) {
-            boolean finished = false;
-            try {
-                long endTime = System.currentTimeMillis() + maxWait;
-                awaitPump(outputPump, endTime);
-                awaitPump(inputPump, endTime);
-                awaitPump(errorPump, endTime);
-            } finally {
-                if (!arePumpsRunning()) {
-                    // process finished
-                    finished = true;
-                    int exitCode = wrapUpProcess();
-                    handler.complete(exitCode, processException);
-                }
-            }
-            return finished;
-        } else {
-            handler.complete(-1, processException);
-            return true;
-        }
-    }
-
-    private int wrapUpProcess() {
-        int exitCode = -1;
-        boolean processIncomplete = true;
-        try {
-            exitCode = process.exitValue();
-            processIncomplete = false;
-        } catch (IllegalThreadStateException e) {
-            // process still running - could be a race to have the process finish so wait a little to be sure
-            while (processIncomplete && System.currentTimeMillis() - getTimeoutTime() < 10) {
-                // we are currently before the end of the period (within 10ms slack), so process probably not ready yet
-                try {
-                    Thread.sleep(100);
-                    exitCode = process.exitValue();
-                    processIncomplete = false;
-                } catch (InterruptedException e1) {
-                    // just ignore
-                } catch (IllegalThreadStateException e2) {
-                    // ignore and try in the next loop
-                }
-            }
-        } finally {
-            process.destroy();
-        }
-
-        // make sure pumps are done
-        if (arePumpsRunning()) {
-            cancel();
-        }
-
-        if (processIncomplete) {
-            processException = new ProcessTimeoutException("process timed out");
-        }
-        return exitCode;
-    }
-
-    private void awaitPump(LatchedRunnable runnable, long latestTime) {
-        if (runnable != null) {
-            long timeout = latestTime - System.currentTimeMillis();
-            if (timeout < 1) {
-                timeout = 1;
-            }
-            runnable.await(timeout);
-        }
-    }
-
-    /**
-     * Cancel should be called if you wish to interrupt process execution.
-     */
-    public void cancel() {
-        this.cancelled = true;
-        if (outputPump != null) {
-            outputPump.cancel();
-        }
-
-        if (inputPump != null) {
-            inputPump.cancel();
-        }
-
-        if (errorPump != null) {
-            errorPump.cancel();
-        }
-        process.destroy();
-    }
-
-    public void setTimeout(long timeout) {
-        this.timeout = timeout;
-    }
-
-    public static void shutdown() {
-        if (pumpThreadPool != null) {
-            pumpThreadPool.shutdown();
-        }
-    }
-}

File processutils/src/main/java/com/atlassian/utils/process/InputHandler.java

-package com.atlassian.utils.process;
-
-import java.io.OutputStream;
-
-/**
- * A Handler for process input
- *
- * The InputHandler interface is designed to allow different input provision strategies to be plugged into
- * process handlers
- */
-public interface InputHandler {
-    void process(OutputStream input);
-    void complete();
-
-    void setWatchdog(Watchdog watchdog);
-}

File processutils/src/main/java/com/atlassian/utils/process/LatchedRunnable.java

-package com.atlassian.utils.process;
-
-import org.apache.log4j.Logger;
-import org.apache.log4j.NDC;
-
-import java.util.Stack;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Date: 16/07/2008
- * Time: 14:54:03
- */
-public abstract class LatchedRunnable implements Runnable {
-    private static Logger log = Logger.getLogger(LatchedRunnable.class);
-    private CountDownLatch latch = new CountDownLatch(1);
-    private Thread runner;
-    private boolean cancelled;
-    private Stack<?> ndcStack = NDC.cloneStack();
-
-    public final void run() {
-        try {
-            NDC.inherit(ndcStack);
-            runner = Thread.currentThread();
-            doTask();
-        } finally {
-            latch.countDown();
-            NDC.remove();
-        }
-    }
-
-    public boolean await(long millis) {
-        try {
-            return latch.await(millis, TimeUnit.MILLISECONDS);
-        } catch (InterruptedException e) {
-            log.warn("Interrupted waiting for ExternalProcess pump to complete");
-            throw new RuntimeException("Interrupted waiting for Process pump", e);
-        }
-    }
-
-    public boolean isRunning() {
-        return latch.getCount() > 0;
-    }
-
-    protected abstract void doTask();
-
-
-    public void interrupt() {
-        if (runner != null) {
-            runner.interrupt();
-        }
-    }
-
-    public void cancel() {
-        this.cancelled = true;
-    }
-
-    public boolean isCancelled() {
-        return cancelled;
-    }
-}

File processutils/src/main/java/com/atlassian/utils/process/LineOutputHandler.java

-package com.atlassian.utils.process;
-
-import java.io.Closeable;
-import java.io.InputStream;
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-import java.io.IOException;
-import java.io.InterruptedIOException;
-import java.io.UnsupportedEncodingException;
-
-/**
- * An Output Handler which breaks the output from the process into
- * discrete lines and processes each line in turn. Subclasses provide the
- * appropriate implementation of the per-line processing method.
- */
-public abstract class LineOutputHandler extends BaseOutputHandler {
-    private final String encoding;
-
-    protected LineOutputHandler() {
-        this(null); // if not encoding is defined, use the default encoding from the admin
-    }
-
-    protected LineOutputHandler(String encoding) {
-        this.encoding = encoding;
-    }
-
-    public String getEncoding() {
-        return encoding;
-    }
-    
-    public void process(InputStream output) throws ProcessException {
-        if (encoding == null) {
-            process(new BufferReaderLineReader(new BufferedReader(new InputStreamReader(output))));
-        } else {
-            try {
-                process(new BufferReaderLineReader(new BufferedReader(new InputStreamReader(output, encoding))));
-            } catch (UnsupportedEncodingException e) {
-                throw new ProcessException(e);
-            }
-        }
-    }
-
-    protected void process(LineReadable reader) throws ProcessException {
-        int counter = 0;
-        try {
-            String line;
-            while ((line = reader.readLine()) != null) {
-                resetWatchdog();
-                processLine(counter++, line);
-            }
-            processInputEnd(counter);
-        } catch (InterruptedIOException e) {
-            // This means the process was asked to stop which can be normal so we just finish
-            processEndByException(counter);
-        } catch (IOException e) {
-            processEndByException(counter);
-            throw new ProcessException(e);
-        } finally {
-            closeQuietly(reader);
-        }
-    }
-
-    private void closeQuietly(Closeable closeable) {
-        try {
-            if (closeable != null) {
-                closeable.close();
-            }
-        } catch (IOException ioe) {
-            // ignore
-        }
-    }
-
-    protected void processEndByException(int counter) {
-        // do nothing by default
-    }
-
-    /**
-     * Input has finished
-     *
-     * @param lineCount total number of lines processed
-     */
-    protected void processInputEnd(int lineCount) throws ProcessException {
-        // do nothing by default
-    }
-
-    /**
-     * Process the given line
-     *
-     * @param lineNum The line number of the line being processed
-     * @param line the content of the line
-     */
-    protected abstract void processLine(int lineNum, String line);
-    
-    static class BufferReaderLineReader implements LineReadable {
-
-        private final BufferedReader reader;
-
-        BufferReaderLineReader(BufferedReader reader) {
-            this.reader = reader;
-        } 
-
-        public String readLine() throws IOException {
-            return reader.readLine();
-        }
-
-        public void close() throws IOException {
-            reader.close();
-        }
-    }
-
-}

File processutils/src/main/java/com/atlassian/utils/process/LineReadable.java

-package com.atlassian.utils.process;
-
-import java.io.Closeable;
-import java.io.IOException;
-
-public interface LineReadable extends Closeable {
-
-    String readLine() throws IOException;
-
-}

File processutils/src/main/java/com/atlassian/utils/process/LoggingProcessMonitor.java

-package com.atlassian.utils.process;
-
-import org.apache.log4j.Logger;
-import org.apache.log4j.Priority;
-
-/**
- * ProcessMonitor that logs the results to the provided {@link Logger} using the provided {@link Priority}. When
- * the external process does not succeed, the error messages are logged using the info priority.
- */
-public class LoggingProcessMonitor implements ProcessMonitor {
-    private Logger logger;
-    private Priority priority;
-    private StringObfuscator obfuscator;
-    
-    public LoggingProcessMonitor(Logger logger, Priority priority) {
-        this.logger = logger;
-        this.priority = priority;
-    }
-
-    public LoggingProcessMonitor(Logger logger, Priority priority, StringObfuscator obfuscator) {
-        this(logger, priority);
-        this.obfuscator = obfuscator;
-    }
-    
-    protected String obfuscate(String value) {
-        if (obfuscator != null) {
-            return obfuscator.obfuscate(value);
-        } else {
-            return value;
-        }
-    }
-    
-    /**
-     * @param process the external process.
-     * @return the command line. 
-     */
-    protected String getCommandLine(ExternalProcess process) {
-        return obfuscate(process.getCommandLine());
-    }
-
-    /**
-     * Logs message to Log4j logger
-     */
-    public void onBeforeStart(ExternalProcess process) {
-        if (this.logger != null && this.logger.isEnabledFor(this.priority)) {
-            logger.log(this.priority, "Starting process: " + getCommandLine(process));
-        }
-    }
-
-    /**
-     * Logs message to Log4j logger
-     */
-    public void onAfterFinished(ExternalProcess process) {
-        if (this.logger != null && this.logger.isEnabledFor(this.priority)) {
-            StringBuilder message = new StringBuilder();
-            String commandLine = getCommandLine(process);
-            message.append("Finished process: ").append(commandLine);
-            Long startTime = process.getStartTime();
-            if (startTime != null) {
-            	message.append(" took ").append(System.currentTimeMillis() - startTime.longValue()).append("ms");
-            }
-            logger.log(priority, message.toString());
-            
-            // log errors if present
-            ProcessHandler handler = process.getHandler();
-            if (handler != null && !handler.succeeded()) {
-                logger.info(getErrorMessage(process));
-            }
-        }
-    }
-    
-    public String getErrorMessage(ExternalProcess process) {
-        ProcessHandler handler = process.getHandler();
-        String commandLine = getCommandLine(process);
-        StringBuilder message = new StringBuilder();
-
-        if (handler.getException() != null) {
-            message.append("Exception executing command \"")
-                .append(commandLine).append("\" ")
-                .append(handler.getException().getMessage()).append("\n")
-                .append(handler.getException()).append("\n");
-        }
-
-        String reason = null;
-        if (handler instanceof PluggableProcessHandler) {
-            OutputHandler errorHandler = ((PluggableProcessHandler) handler).getErrorHandler();
-            if (errorHandler instanceof StringOutputHandler) {
-                StringOutputHandler errorStringHandler = (StringOutputHandler) errorHandler;
-                if (errorStringHandler.getOutput() != null) {
-                    reason = errorStringHandler.getOutput();
-                }
-            }
-        }
-        if (reason != null && reason.trim().length() > 0) {
-            message.append("Error executing command \"").append(commandLine).append("\": ").append(reason);
-        }
-        return obfuscate(message.toString());
-    }
-}

File processutils/src/main/java/com/atlassian/utils/process/OutputHandler.java

-package com.atlassian.utils.process;
-
-import java.io.InputStream;
-
-/**
- * A Handler for process output
- *
- * The OutputHandler interface is designed to allow different output handling strategies to be plugged into
- * process handlers
- */
-public interface OutputHandler {
-    /**
-     * Process an output stream generated by the external process (either stdout or stderr)
-     *
-     * @param output the external process' output stream (available as an input to this class)
-     * @throws ProcessException if there is a problem processing the output
-     */
-    void process(InputStream output) throws ProcessException;
-
-    /**
-     * Called when the process completes. This call allows the output handler to close any
-     * open resources and finalize any processing.
-     *
-     * @throws ProcessException if there is a problem completing processing
-     */
-    void complete() throws ProcessException;
-
-    /**
-     * Set the watchdog that this handler should be resetting to prevent the process from being terminated.
-     * The watchdog should be called periodically based on output generated by the process.
-     *
-     * @param watchdog process watchdog instance.
-     */
-    void setWatchdog(Watchdog watchdog);
-}

File processutils/src/main/java/com/atlassian/utils/process/PluggableProcessHandler.java

-package com.atlassian.utils.process;
-
-import org.apache.log4j.Logger;
-
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * An implementation of a ProcessHandler where the processors for the process' IO streams can
- * be plugged in.
- *
- */
-public class PluggableProcessHandler extends BaseProcessHandler {
-    private int exitCode;
-    private ProcessException exception;
-
-    private OutputHandler outputHandler;
-    private OutputHandler errorHandler;
-    private InputHandler inputHandler;
-
-    private boolean complete;
-    private boolean throwOnNonZeroExit = true;
-
-    private static final Logger LOGGER = Logger.getLogger(PluggableProcessHandler.class);
-
-    public PluggableProcessHandler() {
-    }
-
-    public void processOutput(InputStream processOutput) throws ProcessException {
-        if (outputHandler == null) {
-            throw new IllegalStateException("Process output received with no handler");
-        }
-        outputHandler.setWatchdog(getWatchdog());
-        outputHandler.process(processOutput);
-    }
-
-    public void processError(InputStream processError) throws ProcessException {
-        if (errorHandler == null) {
-            throw new IllegalStateException("Process error output received with no handler");
-        }
-        errorHandler.setWatchdog(getWatchdog());
-        errorHandler.process(processError);
-    }
-
-    public boolean hasInput() {
-        return inputHandler != null;
-    }
-
-    public void provideInput(OutputStream processInput) {
-        if (!hasInput()) {
-            throw new IllegalStateException("Attempt to read input without an input handler");
-        }
-        inputHandler.setWatchdog(getWatchdog());
-        inputHandler.process(processInput);
-    }
-
-    public void complete(int code, ProcessException pe) {
-        this.exitCode = code;
-        this.exception = pe;
-        if (outputHandler != null) {
-            try {
-                outputHandler.complete();
-            } catch (Throwable e) {
-                setException(e);
-            }
-        }
-        if (errorHandler != null) {
-            try {
-                errorHandler.complete();
-            } catch (Throwable e) {
-                setException(e);
-            }
-        }
-        if (inputHandler != null) {
-            try {
-                inputHandler.complete();
-            } catch (Throwable e) {
-                setException(e);
-            }
-        }
-
-        if (pe == null && code != 0 && throwOnNonZeroExit) {
-            setException(new ProcessException("Non-zero exit code: " + code, code));
-        }
-        complete = true;
-    }
-
-    public int getExitCode() {
-        return exitCode;
-    }
-
-    public ProcessException getException() {
-        return exception;
-    }
-
-    public void setException(Throwable e) {
-        if (exception == null) {
-            if (e instanceof ProcessException) {
-                this.exception = (ProcessException) e;
-            } else {
-                this.exception = new ProcessException(e);
-            }
-        } else {
-            LOGGER.debug("Ignored exception as exception for handler is already set", e);
-        }
-    }
-
-    public String getError() {
-        return null;
-    }
-
-    public void setOutputHandler(OutputHandler outputHandler) {
-        this.outputHandler = outputHandler;
-    }
-
-    public void setErrorHandler(OutputHandler errorHandler) {
-        this.errorHandler = errorHandler;
-    }
-
-    public void setInputHandler(InputHandler inputHandler) {
-        this.inputHandler = inputHandler;
-    }
-
-    public OutputHandler getOutputHandler() {
-        return outputHandler;
-    }
-
-    public OutputHandler getErrorHandler() {
-        return errorHandler;
-    }
-
-    public InputHandler getInputHandler() {
-        return inputHandler;
-    }
-
-    public boolean succeeded() {
-        return exception == null;
-    }
-
-    public void reset() {
-        exitCode = 0;
-        exception = null;
-        complete = false;
-    }
-
-    public boolean isComplete() {
-        return complete;
-    }
-
-    public boolean isThrowOnNonZeroExit() {
-        return throwOnNonZeroExit;
-    }
-
-    public void setThrowOnNonZeroExit(boolean throwOnNonZeroExit) {
-        this.throwOnNonZeroExit = throwOnNonZeroExit;
-    }
-}

File processutils/src/main/java/com/atlassian/utils/process/ProcessException.java

-package com.atlassian.utils.process;
-
-/**
- * Exceptions thrown while running external processes
- */
-public class ProcessException extends Exception {
-    int exitCode;
-
-    public ProcessException(String message, Throwable cause) {
-        super(message, cause);
-        exitCode = extractExitCode(cause);
-    }
-
-    private static int extractExitCode(Throwable cause) {
-        // Trawl the whole chain looking for a process exception - copy it's exit code.
-        while (cause != null) {
-            if (cause instanceof ProcessException) {
-                return ((ProcessException) cause).getExitCode();
-            }
-            cause = cause.getCause();
-        }
-        return 0;
-    }
-
-    public ProcessException(String message) {
-        super(message);
-    }
-
-    public ProcessException(Throwable e) {
-        super(e);
-        exitCode = extractExitCode(e);
-    }
-
-    public ProcessException(String message, int exitCode) {
-        super(message);
-        this.exitCode = exitCode;
-    }
-
-    public int getExitCode() {
-        return exitCode;
-    }
-}

File processutils/src/main/java/com/atlassian/utils/process/ProcessHandler.java

-package com.atlassian.utils.process;
-
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * Interface used to manage the IO and termination needs of an external processes
- * managed by ExternalProcess.  The methods of this interface will be called by
- * different threads, so implementors should take care to ensure thread safety
- *
- * @see com.atlassian.utils.process.ExternalProcess
- */
-public interface ProcessHandler {
-    /**
-     * Process the process stdout stream
-     *
-     * @param output the external process' output stream (available as an input to this class)
-     * @throws ProcessException if there is a problem processing the output
-     */
-    void processOutput(InputStream output) throws ProcessException;
-
-    /**
-     * Process the process stderr stream
-     *
-     * @param error the external process' standard error stream (available as an input to this class)
-     * @throws ProcessException if there is a problem processing the output
-     */
-    void processError(InputStream error) throws ProcessException;
-
-    /**
-     * Indicate if this handler has input to provide to the process
-     *
-     * @return true if input is available
-     */
-    boolean hasInput();
-
-    /**
-     * Provide input to the external process. Input is provided by writing the content to the
-     * given output stream. This method will only be called if hasInput() returns true
-     *
-     * @param input the output stream representing standard input to the external process
-     * @throws IllegalStateException if no input has been configured.
-     */
-    void provideInput(OutputStream input);
-
-    /**
-     * Called when the external process has completed
-     *
-     * @param exitCode the exit code of the external process
-     * @param exception any process exceptions that were thrown within the VM when handling the
-     *        external process
-     */
-    void complete(int exitCode, ProcessException exception);
-
-    /**
-     * Indicate if the process has completed
-     *
-     * @return true if complete has been called.
-     */
-    boolean isComplete();
-
-    /**
-     * Set the watchdog associated with this handler. The watchdog should be called at regular intervals
-     * to prevent the external process being terminated. Typically this is done in the IO handling methods
-     *
-     * @return the handler's watchdog instance
-     */
-    void setWatchdog(Watchdog watchdog);
-
-    /**
-     * Indicate if the process execution has been considered successful.
-     *
-     * @return true if the process execution completed without error
-     */
-    boolean succeeded();
-
-    /**
-     * Called if the process is to be re-executed.
-     */
-    void reset();
-
-    /**
-     * Get any processing exception associated with this handler
-     * @return a processing exception instance or null if no exception occurred.
-     */
-    ProcessException getException();
-
-    /**
-     * Get the process exit code
-     * @return process exit code
-     */
-    int getExitCode();
-}
-

File processutils/src/main/java/com/atlassian/utils/process/ProcessMonitor.java

-package com.atlassian.utils.process;
-
-/**
- * Interface for monitoring an external process.
- * 
- *  @see ExternalProcess 
- */
-public interface ProcessMonitor {
-    /**
-     * Call-back method, called just before the external process is started.
-     * @param process the {@link ExternalProcess} that is about to be started.
-     */
-    void onBeforeStart(ExternalProcess process);
-    
-    /**
-     * Call-back method, called right after the external process has finished. The process might have
-     * been finished normally, in an error, or canceled.
-     * @param process the {@link ExternalProcess} that has just finished.
-     */
-    void onAfterFinished(ExternalProcess process);
-}

File processutils/src/main/java/com/atlassian/utils/process/ProcessTimeoutException.java

-package com.atlassian.utils.process;
-
-/**
- *
- * This ProcessException is thrown when a process does not complete within the specified timeout period.
- *
- */
-public class ProcessTimeoutException extends ProcessException {
-
-    private static final long serialVersionUID = 5607536120405113374L;
-
-    public ProcessTimeoutException(String message, Throwable cause) {
-        super(message, cause);
-    }
-
-    public ProcessTimeoutException(String message) {
-        super(message);