/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.activemq.artemis.cli.process; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import org.apache.activemq.artemis.utils.collections.ConcurrentHashSet; public class ProcessBuilder { static ConcurrentHashSet<Process> processes = new ConcurrentHashSet<>(); static { Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { for (Process p : processes) { // if (p.isAlive()) { p.destroy(); } } } }); } /** * it will lookup for process that are dead already, eliminating leaks. */ public static void cleanupProcess() { for (Process p : processes) { // if (!p.isAlive()) { processes.remove(p); } } } /** * * * * @param logname the prefix for log output * @param location The location where this command is being executed from * @param hook it will finish the process upon shutdown of the VM * @param args The arguments being passwed to the the CLI tool * @return * @throws Exception */ public static Process build(String logname, File location, boolean hook, String... args) throws Exception { boolean IS_WINDOWS = System.getProperty("os.name").toLowerCase().trim().startsWith("win"); String[] newArgs; if (IS_WINDOWS) { newArgs = rebuildArgs(args, "cmd", "/c", "artemis.cmd"); } else { newArgs = rebuildArgs(args, "./artemis"); } java.lang.ProcessBuilder builder = new java.lang.ProcessBuilder(newArgs); builder.directory(new File(location, "bin")); Process process = builder.start(); ProcessLogger outputLogger = new ProcessLogger(true, process.getInputStream(), logname, false); outputLogger.start(); // Adding a reader to System.err, so the VM won't hang on a System.err.println as identified on this forum thread: ProcessLogger errorLogger = new ProcessLogger(true, process.getErrorStream(), logname, true); errorLogger.start(); processes.add(process); cleanupProcess(); return process; } public static String[] rebuildArgs(String[] args, String... prefixArgs) { String[] resultArgs = new String[args.length + prefixArgs.length]; int i = 0; for (String arg : prefixArgs) { resultArgs[i++] = arg; } for (String arg : args) { resultArgs[i++] = arg; } return resultArgs; } /** * Redirect the input stream to a logger (as debug logs) */ static class ProcessLogger extends Thread { private final InputStream is; private final String logName; private final boolean print; private final boolean sendToErr; boolean failed = false; ProcessLogger(final boolean print, final InputStream is, final String logName, final boolean sendToErr) throws ClassNotFoundException { this.is = is; this.print = print; this.logName = logName; this.sendToErr = sendToErr; setDaemon(false); } @Override public void run() { try { InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); String line; while ((line = br.readLine()) != null) { if (print) { if (sendToErr) { System.err.println(logName + "-err:" + line); } else { System.out.println(logName + "-out:" + line); } } } } catch (IOException e) { // ok, stream closed } } } }