// Job.java package com.jdojo.process.api; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; /** * An instance of this class is used as a job that sleeps at a * regular interval up to a maximum duration. The sleep * interval in seconds can be specified as the first argument * and the sleep duration as the second argument while running. * this class. The default sleep interval and sleep duration * are 5 seconds and 60 seconds, respectively. If these values * are less than zero, zero is used instead. */ publicclassJob { // The job sleep interval publicstaticfinallongDEFAULT_SLEEP_INTERVAL=5; // The job sleep duration publicstaticfinallongDEFAULT_SLEEP_DURATION=60; publicstaticvoidmain(String[] args) { longsleepInterval= DEFAULT_SLEEP_INTERVAL; longsleepDuration= DEFAULT_SLEEP_DURATION; // Get the passed in sleep interval if (args.length >= 1) { sleepInterval = parseArg(args[0], DEFAULT_SLEEP_INTERVAL); if (sleepInterval < 0) { sleepInterval = 0; } } // Get the passed in the sleep duration if (args.length >= 2) { sleepDuration = parseArg(args[1], DEFAULT_SLEEP_DURATION); if (sleepDuration < 0) { sleepDuration = 0; } } longpid= ProcessHandle.current().getPid(); System.out.printf("Job (pid=%d) info: Sleep Interval" + "=%d seconds, Sleep Duration=%d " + "seconds.%n", pid, sleepInterval, sleepDuration); for (longsleptFor=0; sleptFor < sleepDuration; sleptFor += sleepInterval) { try { System.out.printf("Job (pid=%d) is going to" + " sleep for %d seconds.%n", pid, sleepInterval); // Sleep for the sleep interval TimeUnit.SECONDS.sleep(sleepInterval); } catch (InterruptedException ex) { System.out.printf("Job (pid=%d) was " + "interrupted.%n", pid); } } } /** * Starts a new JVM to run the Job class. * @param sleepInterval The sleep interval when the Job * class is run. It is passed to the JVM as the first * argument. * @param sleepDuration The sleep duration for the Job * class. It is passed to the JVM as the second argument. * @return The new process reference of the newly launched * JVM or null if the JVM cannot be launched. */ publicstatic Process startProcess(long sleepInterval, long sleepDuration) { // Store the command to launch a new JVM in a // List<String> List<String> cmd = newArrayList<>(); // Add command components in order addJvmPath(cmd); addModulePath(cmd); addClassPath(cmd); addMainClass(cmd); // Add arguments to run the class cmd.add(String.valueOf(sleepInterval)); cmd.add(String.valueOf(sleepDuration)); // Build the process attributes ProcessBuilderpb=newProcessBuilder() .command(cmd) .inheritIO(); StringcommandLine= pb.command() .stream() .collect(Collectors.joining(" ")); System.out.println("Command used:\n" + commandLine); // Start the process Processp=null; try { p = pb.start(); } catch (IOException e) { e.printStackTrace(); } return p; } /** * Used to parse the arguments passed to the JVM, which * in turn is passed to the main() method. * @param valueStr The string value of the argument * @param defaultValue The default value of the argument if * the valueStr is not an integer. * @return valueStr as a long or the defaultValue if * valueStr is not an integer. */ privatestaticlongparseArg(String valueStr, long defaultValue) { longvalue= defaultValue; if (valueStr != null) { try { value = Long.parseLong(valueStr); } catch (NumberFormatException e) { // no action needed } } return value; } /** * Adds the JVM path to the command list. It first attempts * to use the command attribute of the current process; * failing that it relies on the java.home system property. * @param cmd The command list */ privatestaticvoidaddJvmPath(List<String> cmd) { // First try getting the command to run the current JVM StringjvmPath= ProcessHandle.current() .info() .command().orElse(""); if(jvmPath.length() > 0) { cmd.add(jvmPath); } else { // Try composing the JVM path using the java.home // system property finalStringFILE_SEPARATOR= System.getProperty("file.separator"); jvmPath = System.getProperty("java.home") + FILE_SEPARATOR + "bin" + FILE_SEPARATOR + "java"; cmd.add(jvmPath); } } /** * Adds a module path to the command list. * @param cmd The command list */ privatestaticvoidaddModulePath(List<String> cmd) { StringmodulePath= System.getProperty("jdk.module.path"); if(modulePath != null && modulePath.trim().length() > 0) { cmd.add("--module-path"); cmd.add(modulePath); } } /** * Adds class path to the command list. * @param cmd The command list */ privatestaticvoidaddClassPath(List<String> cmd) { StringclassPath= System.getProperty("java.class.path"); if(classPath != null && classPath.trim().length() > 0) { cmd.add("--class-path"); cmd.add(classPath); } } /** * Adds a main class to the command list. Adds * module/className or just className depending on whether * the Job class was loaded in a named module or unnamed * module * @param cmd The command list */ privatestaticvoidaddMainClass(List<String> cmd) { Class<Job> cls = Job.class; StringclassName= cls.getName(); Modulemodule= cls.getModule(); if(module.isNamed()) { StringmoduleName=module.getName(); cmd.add("--module"); cmd.add(moduleName + "/" + className); } else { cmd.add(className); } } }
// StartProcessTest.java package com.jdojo.process.api; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; publicclassStartProcessTest { publicstaticvoidmain(String[] args) { // Start a process that runs for 15 seconds Processp= Job.startProcess(5, 15); if (p == null) { System.out.println("Could not create a new process."); return; } // Get the handle of the current process ProcessHandlehandle= p.toHandle(); // Print the process details CurrentProcessInfo.printInfo(handle); CompletableFuture<ProcessHandle> future = handle.onExit(); // Print a message when process terminates future.thenAccept((ProcessHandle ph) -> { System.out.printf("Job (pid=%d) terminated.%n", ph.getPid()); }); try { // Wait for the process to complete future.get(); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } // Print process details again CurrentProcessInfo.printInfo(handle); } }
C:\java9\bin\java.exe --module-path C:\Java9Revealed\com.jdojo.process.api\build\classes --class-path C:\Java9Revealed\com.jdojo.process.api\build\classes --module com.jdojo.process.api/com.jdojo.process.api.Job 5 15 PID: 10928 IsAlive: true Command: C:\java9\bin\java.exe Arguments: [] CommandLine: Start Time: 2016-11-28T13:43:28.318-06:00[America/Chicago] CPU Time: PT0S Owner: kishori\ksharan Children Count: 1 Job (pid=10928) info: Sleep Interval=5 seconds, Sleep Duration=15 seconds. Job (pid=10928) is going to sleep for 5 seconds. Job (pid=10928) is going to sleep for 5 seconds. Job (pid=10928) is going to sleep for 5 seconds. Job (pid=10928) terminated. PID: 10928 IsAlive: false Command: Arguments: [] CommandLine: Start Time: 2016-11-28T13:43:28.318-06:00[America/Chicago] CPU Time: PT0.359375S Owner: kishori\ksharan Children Count: 0