/* * $Id$ * * SARL is an general-purpose agent programming language. * More details on http://www.sarl.io * * Copyright (C) 2014-2017 the original authors or authors. * * Licensed 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 io.janusproject; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; import java.io.PrintWriter; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.text.MessageFormat; import java.util.Arrays; import java.util.Iterator; import java.util.Properties; import java.util.UUID; import java.util.logging.Logger; import java.util.regex.Pattern; import com.google.common.base.Strings; import com.google.inject.Module; import com.hazelcast.logging.LoggingService; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Option; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.arakhne.afc.vmutil.FileSystem; import io.janusproject.kernel.Kernel; import io.janusproject.services.executor.EarlyExitException; import io.janusproject.services.executor.ExecutorService; import io.janusproject.services.network.NetworkConfig; import io.janusproject.util.LoggerCreator; import io.sarl.lang.SARLVersion; import io.sarl.lang.core.Agent; /** * This is the class that permits to boot the Janus platform. * * <p>This class provides the "main" function for the platform. The list of the parameters is composed of a list of options, the * classname of an agent to launch, and the parameters to pass to the launched agent. * * <p>The supported options may be obtain by passing no parameter, or the option <code>-h</code>. * * <p>Example of Janus launching with Maven: * <pre> * <code>mvn exec:java * -Dexec.mainClass="io.janusproject.Boot" * -Dexec.args="my.Agent"</code> * </pre> * * <p>Example of Janus launching from the CLI (only with the Jar file that is containing all the jar dependencies): * <pre> * <code>java -jar janus-with-dependencies.jar my.Agent</code> * </pre> * * @author $Author: srodriguez$ * @author $Author: sgalland$ * @version $FullVersion$ * @mavengroupid $GroupId$ * @mavenartifactid $ArtifactId$ */ public final class Boot { /** Short command-line option for "embedded". */ public static final String CLI_OPTION_EMBEDDED_SHORT = "e"; //$NON-NLS-1$ /** Long command-line option for "embedded". */ public static final String CLI_OPTION_EMBEDDED_LONG = "embedded"; //$NON-NLS-1$ /** Short command-line option for "boot agent id". */ public static final String CLI_OPTION_BOOTID_SHORT = "B"; //$NON-NLS-1$ /** Long command-line option for "boot agent id". */ public static final String CLI_OPTION_BOOTID_LONG = "bootid"; //$NON-NLS-1$ /** Short command-line option for "random id". */ public static final String CLI_OPTION_RANDOMID_SHORT = "R"; //$NON-NLS-1$ /** Long command-line option for "random id". */ public static final String CLI_OPTION_RANDOMID_LONG = "randomid"; //$NON-NLS-1$ /** Short command-line option for "Janus world id". */ public static final String CLI_OPTION_WORLDID_SHORT = "W"; //$NON-NLS-1$ /** Long command-line option for "Janus world id". */ public static final String CLI_OPTION_WORLDID_LONG = "worldid"; //$NON-NLS-1$ /** Short command-line option for "file". */ public static final String CLI_OPTION_FILE_SHORT = "f"; //$NON-NLS-1$ /** Long command-line option for "file". */ public static final String CLI_OPTION_FILE_LONG = "file"; //$NON-NLS-1$ /** Short command-line option for "help". */ public static final String CLI_OPTION_HELP_SHORT = "h"; //$NON-NLS-1$ /** Long command-line option for "help". */ public static final String CLI_OPTION_HELP_LONG = "help"; //$NON-NLS-1$ /** Long command-line option for "nologo". */ public static final String CLI_OPTION_NOLOGO_LONG = "nologo"; //$NON-NLS-1$ /** Short command-line option for "offline". */ public static final String CLI_OPTION_OFFLINE_SHORT = "o"; //$NON-NLS-1$ /** Long command-line option for "offline". */ public static final String CLI_OPTION_OFFLINE_LONG = "offline"; //$NON-NLS-1$ /** Short command-line option for "be quiet". */ public static final String CLI_OPTION_QUIET_SHORT = "q"; //$NON-NLS-1$ /** Long command-line option for "be quiet". */ public static final String CLI_OPTION_QUIET_LONG = "quiet"; //$NON-NLS-1$ /** Short command-line option for "be more verbose". */ public static final String CLI_OPTION_VERBOSE_SHORT = "v"; //$NON-NLS-1$ /** Long command-line option for "be more verbose". */ public static final String CLI_OPTION_VERBOSE_LONG = "verbose"; //$NON-NLS-1$ /** Long command-line option for "display the version". */ public static final String CLI_OPTION_VERSION = "version"; //$NON-NLS-1$ /** Short command-line option for "change log level". */ public static final String CLI_OPTION_LOG_SHORT = "l"; //$NON-NLS-1$ /** Long command-line option for "change log level". */ public static final String CLI_OPTION_LOG_LONG = "log"; //$NON-NLS-1$ /** Short command-line option for "env. variable definition". */ public static final String CLI_OPTION_DEFINE_SHORT = "D"; //$NON-NLS-1$ /** Long command-line option for "env. variable definition". */ public static final String CLI_OPTION_DEFINE_LONG = "define"; //$NON-NLS-1$ /** Short command-line option for "show defaults". */ public static final String CLI_OPTION_SHOWDEFAULTS_SHORT = "s"; //$NON-NLS-1$ /** Long command-line option for "show defaults". */ public static final String CLI_OPTION_SHOWDEFAULTS_LONG = "showdefaults"; //$NON-NLS-1$ /** Short command-line option for "show the classpath". */ public static final String CLI_OPTION_SHOWCLASSPATH = "showclasspath"; //$NON-NLS-1$ /** Short command-line option for "show CLI arguments". */ public static final String CLI_OPTION_SHOWCLIARGUMENTS_LONG = "cli"; //$NON-NLS-1$ /** Short command-line option for "classpath". */ public static final String CLI_OPTION_CLASSPATH_SHORT = "cp"; //$NON-NLS-1$ /** Long command-line option for "classpath". */ public static final String CLI_OPTION_CLASSPATH_LONG = "classpath"; //$NON-NLS-1$ private static final int ERROR_EXIT_CODE = 255; private static PrintStream consoleLogger; private static Exiter applicationExiter; private Boot() { // } /** * Parse the command line. * * @param args - the CLI arguments given to the program. * @return the arguments that are not recognized as CLI options. */ @SuppressWarnings({"checkstyle:cyclomaticcomplexity", "checkstyle:npathcomplexity"}) public static String[] parseCommandLine(String[] args) { final CommandLineParser parser = new DefaultParser(); try { final CommandLine cmd = parser.parse(getOptions(), args, false); boolean noLogo = false; boolean embedded = false; int verbose = LoggerCreator.toInt(JanusConfig.VERBOSE_LEVEL_VALUE); final Iterator<Option> optIterator = cmd.iterator(); while (optIterator.hasNext()) { final Option opt = optIterator.next(); String optName = opt.getLongOpt(); if (Strings.isNullOrEmpty(optName)) { optName = opt.getOpt(); } switch (optName) { case CLI_OPTION_HELP_LONG: showHelp(); return null; case CLI_OPTION_VERSION: showVersion(); return null; case CLI_OPTION_SHOWDEFAULTS_LONG: showDefaults(); return null; case CLI_OPTION_SHOWCLASSPATH: showClasspath(); return null; case CLI_OPTION_SHOWCLIARGUMENTS_LONG: showCommandLineArguments(args); return null; case CLI_OPTION_FILE_LONG: final String rawFilename = opt.getValue(); if (rawFilename == null || "".equals(rawFilename)) { //$NON-NLS-1$ showHelp(); } final File file = new File(rawFilename); if (!file.canRead()) { showError(MessageFormat.format(Messages.Boot_0, rawFilename), null); return null; } setPropertiesFrom(file); break; case CLI_OPTION_CLASSPATH_LONG: addToSystemClasspath(opt.getValue()); break; case CLI_OPTION_OFFLINE_LONG: setOffline(true); break; case CLI_OPTION_RANDOMID_LONG: setRandomContextUUID(); break; case CLI_OPTION_BOOTID_LONG: setBootAgentTypeContextUUID(); break; case CLI_OPTION_WORLDID_LONG: setDefaultContextUUID(); break; case CLI_OPTION_DEFINE_LONG: final String name = opt.getValue(0); if (!Strings.isNullOrEmpty(name)) { setProperty(name, Strings.emptyToNull(opt.getValue(1))); } break; case CLI_OPTION_LOG_LONG: verbose = Math.max(LoggerCreator.toInt(opt.getValue()), 0); break; case CLI_OPTION_QUIET_LONG: if (verbose > 0) { --verbose; } break; case CLI_OPTION_VERBOSE_LONG: ++verbose; break; case CLI_OPTION_NOLOGO_LONG: noLogo = true; break; case CLI_OPTION_EMBEDDED_LONG: embedded = true; break; default: } } // Show the help when there is no argument. if (cmd.getArgs().length == 0) { showHelp(); return null; } // Change the verbosity setVerboseLevel(verbose); // Do nothing at exit if (embedded) { setExiter(() -> { ExecutorService.neverReturn(); }); } // Show the Janus logo? if (noLogo || verbose == 0) { setProperty(JanusConfig.JANUS_LOGO_SHOW_NAME, Boolean.FALSE.toString()); } return cmd.getArgs(); } catch (IOException | ParseException e) { showError(e.getLocalizedMessage(), e); // Event if showError never returns, add the return statement for // avoiding compilation error. return null; } } /** Add the given entries to the system classpath. * * @param entries the new classpath entries. The format of the value is the same as for the <code>-cp</code> * command-line option of the <code>java</code> tool. */ public static void addToSystemClasspath(String entries) { if (!Strings.isNullOrEmpty(entries)) { final String[] individualEntries = entries.split(Pattern.quote(File.pathSeparator)); final ClassLoader sysloader = ClassLoader.getSystemClassLoader(); if (sysloader instanceof URLClassLoader) { final Method method; try { method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); //$NON-NLS-1$ method.setAccessible(true); } catch (Throwable t) { showError(t.getLocalizedMessage(), t); return; } for (final String entry : individualEntries) { if (!Strings.isNullOrEmpty(entry)) { final URL url = FileSystem.convertStringToURL(entry, false); if (url != null) { try { method.invoke(sysloader, url); } catch (Throwable t) { showError(t.getLocalizedMessage(), t); } } } } } } } private static Class<? extends Agent> loadAgentClass(String fullyQualifiedName) { final Class<?> type; try { type = Class.forName(fullyQualifiedName); } catch (Exception e) { showError(MessageFormat.format( Messages.Boot_1, fullyQualifiedName, System.getProperty("java.class.path")), //$NON-NLS-1$ e); // Event if showError never returns, add the return statement for // avoiding compilation error. return null; } // The following test is needed because the // cast to Class<? extends Agent> is not checking // the Agent type (it is a generic type, not // tested at runtime). if (Agent.class.isAssignableFrom(type)) { return type.asSubclass(Agent.class); } showError(MessageFormat.format(Messages.Boot_2, fullyQualifiedName), null); // Event if showError never returns, add the return statement for // avoiding compilation error. return null; } /** * Main function that is parsing the command line and launching the first agent. * * @param args - command line arguments * @see #startJanus(Class, Object...) */ public static void main(String[] args) { try { Object[] freeArgs = parseCommandLine(args); if (JanusConfig.getSystemPropertyAsBoolean(JanusConfig.JANUS_LOGO_SHOW_NAME, JanusConfig.JANUS_LOGO_SHOW.booleanValue())) { showJanusLogo(); } if (freeArgs.length == 0) { showError(Messages.Boot_3, null); // Event if showError never returns, add the return statement for // avoiding compilation error. return; } final String agentToLaunch = freeArgs[0].toString(); freeArgs = Arrays.copyOfRange(freeArgs, 1, freeArgs.length, String[].class); // Load the agent class final Class<? extends Agent> agent = loadAgentClass(agentToLaunch); assert agent != null; startJanus(agent, freeArgs); } catch (EarlyExitException exception) { // Be silent return; } catch (Throwable e) { showError(MessageFormat.format(Messages.Boot_4, e.getLocalizedMessage()), e); // Even if showError never returns, add the return statement for // avoiding compilation error. return; } } /** * Replies the console stream for logging messages from the boot mechanism. * * <p>The console stream is independent of the stream used by the {@link LoggingService logging service} of the platform. Indeed, * the console stream is used for displaying information, warnings and messages before the Janus platform is realy launched. * * @return the console logger. */ public static PrintStream getConsoleLogger() { return consoleLogger == null ? System.out : consoleLogger; } /** * Replies the console stream for logging messages from the boot mechanism. * * <p>The console stream is independent of the stream used by the {@link LoggingService logging service} of the platform. Indeed, * the console stream is used for displaying information, warnings and messages before the Janus platform is realy launched. * * @param stream - the stream to use for the console logging. */ public static void setConsoleLogger(PrintStream stream) { consoleLogger = stream; } /** * Replies the command line options supported by this boot class. * * @return the command line options. */ public static Options getOptions() { final Options options = new Options(); options.addOption(CLI_OPTION_CLASSPATH_SHORT, CLI_OPTION_CLASSPATH_LONG, true, Messages.Boot_24); options.addOption(CLI_OPTION_EMBEDDED_SHORT, CLI_OPTION_EMBEDDED_LONG, false, Messages.Boot_5); options.addOption(CLI_OPTION_BOOTID_SHORT, CLI_OPTION_BOOTID_LONG, false, MessageFormat.format(Messages.Boot_6, JanusConfig.BOOT_DEFAULT_CONTEXT_ID_NAME, JanusConfig.RANDOM_DEFAULT_CONTEXT_ID_NAME)); options.addOption(CLI_OPTION_FILE_SHORT, CLI_OPTION_FILE_LONG, true, Messages.Boot_7); options.addOption(CLI_OPTION_HELP_SHORT, CLI_OPTION_HELP_LONG, false, Messages.Boot_8); options.addOption(null, CLI_OPTION_NOLOGO_LONG, false, Messages.Boot_9); options.addOption(CLI_OPTION_OFFLINE_SHORT, CLI_OPTION_OFFLINE_LONG, false, MessageFormat.format(Messages.Boot_10, JanusConfig.OFFLINE)); options.addOption(CLI_OPTION_QUIET_SHORT, CLI_OPTION_QUIET_LONG, false, Messages.Boot_11); options.addOption(CLI_OPTION_RANDOMID_SHORT, CLI_OPTION_RANDOMID_LONG, false, MessageFormat.format(Messages.Boot_12, JanusConfig.BOOT_DEFAULT_CONTEXT_ID_NAME, JanusConfig.RANDOM_DEFAULT_CONTEXT_ID_NAME)); options.addOption(CLI_OPTION_SHOWDEFAULTS_SHORT, CLI_OPTION_SHOWDEFAULTS_LONG, false, Messages.Boot_13); options.addOption(CLI_OPTION_SHOWCLASSPATH, false, Messages.Boot_23); options.addOption(null, CLI_OPTION_SHOWCLIARGUMENTS_LONG, false, Messages.Boot_14); options.addOption(CLI_OPTION_VERBOSE_SHORT, CLI_OPTION_VERBOSE_LONG, false, Messages.Boot_15); options.addOption(CLI_OPTION_VERSION, false, Messages.Boot_25); options.addOption(CLI_OPTION_WORLDID_SHORT, CLI_OPTION_WORLDID_LONG, false, MessageFormat.format(Messages.Boot_16, JanusConfig.BOOT_DEFAULT_CONTEXT_ID_NAME, JanusConfig.RANDOM_DEFAULT_CONTEXT_ID_NAME)); final StringBuilder b = new StringBuilder(); int level = 0; for (final String logLevel : LoggerCreator.getLevelStrings()) { if (b.length() > 0) { b.append(", "); //$NON-NLS-1$ } b.append(logLevel); b.append(" ("); //$NON-NLS-1$ b.append(level); b.append(")"); //$NON-NLS-1$ ++level; } Option opt = new Option(CLI_OPTION_LOG_SHORT, CLI_OPTION_LOG_LONG, true, MessageFormat.format(Messages.Boot_17, JanusConfig.VERBOSE_LEVEL_VALUE, b)); opt.setArgs(1); options.addOption(opt); opt = new Option(CLI_OPTION_DEFINE_SHORT, CLI_OPTION_DEFINE_LONG, true, Messages.Boot_18); opt.setArgs(2); opt.setValueSeparator('='); opt.setArgName(Messages.Boot_19); options.addOption(opt); return options; } /** * Show an error message, and exit. * * <p>This function never returns. * * @param message - the description of the error. * @param exception - the cause of the error. */ @SuppressWarnings("checkstyle:regexp") public static void showError(String message, Throwable exception) { try (PrintWriter logger = new PrintWriter(getConsoleLogger())) { if (message != null && !message.isEmpty()) { logger.println(message); } else if (exception != null) { exception.printStackTrace(logger); } logger.println(); logger.flush(); showHelp(logger); } } /** * Show the help message on the standard console. This function never returns. */ public static void showHelp() { showHelp(new PrintWriter(getConsoleLogger())); } private static void showHelp(PrintWriter logger) { final HelpFormatter formatter = new HelpFormatter(); formatter.printHelp(logger, HelpFormatter.DEFAULT_WIDTH, getProgramName() + " " //$NON-NLS-1$ + Messages.Boot_20, "", //$NON-NLS-1$ getOptions(), HelpFormatter.DEFAULT_LEFT_PAD, HelpFormatter.DEFAULT_DESC_PAD, ""); //$NON-NLS-1$ logger.flush(); getExiter().exit(); } /** Replies the name of the program. * * @return the name of the program. */ public static String getProgramName() { String programName = JanusConfig.getSystemProperty(JanusConfig.JANUS_PROGRAM_NAME, null); if (Strings.isNullOrEmpty(programName)) { programName = JanusConfig.JANUS_PROGRAM_NAME_VALUE; } return programName; } /** * Show the default values of the system properties. This function never returns. */ @SuppressWarnings("checkstyle:regexp") public static void showDefaults() { final Properties defaultValues = new Properties(); JanusConfig.getDefaultValues(defaultValues); NetworkConfig.getDefaultValues(defaultValues); try (OutputStream os = getConsoleLogger()) { defaultValues.storeToXML(os, null); os.flush(); } catch (Throwable e) { e.printStackTrace(); } getExiter().exit(); } /** * Show the classpath of the system properties. This function never returns. */ @SuppressWarnings({ "checkstyle:regexp", "resource" }) public static void showClasspath() { final String cp = System.getProperty("java.class.path"); //$NON-NLS-1$ if (!Strings.isNullOrEmpty(cp)) { final PrintStream ps = getConsoleLogger(); for (final String entry : cp.split(Pattern.quote(File.pathSeparator))) { ps.println(entry); } ps.flush(); } getExiter().exit(); } /** * Show the version of Janus. This function never returns. */ public static void showVersion() { try (PrintWriter logger = new PrintWriter(getConsoleLogger())) { logger.println(MessageFormat.format(Messages.Boot_26, JanusVersion.JANUS_RELEASE_VERSION)); logger.println(MessageFormat.format(Messages.Boot_27, SARLVersion.SPECIFICATION_RELEASE_VERSION_STRING)); logger.flush(); } getExiter().exit(); } /** * Show the command line arguments. This function never returns. * * @param args - the command line arguments. */ @SuppressWarnings("checkstyle:regexp") public static void showCommandLineArguments(String[] args) { try (PrintStream os = getConsoleLogger()) { for (int i = 0; i < args.length; ++i) { os.println(i + ": " //$NON-NLS-1$ + args[i]); } os.flush(); } catch (Throwable e) { e.printStackTrace(); } getExiter().exit(); } /** * Show the heading logo of the Janus platform. */ @SuppressWarnings("checkstyle:regexp") public static void showJanusLogo() { getConsoleLogger().println(Messages.Boot_21); } /** * Set offline flag of the Janus platform. * * <p>This function is equivalent to the command line option <code>-o</code>. * * <p>This function must be called before launching the Janus platform. * * @param isOffline - the offline flag. * @since 2.0.2.0 * @see JanusConfig#OFFLINE */ public static void setOffline(boolean isOffline) { System.setProperty(JanusConfig.OFFLINE, Boolean.toString(isOffline)); } /** * Force the Janus platform to use a random identifier for its default context. * * <p>This function is equivalent to the command line option <code>-R</code>. * * <p>This function must be called before launching the Janus platform. * * @since 2.0.2.0 * @see JanusConfig#BOOT_DEFAULT_CONTEXT_ID_NAME * @see JanusConfig#RANDOM_DEFAULT_CONTEXT_ID_NAME */ public static void setRandomContextUUID() { System.setProperty(JanusConfig.BOOT_DEFAULT_CONTEXT_ID_NAME, Boolean.FALSE.toString()); System.setProperty(JanusConfig.RANDOM_DEFAULT_CONTEXT_ID_NAME, Boolean.TRUE.toString()); } /** * Force the Janus platform to use a default context identifier that tis build upon the classname of the boot agent. It means * that the UUID is always the same for a given classname. * * <p>This function is equivalent to the command line option <code>-B</code>. * * @since 2.0.2.0 * @see JanusConfig#BOOT_DEFAULT_CONTEXT_ID_NAME * @see JanusConfig#RANDOM_DEFAULT_CONTEXT_ID_NAME */ public static void setBootAgentTypeContextUUID() { System.setProperty(JanusConfig.BOOT_DEFAULT_CONTEXT_ID_NAME, Boolean.TRUE.toString()); System.setProperty(JanusConfig.RANDOM_DEFAULT_CONTEXT_ID_NAME, Boolean.FALSE.toString()); } /** * Force the Janus platform to use the identifier hard-coded in the source code for its default context. * * <p>This function is equivalent to the command line option <code>-W</code>. * * <p>This function must be called before launching the Janus platform. * * @since 2.0.2.0 * @see JanusConfig#BOOT_DEFAULT_CONTEXT_ID_NAME * @see JanusConfig#RANDOM_DEFAULT_CONTEXT_ID_NAME */ public static void setDefaultContextUUID() { System.setProperty(JanusConfig.BOOT_DEFAULT_CONTEXT_ID_NAME, Boolean.FALSE.toString()); System.setProperty(JanusConfig.RANDOM_DEFAULT_CONTEXT_ID_NAME, Boolean.FALSE.toString()); } /** * Force the verbosity level. * * <p>This function must be called before launching the Janus platform. * * @param level - the verbosity level. * @since 2.0.2.0 * @see JanusConfig#VERBOSE_LEVEL_NAME */ public static void setVerboseLevel(int level) { System.setProperty(JanusConfig.VERBOSE_LEVEL_NAME, Integer.toString(level)); } /** * Set the system property. This function is an helper for setting a system property usually accessible with {@link System}. * * <p>This function must be called before launching the Janus platform. * * @param name - the name of the property. * @param value - the value of the property. If the value is <code>null</code> or empty, the property is removed. * @since 2.0.2.0 * @see System#setProperty(String, String) * @see System#getProperties() */ public static void setProperty(String name, String value) { if (name != null && !name.isEmpty()) { if (value == null || value.isEmpty()) { System.getProperties().remove(name); } else { System.setProperty(name, value); } } } /** * Set the system property from the content of the file with the given URL. This function is an helper for setting the system * properties usually accessible with {@link System}. * * @param propertyFile - the URL from which a stream is opened. * @throws IOException - if the stream cannot be read. * @since 2.0.2.0 * @see System#getProperties() * @see Properties#load(InputStream) */ public static void setPropertiesFrom(URL propertyFile) throws IOException { final Properties systemProperties = System.getProperties(); try (InputStream stream = propertyFile.openStream()) { systemProperties.load(stream); } } /** * Set the system property from the content of the file with the given URL. This function is an helper for setting the system * properties usually accessible with {@link System}. * * @param propertyFile - the URL from which a stream is opened. * @throws IOException - if the stream cannot be read. * @since 2.0.2.0 * @see System#getProperties() * @see Properties#load(InputStream) */ public static void setPropertiesFrom(File propertyFile) throws IOException { final Properties systemProperties = System.getProperties(); try (InputStream stream = new FileInputStream(propertyFile)) { systemProperties.load(stream); } } /** * Replies the identifier of the boot agent from the system's properties. The boot agent is launched with * {@link #startJanus(Class, Object...)}. * * @return the identifier of the boot agent, or <code>null</code> if it is unknown. * @since 2.0.2.0 * @see JanusConfig#BOOT_AGENT_ID * @see #startJanus(Class, Object...) */ public static UUID getBootAgentIdentifier() { final String id = JanusConfig.getSystemProperty(JanusConfig.BOOT_AGENT_ID); if (id != null && !id.isEmpty()) { try { return UUID.fromString(id); } catch (Throwable exception) { // } } return null; } /** * Launch the Janus kernel and the first agent in the kernel. * * <p>Thus function does not parse the command line. See {@link #main(String[])} for the command line management. When this * function is called, it is assumed that all the system's properties are correctly set. * * <p>The platformModule parameter permits to specify the injection module to use. The injection module is in change of * creating/injecting all the components of the platform. The default injection module is retreived from the system property * with the name stored in {@link JanusConfig#INJECTION_MODULE_NAME}. The default type for the injection module is stored in * the constant {@link JanusConfig#INJECTION_MODULE_NAME_VALUE}. * * <p>The function {@link #getBootAgentIdentifier()} permits to retreive the identifier of the launched agent. * * @param agentCls - type of the first agent to launch. * @param params - parameters to pass to the agent as its initliazation parameters. * @return the kernel that was launched. * @throws Exception - if it is impossible to start the platform. * @see #main(String[]) * @see #getBootAgentIdentifier() */ public static Kernel startJanus(Class<? extends Agent> agentCls, Object... params) throws Exception { return startJanusWithModuleType(null, agentCls, params); } /** * Launch the Janus kernel and the first agent in the kernel. * * <p>Thus function does not parse the command line. See {@link #main(String[])} for the command line management. When this * function is called, it is assumed that all the system's properties are correctly set. * * <p>The platformModule parameter permits to specify the injection module to use. The injection module is in change of * creating/injecting all the components of the platform. The default injection module is retreived from the system property * with the name stored in {@link JanusConfig#INJECTION_MODULE_NAME}. The default type for the injection module is stored in * the constant {@link JanusConfig#INJECTION_MODULE_NAME_VALUE}. * * <p>The function {@link #getBootAgentIdentifier()} permits to retreive the identifier of the launched agent. * * @param platformModule - type of the injection module to use for initializing the platform, if <code>null</code> the default * module will be used. * @param agentCls - type of the first agent to launch. * @param params - parameters to pass to the agent as its initliazation parameters. * @return the kernel that was launched. * @throws Exception - if it is impossible to start the platform. * @since 0.5 * @see #main(String[]) * @see #getBootAgentIdentifier() */ public static Kernel startJanusWithModuleType(Class<? extends Module> platformModule, Class<? extends Agent> agentCls, Object... params) throws Exception { Class<? extends Module> startupModule = platformModule; if (startupModule == null) { startupModule = JanusConfig.getSystemPropertyAsClass(Module.class, JanusConfig.INJECTION_MODULE_NAME, JanusConfig.INJECTION_MODULE_NAME_VALUE); } assert startupModule != null : "No platform injection module"; //$NON-NLS-1$ return startJanusWithModule(startupModule.newInstance(), agentCls, params); } /** * Launch the Janus kernel and the first agent in the kernel. * * <p>Thus function does not parse the command line. See {@link #main(String[])} for the command line management. When this * function is called, it is assumed that all the system's properties are correctly set. * * <p>The startupModule parameter permits to specify the injection module to use. The injection module is in change of * creating/injecting all the components of the platform. The default injection module is retreived from the system property * with the name stored in {@link JanusConfig#INJECTION_MODULE_NAME}. The default type for the injection module is stored in * the constant {@link JanusConfig#INJECTION_MODULE_NAME_VALUE}. * * <p>The function {@link #getBootAgentIdentifier()} permits to retreive the identifier of the launched agent. * * @param startupModule - the injection module to use for initializing the platform. * @param agentCls - type of the first agent to launch. * @param params - parameters to pass to the agent as its initliazation parameters. * @return the kernel that was launched. * @throws Exception - if it is impossible to start the platform. * @since 0.5 * @see #main(String[]) * @see #getBootAgentIdentifier() */ public static Kernel startJanusWithModule(Module startupModule, Class<? extends Agent> agentCls, Object... params) throws Exception { // Set the boot agent classname System.setProperty(JanusConfig.BOOT_AGENT, agentCls.getName()); // Get the start-up injection module assert startupModule != null : "No platform injection module"; //$NON-NLS-1$ final Kernel k = Kernel.create(startupModule); final Logger logger = k.getLogger(); if (logger != null) { logger.info(MessageFormat.format(Messages.Boot_22, agentCls.getName())); } final UUID id = k.spawn(agentCls, params); if (id != null) { System.setProperty(JanusConfig.BOOT_AGENT_ID, id.toString()); } else { System.getProperties().remove(JanusConfig.BOOT_AGENT_ID); } return k; } /** * Replies the tool for exiting the application. * * @return the tool for exiting the application. */ public static Exiter getExiter() { return applicationExiter == null ? () -> System.exit(ERROR_EXIT_CODE) : applicationExiter; } /** * Changes the tool that permits to stop the application. * * @param exiter - the exit tool. */ public static void setExiter(Exiter exiter) { applicationExiter = exiter; } /** * Tool for exiting from the application. * * @author $Author: sgalland$ * @version $FullVersion$ * @mavengroupid $GroupId$ * @mavenartifactid $ArtifactId$ */ @FunctionalInterface public interface Exiter { /** * Exit the application. */ void exit(); } }