/* * JBoss, Home of Professional Open Source. * Copyright 2010, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.as.process; import static java.security.AccessController.doPrivileged; import java.io.File; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.logging.Handler; import java.util.logging.Logger; import javax.net.ServerSocketFactory; import org.jboss.as.process.logging.ProcessLogger; import org.jboss.as.process.protocol.ProtocolServer; import org.jboss.as.version.ProductConfig; import org.jboss.as.version.Version; import org.jboss.logging.MDC; import org.jboss.logmanager.handlers.ConsoleHandler; import org.jboss.modules.Module; import org.jboss.threads.JBossThreadFactory; import org.wildfly.security.manager.WildFlySecurityManager; /** * The main entry point for the process controller. * * @author <a href="mailto:david.lloyd@redhat.com">David M. Lloyd</a> */ public final class Main { public static String getVersionString() { return Version.AS_VERSION; } private static void usage() { CommandLineArgumentUsageImpl.printUsage(System.out); } private Main() { } public static final String HOST_CONTROLLER_PROCESS_NAME = "Host Controller"; public static final String HOST_CONTROLLER_MODULE = "org.jboss.as.host-controller"; public static void main(String[] args) throws IOException { start(args); } public static ProcessController start(String[] args) throws IOException { MDC.put("process", "process controller"); String javaHome = WildFlySecurityManager.getPropertyPrivileged("java.home", "."); String jvmName = javaHome + "/bin/java"; String jbossHome = WildFlySecurityManager.getPropertyPrivileged("jboss.home.dir", "."); String modulePath = null; String bootJar = null; String bootModule = HOST_CONTROLLER_MODULE; final PCSocketConfig pcSocketConfig = new PCSocketConfig(); String currentWorkingDir = WildFlySecurityManager.getPropertyPrivileged("user.dir", null); final List<String> javaOptions = new ArrayList<String>(); final List<String> smOptions = new ArrayList<String>(); // target module is always SM // -mp is my module path // -jar is jboss-modules.jar in jboss-home // log config should be fixed loc // If the security manager is installed assume we need to use -secmgr boolean securityManagerEnabled = System.getSecurityManager() != null; OUT: for (int i = 0; i < args.length; i++) { String arg = args[i]; if ("-jvm".equals(arg)) { jvmName = args[++i]; } else if ("-jboss-home".equals(arg)) { jbossHome = args[++i]; } else if ("-mp".equals(arg)) { modulePath = args[++i]; } else if ("-jar".equals(arg)) { bootJar = args[++i]; } else if ("-secmgr".equals(arg)) { securityManagerEnabled = true; } else if ("--".equals(arg)) { for (i++; i < args.length; i++) { arg = args[i]; if ("--".equals(arg)) { for (i++; i < args.length; i++) { arg = args[i]; if (handleHelpOrVersion(arg, jbossHome)) { return null; } else if (pcSocketConfig.processPCSocketConfigArgument(arg, args, i)) { if (pcSocketConfig.isParseFailed()) { return null; } i += pcSocketConfig.getArgIncrement(); } else if (arg.startsWith("-D" + CommandLineConstants.PREFER_IPV4_STACK + "=")) { // AS7-5409 set the property for this process and pass it to HC via javaOptions String val = parseValue(arg, "-D" + CommandLineConstants.PREFER_IPV4_STACK); WildFlySecurityManager.setPropertyPrivileged(CommandLineConstants.PREFER_IPV4_STACK, val); addJavaOption(arg, javaOptions); } else if (arg.startsWith("-D" + CommandLineConstants.PREFER_IPV6_ADDRESSES + "=")) { // AS7-5409 set the property for this process and pass it to HC via javaOptions String val = parseValue(arg, "-D" + CommandLineConstants.PREFER_IPV6_ADDRESSES); WildFlySecurityManager.setPropertyPrivileged(CommandLineConstants.PREFER_IPV6_ADDRESSES, val); addJavaOption(arg, javaOptions); } else { addJavaOption(arg, smOptions); } } break OUT; } else if (handleHelpOrVersion(arg, jbossHome)) { // This would normally come in via the nested if ("--".equals(arg)) case above, but in case someone tweaks the // script to set it directly, we've handled it return null; } else if (pcSocketConfig.processPCSocketConfigArgument(arg, args, i)) { // This would normally come in via the nested if ("--".equals(arg)) case above, but in case someone tweaks the // script to set it directly, we've handled it if (pcSocketConfig.isParseFailed()) { return null; } i += pcSocketConfig.getArgIncrement(); } else { // Windows batch scripts can't filter out parameters, ignore the -Djava.security.manager system property if (arg.startsWith("-Djava.security.manager")) { // Turn on the security manager securityManagerEnabled = true; } else { addJavaOption(arg, javaOptions); } } } break OUT; } else if (handleHelpOrVersion(arg, jbossHome)) { // This would normally come in via the if ("--".equals(arg)) cases above, but in case someone tweaks the // script to set it directly, we've handled it) return null; } else if (pcSocketConfig.processPCSocketConfigArgument(arg, args, i)) { // This would normally come in via the if ("--".equals(arg)) cases above, but in case someone tweaks the // script to set it directly, we've handled it if (pcSocketConfig.isParseFailed()) { return null; } i += pcSocketConfig.getArgIncrement(); } else { throw ProcessLogger.ROOT_LOGGER.invalidOption(arg); } } if (modulePath == null) { // if "-mp" (i.e. module path) wasn't part of the command line args, then check the system property. // if system property not set, then default to JBOSS_HOME/modules // TODO: jboss-modules setting module.path is not a reliable API; log a WARN or something if we get here modulePath = WildFlySecurityManager.getPropertyPrivileged("module.path", jbossHome + File.separator + "modules"); } if (bootJar == null) { // if "-jar" wasn't part of the command line args, then default to JBOSS_HOME/jboss-modules.jar bootJar = jbossHome + File.separator + "jboss-modules.jar"; } Handler consoleHandler = null; final Logger rootLogger = Logger.getLogger(""); for (Handler handler : rootLogger.getHandlers()) { if (handler instanceof ConsoleHandler) { if (consoleHandler != null) { // duplicate handlers rootLogger.removeHandler(handler); } else { consoleHandler = handler; ((ConsoleHandler)consoleHandler).setWriter(new SynchronizedWriter(System.out)); } } } final ProtocolServer.Configuration configuration = new ProtocolServer.Configuration(); InetAddress pcInetAddress = InetAddress.getByName(pcSocketConfig.getBindAddress()); InetSocketAddress pcInetSocketAddress = new InetSocketAddress(pcInetAddress, pcSocketConfig.getBindPort()); configuration.setBindAddress(pcInetSocketAddress); configuration.setSocketFactory(ServerSocketFactory.getDefault()); final ThreadFactory threadFactory = doPrivileged(new PrivilegedAction<JBossThreadFactory>() { public JBossThreadFactory run() { return new JBossThreadFactory(new ThreadGroup("ProcessController-threads"), Boolean.FALSE, null, "%G - %t", null, null); } }); configuration.setThreadFactory(threadFactory); configuration.setReadExecutor(Executors.newCachedThreadPool(threadFactory)); final ProcessController processController = new ProcessController(configuration, System.out, System.err); final InetSocketAddress boundAddress = processController.getServer().getBoundAddress(); final List<String> initialCommand = new ArrayList<String>(); initialCommand.add(jvmName); initialCommand.add("-D[" + HOST_CONTROLLER_PROCESS_NAME + "]"); initialCommand.addAll(javaOptions); initialCommand.add("-jar"); initialCommand.add(bootJar); // Optionally pass the security manager property to the host controller if (securityManagerEnabled){ initialCommand.add("-secmgr"); } initialCommand.add("-mp"); initialCommand.add(modulePath); initialCommand.add(bootModule); // Optionally pass the security manager property to the process controller if (securityManagerEnabled){ initialCommand.add("-secmgr"); } initialCommand.add("-mp"); // Repeat the module path so HostController's Main sees it initialCommand.add(modulePath); initialCommand.add(CommandLineConstants.PROCESS_CONTROLLER_BIND_ADDR); initialCommand.add(boundAddress.getAddress().getHostAddress()); initialCommand.add(CommandLineConstants.PROCESS_CONTROLLER_BIND_PORT); initialCommand.add(Integer.toString(boundAddress.getPort())); initialCommand.addAll(smOptions); initialCommand.add("-D" + "jboss.home.dir=" + jbossHome); processController.addProcess(HOST_CONTROLLER_PROCESS_NAME, initialCommand, Collections.<String, String>emptyMap(), currentWorkingDir, true, true); processController.startProcess(HOST_CONTROLLER_PROCESS_NAME); final Thread shutdownThread = new Thread(new Runnable() { public void run() { processController.shutdown(); } }, "Shutdown thread"); shutdownThread.setDaemon(false); Runtime.getRuntime().addShutdownHook(shutdownThread); return processController; } private static String parseValue(final String arg, final String key) { String value = null; int splitPos = key.length(); if (arg.length() <= splitPos + 1 || arg.charAt(splitPos) != '=') { System.out.println(ProcessLogger.ROOT_LOGGER.noArgValue(key)); usage(); } else { value = arg.substring(splitPos + 1); } return value; } private static void addJavaOption(String option, List<String> javaOptions) { // Remove any existing -D options that this one replaces if (option.startsWith("-D")) { String key; int splitPos = option.indexOf('='); if (splitPos < 0) { key = option; } else { key = option.substring(0, splitPos); } for (Iterator<String> iter = javaOptions.iterator(); iter.hasNext();) { String existingOp = iter.next(); if (existingOp.equals(key) || (existingOp.startsWith(key) && existingOp.indexOf('=') == key.length())) { iter.remove(); } } } javaOptions.add(option); } private static boolean handleHelpOrVersion(String arg, String jbossHome) { if (CommandLineConstants.HELP.equals(arg) || CommandLineConstants.SHORT_HELP.equals(arg) || CommandLineConstants.OLD_HELP.equals(arg)) { usage(); return true; } else if (CommandLineConstants.VERSION.equals(arg) || CommandLineConstants.SHORT_VERSION.equals(arg) || CommandLineConstants.OLD_VERSION.equals(arg) || CommandLineConstants.OLD_SHORT_VERSION.equals(arg)) { System.out.println(ProductConfig.fromFilesystemSlot(Module.getBootModuleLoader(), jbossHome, null).getPrettyVersionString()); return true; } return false; } private static class PCSocketConfig { private String bindAddress; private int bindPort = 0; private int argIncrement = 0; private boolean parseFailed; private PCSocketConfig() { } private String getBindAddress() { if (bindAddress != null) { return bindAddress; } else { boolean v4Stack = Boolean.valueOf(WildFlySecurityManager.getPropertyPrivileged(CommandLineConstants.PREFER_IPV4_STACK, "false")); boolean useV6 = !v4Stack && Boolean.valueOf(WildFlySecurityManager.getPropertyPrivileged(CommandLineConstants.PREFER_IPV6_ADDRESSES, "false")); return useV6 ? "::1" : "127.0.0.1"; } } private int getBindPort() { return bindPort; } private int getArgIncrement() { return argIncrement; } private boolean isParseFailed() { return parseFailed; } private boolean processPCSocketConfigArgument(final String arg, final String[] args, final int index) { boolean isPCSocketArg = true; argIncrement = 0; if (CommandLineConstants.PROCESS_CONTROLLER_BIND_ADDR.equals(arg) || CommandLineConstants.OLD_PROCESS_CONTROLLER_BIND_ADDR.equals(arg)) { bindAddress = args[index +1]; argIncrement = 1; } else if (arg.startsWith(CommandLineConstants.PROCESS_CONTROLLER_BIND_ADDR)) { String addr = parseValue(arg, CommandLineConstants.PROCESS_CONTROLLER_BIND_ADDR); if (addr == null) { parseFailed = true; } else { bindAddress = addr; } } else if (arg.startsWith(CommandLineConstants.OLD_PROCESS_CONTROLLER_BIND_ADDR)) { String addr = parseValue(arg, CommandLineConstants.OLD_PROCESS_CONTROLLER_BIND_ADDR); if (addr == null) { parseFailed = true; } else { bindAddress = addr; } } else if (CommandLineConstants.PROCESS_CONTROLLER_BIND_PORT.equals(arg) || CommandLineConstants.OLD_PROCESS_CONTROLLER_BIND_PORT.equals(arg)) { bindPort = Integer.parseInt(args[index + 1]); argIncrement = 1; } else if (arg.startsWith(CommandLineConstants.PROCESS_CONTROLLER_BIND_PORT)) { String port = parseValue(arg, CommandLineConstants.PROCESS_CONTROLLER_BIND_PORT); if (port == null) { parseFailed = true; } else { bindPort = Integer.parseInt(port); } } else if (arg.startsWith(CommandLineConstants.OLD_PROCESS_CONTROLLER_BIND_PORT)) { String port = parseValue(arg, CommandLineConstants.OLD_PROCESS_CONTROLLER_BIND_PORT); if (port == null) { parseFailed = true; } else { bindPort = Integer.parseInt(port); } } else { isPCSocketArg = false; } return isPCSocketArg; } } }