content: /*
   * 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(() -> {
           for (Process p : processes) {
              p.destroy();
           }
        }));
     }
  
     /**
      * it will lookup for process that are dead already, eliminating leaks.
      */
     public static void cleanupProcess() {
        for (Process p : processes) {
           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
      */
     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;
  
        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
           }
        }
     }
  }
  