Package org.apache.ace.agent.launcher

Source Code of org.apache.ace.agent.launcher.Launcher

/*
* 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.ace.agent.launcher;

import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.ServiceLoader;

import org.apache.ace.agent.AgentConstants;
import org.apache.commons.cli.BasicParser;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.launch.Framework;
import org.osgi.framework.launch.FrameworkFactory;

/**
* A simple launcher, that launches the embedded OSGi framework together with a management agent. Additional bundles may
* be installed by putting {@link BundleProvider} services on the classpath.
*/
public class Launcher implements PropertyProvider {
    private static final String SYSTEM_PREFIX = "system.";
    private static final String FRAMEWORK_PREFIX = "framework.";

    /**
     * MAIN ENTRY POINT
     */
    public static void main(String[] args) throws Exception {
        Launcher launcher = new Launcher();
        launcher.parseArgs(args);
        launcher.run();
    }

    private Map<String, String> m_configuration;

    /**
     * @return the value of the property with the given key.
     */
    public String getProperty(String key) {
        String value = m_configuration.get(key);
        if (value == null) {
            value = System.getProperty(key);
        }
        return value;
    }

    public Map<String, String> parseArgs(String... args) throws Exception {
        Options options = new Options();
        options.addOption(OptionBuilder.withDescription("the agent ID to use").hasArg().withArgName("ID").withLongOpt("agent").create('a'));
        options.addOption(OptionBuilder.withDescription("the Apache ACE server URL(s) to use").hasArg().withArgName("URLs").withLongOpt("serverurl").create('s'));
        options.addOption(OptionBuilder.withDescription("enable verbose logging").withLongOpt("verbose").create('v'));
        options.addOption(OptionBuilder.withDescription("use configuration file").hasArg().withArgName("FILE").withLongOpt("config").create('c'));
        options.addOption(OptionBuilder.withDescription("prints this message").withLongOpt("help").create('h'));

        // Start from scratch...
        Map<String, String> config = new HashMap<String, String>();

        CommandLineParser parser = new BasicParser();
        CommandLine command = parser.parse(options, args, false /* stopAtNonOption */);

        if (command.hasOption("h")) {
            printHelp(options);
            System.exit(0);
        }

        // first map all default properties
        propagateConfiguration(loadDefaultProperties(), config);

        // overwrite with user properties
        if (command.hasOption("c")) {
            propagateConfiguration(loadUserProperties(command.getOptionValue("c")), config);
        }

        // add all non-recognized command line options...
        propagateConfiguration(command.getArgs(), config);

        // convenience debug override...
        if (command.hasOption("v")) {
            config.put("verbose", "true");
            config.put(AgentConstants.CONFIG_LOGGING_LEVEL, "DEBUG");
        }

        // handle overrides...
        if (command.hasOption("s")) {
            config.put(AgentConstants.CONFIG_DISCOVERY_SERVERURLS, command.getOptionValue("s"));
        }
        if (command.hasOption("a")) {
            config.put(AgentConstants.CONFIG_IDENTIFICATION_AGENTID, command.getOptionValue("a"));
        }

        return (m_configuration = config);
    }

    /**
     * Main execution logic of the launcher; Start a framework, install bundles and pass configuration to the
     * {@link AgentFactory}.
     *
     * @throws Exception
     *             on failure
     */
    public void run() throws Exception {
        int rc = 0;
        try {
            FrameworkFactory frameworkFactory = loadFrameworkFactory();
            BundleProvider[] bundleProviders = loadBundleProviders();

            logVerbose("Launching OSGi framework\n- factory:\t%s\n- properties:\t%s\n- providers:\t%s\n",
                frameworkFactory.getClass().getName(), m_configuration, Arrays.toString(bundleProviders));

            Framework framework = frameworkFactory.newFramework(m_configuration);
            framework.init();

            BundleContext context = framework.getBundleContext();

            for (BundleProvider bundleProvider : bundleProviders) {
                installBundles(context, bundleProvider);
            }

            framework.start();

            logVerbose("Startup complete...");

            framework.waitForStop(0);
        }
        catch (Exception e) {
            e.printStackTrace(System.err);
            rc = 1;
        }

        System.exit(rc);
    }

