package games.strategy.engine.framework; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import java.util.Scanner; import games.strategy.debug.ClientLogger; import games.strategy.engine.ClientFileSystemHelper; import games.strategy.engine.framework.system.Memory; import games.strategy.engine.framework.system.SystemProperties; import games.strategy.util.Version; /** * To hold various static utility methods for running a java program. */ public class ProcessRunnerUtil { public static void runClass(final Class<?> mainClass) { final List<String> commands = new ArrayList<>(); populateBasicJavaArgs(commands); commands.add(mainClass.getName()); exec(commands); } public static void populateBasicJavaArgs(final List<String> commands) { populateBasicJavaArgs(commands, System.getProperty("java.class.path")); } public static void populateBasicJavaArgs(final List<String> commands, final long maxMemory) { populateBasicJavaArgs(commands, System.getProperty("java.class.path"), maxMemory); } public static void populateBasicJavaArgs(final List<String> commands, final String newClasspath) { // for whatever reason, .maxMemory() returns a value about 12% smaller than the real Xmx value, so we are going to // add 64m to that to // compensate // final long maxMemory = ((long) (Runtime.getRuntime().maxMemory() * 1.15) + 67108864); final long maxMemory = Memory.getMaxMemoryInBytes(); System.out.println("Setting memory for new triplea process to: " + (maxMemory / (1024 * 1024)) + "m"); populateBasicJavaArgs(commands, newClasspath, maxMemory); } public static void populateBasicJavaArgs(final List<String> commands, final String classpath, final long maxMemory) { final String javaCommand = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java"; commands.add(javaCommand); commands.add("-classpath"); if (classpath != null && classpath.length() > 0) { commands.add(classpath); } else { commands.add(System.getProperty("java.class.path")); } commands.add("-Xmx" + maxMemory); // this should never ever go above 1000mb, because some users have errors because some JVM's can't handle // that much // commands.add("-Xmx896m"); // preserve noddraw to fix 1742775 final String[] preservedSystemProperties = {"sun.java2d.noddraw"}; for (final String key : preservedSystemProperties) { if (System.getProperties().getProperty(key) != null) { final String value = System.getProperties().getProperty(key); if (value.matches("[a-zA-Z0-9.]+")) { commands.add("-D" + key + "=" + value); } } } if (SystemProperties.isMac()) { commands.add("-Dapple.laf.useScreenMenuBar=true"); commands.add("-Xdock:name=\"TripleA\""); final File icons = new File(ClientFileSystemHelper.getRootFolder(), "icons/triplea_icon.png"); if (icons.exists()) { commands.add("-Xdock:icon=" + icons.getAbsolutePath() + ""); } } final String version = System.getProperty(GameRunner.TRIPLEA_ENGINE_VERSION_BIN); if (version != null && version.length() > 0) { final Version testVersion; try { testVersion = new Version(version); commands.add("-D" + GameRunner.TRIPLEA_ENGINE_VERSION_BIN + "=" + testVersion.toString()); } catch (final Exception e) { // nothing } } // since we are setting the xmx already, we need to // make sure this property is set so that triplea // doesn't restart commands.add("-D" + Memory.TRIPLEA_MEMORY_SET + "=" + Boolean.TRUE.toString()); } public static void exec(final List<String> commands) { // System.out.println("Commands: " + commands); final ProcessBuilder builder = new ProcessBuilder(commands); // merge the streams, so we only have to start one reader thread builder.redirectErrorStream(true); try { final Process p = builder.start(); final InputStream s = p.getInputStream(); // we need to read the input stream to prevent possible // deadlocks final Thread t = new Thread(() -> { try (Scanner scanner = new Scanner(s);) { while (scanner.hasNextLine()) { System.out.println(scanner.nextLine()); } } }, "Process output gobbler"); t.setDaemon(true); t.start(); } catch (final IOException e) { ClientLogger.logQuietly(e); } } }