    /**
     * @return the configuration
     */
    final Map<String, String> getConfiguration() {
        return m_configuration;
    }

    private void close(Closeable resource) {
        if (resource != null) {
            try {
                resource.close();
            }
            catch (Exception exception) {
                // Ignore, nothing we can do about this...
            }
        }
    }

    private Bundle[] installBundles(BundleContext context, BundleProvider bundleProvider) throws BundleException, IOException {
        URL[] bundles = bundleProvider.getBundles(this);
        List<Bundle> result = new ArrayList<Bundle>(bundles.length);
        for (URL bundle : bundles) {
            logVerbose("- installing:\t%s%n", bundle.getFile());

            InputStream is = null;
            try {
                is = bundle.openStream();
                result.add(context.installBundle(bundle.toExternalForm(), is));
            }
            finally {
                close(is);
            }
        }
        for (Bundle bundle : result) {
            bundle.start();
        }
        return result.toArray(new Bundle[result.size()]);
    }

    private boolean isVerbose() {
        return (m_configuration.get("verbose") != null) && Boolean.parseBoolean(m_configuration.get("verbose"));
    }

    /**
     * Load {@link BundleProvider}s through the {@link ServiceLoader}.
     *
     * @return list of providers
     * @throws Exception
     *             on failure
     */
    private BundleProvider[] loadBundleProviders() throws Exception {
        ServiceLoader<BundleProvider> bundleFactoryLoader = ServiceLoader.load(BundleProvider.class);
        Iterator<BundleProvider> bundleFactoryIterator = bundleFactoryLoader.iterator();
        List<BundleProvider> bundelFactoryList = new ArrayList<BundleProvider>();
        while (bundleFactoryIterator.hasNext()) {
            bundelFactoryList.add(bundleFactoryIterator.next());
        }
        return bundelFactoryList.toArray(new BundleProvider[bundelFactoryList.size()]);
    }

    private Properties loadDefaultProperties() throws IOException {
        InputStream inStream = null;
        try {
            inStream = getClass().getResourceAsStream("launcher-defaults.properties");

            Properties properties = new Properties();
            properties.load(inStream);
            return properties;
        }
        finally {
            close(inStream);
        }
    }

    private FrameworkFactory loadFrameworkFactory() throws IllegalStateException {
        ServiceLoader<FrameworkFactory> frameworkFactoryLoader = ServiceLoader.load(FrameworkFactory.class);
        Iterator<FrameworkFactory> frameworkFactoryIterator = frameworkFactoryLoader.iterator();
        if (!frameworkFactoryIterator.hasNext()) {
            throw new IllegalStateException("Unable to load any FrameworkFactory");
        }
        return frameworkFactoryIterator.next();
    }

    private Properties loadUserProperties(String configFile) throws IOException {
        try {
            Properties properties = new Properties();
            properties.load(new FileInputStream(configFile));
            return properties;
        }
        catch (Exception e) {
            System.err.println("Can not load or access configuration file : " + configFile);
            return null;
        }
    }

    private void printHelp(Options options) {
        // Since the main() method is in the same class, we can use the following trick to obtain the JAR name...
        String jarName;
        try {
            jarName = new File(getClass().getProtectionDomain().getCodeSource().getLocation().toURI()).getName();
        }
        catch (URISyntaxException exception) {
            jarName = getClass().getSimpleName();
        }

        PrintWriter pw = new PrintWriter(System.out);

        new HelpFormatter().printHelp(pw, 120, "java -jar " + jarName, "\nOptions:", options, 4, 2, null, true);

        pw.println("\n" +
            "The configuration file provides the system and framework properties as well as the\n" +
            "agent configuration settings. If you specify a setting both on the command line and in\n" +
            "a configuration file, the command line setting takes precedence. System properties can\n" +
            "be specified by prefixing the property name with 'system.', for example, to set the\n" +
            "system property 'my.setting' one should specify it as 'system.my.setting'. All non-\n" +
            "system properties (including the agent configuration) are regarded as framework\n" +
            "properties, that is, will be passed to the OSGi framework.\n\n" +
            "Common options are (see ACE documentation for extensive list):\n\n" +
            "- agent.identification.agentid = <ID>\n" +
            "    defines the target name as <name>, if not given 'defaultTargetID' will be used.\n" +
            "    Note that the option '-a' overrides the agent ID in the configuration file!\n" +
            "- agent.discovery.serverurls = <URL-1>,<URL-2>,...,<URL-N>\n" +
            "    defines the location of the Apache ACE server(s), multiple servers can be given\n" +
            "    by separating their URLs with commas. Multiple URLs are used in best-effort round\n" +
            "    robin mode, that is, if the first URL fails, the second URL will be used, and so\n" +
            "    on. If not supplied, the default URL of 'http://localhost:8080' is used.\n" +
            "    Note that the option '-s' overrides the server URL(s) in the configuration file!\n" +
            "- agent.logging.level = (DEBUG|INFO|WARNING|ERROR)\n" +
            "    defines the log level of the agent. If not defined, 'INFO' is used as log level.\n" +
            "    Note that passing the option '-v' to the launcher implicitly sets the log level\n" +
            "    to 'DEBUG';\n" +
            "- agent.controller.syncinterval = <N>\n" +
            "    defines the synchronization interval (in seconds) in which the agent will\n" +
            "    synchronize its state with the Apache ACE server;\n" +
            "- agent.controller.syncdelay = <N>\n" +
            "    defines the initial delay (in seconds) before the agent will start synchronization\n" +
            "    with the Apache ACE server;\n" +
            "- launcher.bundles.dir = <PATH>\n" +
            "    defines the path where the launcher can find its initial set of bundles that should\n" +
            "    be installed upon startup of the agent. If not specified, the launcher will look at\n" +
            "    a directory called 'bundle' in the same directory as the launcher.\n");
        pw.flush();
        pw.close();
    }

    private void propagateConfiguration(Properties properties, Map<String, String> config) {
        if (properties == null) {
            return;
        }
        for (Object _key : properties.keySet()) {
            String key = (String) _key;
            String value = properties.getProperty(key);
            if (key.startsWith(SYSTEM_PREFIX)) {
                System.setProperty(key.substring(SYSTEM_PREFIX.length()), value);
            }
            else if (key.startsWith(FRAMEWORK_PREFIX)) {
                // Strip off the framework prefix, as we pass all configuration options as fw property...
                config.put(key.substring(FRAMEWORK_PREFIX.length()), value);
            }
            else {
                config.put(key, value);
            }
        }
    }

    private void propagateConfiguration(String[] properties, Map<String, String> config) {
        for (String property : properties) {
            String[] kv = property.split("\\s*=\\s*", 2);

            String key = kv[0].trim();
            String value = (kv.length > 1) ? kv[1].trim() : "";

            if (key.startsWith(SYSTEM_PREFIX)) {
                // Never let system properties to propagate as fw property...
                System.setProperty(key.substring(SYSTEM_PREFIX.length()), value);
            }
            else if (key.startsWith(FRAMEWORK_PREFIX)) {
                // Strip off the framework prefix, as we pass all configuration options as framework option...
                config.put(key.substring(FRAMEWORK_PREFIX.length()), value);
            }
            else {
                config.put(key, value);
            }
        }
    }

    private void logVerbose(String msg, Object... args) {
        if (isVerbose()) {
            System.out.printf(msg, args);
        }
    }
}
TOP

Related Classes of org.apache.ace.agent.launcher.Launcher

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.