org.ops4j.pax.runner.Run.java Source code

Java tutorial

Introduction

Here is the source code for org.ops4j.pax.runner.Run.java

Source

/*
 * Copyright 2006 Niclas Hedhman.
 * Copyright 2007 Alin Dreghiciu.
 * Copyright 2007 David Leangen.
 *
 * 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 org.ops4j.pax.runner;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.LogLevel;
import org.apache.felix.framework.Logger;
import org.apache.felix.framework.ServiceRegistry;
import org.apache.felix.framework.util.EventDispatcher;
import org.ops4j.io.FileUtils;
import org.ops4j.lang.NullArgumentException;
import org.ops4j.pax.runner.commons.Info;
import org.ops4j.pax.runner.osgi.RunnerBundle;
import org.ops4j.pax.runner.osgi.RunnerBundleContext;
import org.ops4j.pax.runner.osgi.RunnerStartLevel;
import org.ops4j.pax.runner.platform.*;
import org.ops4j.pax.runner.platform.BundleReference;
import org.ops4j.pax.scanner.*;
import org.osgi.framework.*;

import java.io.File;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;

import static org.ops4j.pax.runner.CommandLine.*;

/**
 * Main runner class. Does all the work.
 *
 * @author Alin Dreghiciu
 * @since August 26, 2007
 */
public class Run {

    /**
     * Logger.
     */
    private static Log LOGGER;
    /**
     * Handler service configuration property name.
     */
    private static final String HANDLER_SERVICE = "handler.service";
    /**
     * Provision service configuration property name.
     */
    private static final String PROVISION_SERVICE = "provision.service";
    /**
     * Platform extender configuration property name.
     */
    private static final String PLATFORM_SERVICE = "platform.service";
    /**
     * Clean start configuration property name.
     */
    private static final String CLEAN_START = "clean";
    /**
     * Working directory configuration property name.
     */
    private static final String WORKING_DIRECTORY = "workingDirectory";
    /**
     * Handler URLs to support keepOriginalUrls option configuration property name.
     */
    private static final String KEEP_ORIGINAL_HANDLER_URLS = "keep.original.handler.urls";

    /**
     * Creates a new runner.
     */
    public Run() {
        if (LOGGER == null) {
            createLogger();
        }
    }

    /**
     * {@inheritDoc}
     */
    public static void main(final String... args) {
        try {
            main(null, args);
        } catch (Throwable t) {
            showError(t);
            System.exit(1);
        }
    }

    /**
     * Start OSGi framework based on command-line arguments, using external Java runner service.
     *
     * @param runner java runner service
     * @param args   command-line arguments
     */
    public static void main(final JavaRunner runner, final String... args) {
        final CommandLine commandLine = new CommandLineImpl(args);

        boolean disableLogo = Boolean.valueOf(commandLine.getOption(OPTION_NOLOGO));
        if (!disableLogo) {
            showLogo();
        }

        initializeLogger(commandLine);
        String configURL = commandLine.getOption(OPTION_CONFIG);
        if (configURL == null) {
            configURL = "classpath:META-INF/runner.properties";
        }
        final Configuration config = new ConfigurationImpl(configURL);
        new Run().start(commandLine, config, new OptionResolverImpl(commandLine, config), runner);
    }

    public static Log getLogger() {
        createLogger();
        return LOGGER;
    }

    /**
     * Starts runner.
     *
     * @param runner java runner service
     * @param args   command-line arguments
     */
    public static void start(final JavaRunner runner, final String... args) {
        final CommandLine commandLine = new CommandLineImpl(args);
        String configURL = commandLine.getOption(OPTION_CONFIG);
        if (configURL == null) {
            configURL = "classpath:META-INF/runner.properties";
        }
        final Configuration config = new ConfigurationImpl(configURL);
        new Run().start(commandLine, config, new OptionResolverImpl(commandLine, config), runner);
    }

    /**
     * Starts runner.
     *
     * @param commandLine comand line to use
     * @param config      configuration to use
     * @param resolver    an option resolver
     */
    public void start(final CommandLine commandLine, final Configuration config, final OptionResolver resolver) {
        start(commandLine, config, resolver, null);
    }

    /**
     * Starts runner with a java runner.
     *
     * @param commandLine comand line to use
     * @param config      configuration to use
     * @param resolver    an option resolver
     * @param runner      java runner service
     */
    public void start(final CommandLine commandLine, final Configuration config, final OptionResolver resolver,
            final JavaRunner runner) {
        final Context context = createContext(commandLine, config, resolver);
        LOGGER.info(commandLine);
        // cleanup if requested
        cleanup(resolver);
        // install aditional services
        installServices(context);
        // install aditional handlers
        installHandlers(context);
        // install provisioning and bundles
        installBundles(installScanners(context), new ExtensionBasedProvisionSchemaResolver(), context);
        // stop the dispatcher as there are no longer events around
        EventDispatcher.shutdown();
        // install platform and start it up
        startPlatform(installPlatform(context), context, runner == null ? createJavaRunner(resolver) : runner);
    }

    /**
     * Removes the working directory if option specified.
     *
     * @param resolver option resolver
     */
    void cleanup(final OptionResolver resolver) {
        final boolean cleanStart = Boolean.valueOf(resolver.get(CLEAN_START));
        if (cleanStart) {
            final File workingDir = new File(resolver.getMandatory(WORKING_DIRECTORY));
            LOGGER.debug("Removing working directory [" + workingDir.getAbsolutePath() + "]");
            FileUtils.delete(workingDir);
        }
    }

    /**
     * Creates and initialize the context.
     *
     * @param commandLine comand line to use
     * @param config      configuration to use
     * @param resolver    an option resolver
     *
     * @return the created context
     */
    Context createContext(final CommandLine commandLine, final Configuration config,
            final OptionResolver resolver) {
        NullArgumentException.validateNotNull(commandLine, "Command line");
        NullArgumentException.validateNotNull(config, "Configuration");
        NullArgumentException.validateNotNull(resolver, "PropertyResolver");

        final ServiceRegistry serviceRegistry = new ServiceRegistry(null);
        final EventDispatcher dispatcher = EventDispatcher.start(new Logger(Logger.LOG_DEBUG));
        serviceRegistry.addServiceListener(new ServiceListener() {
            public void serviceChanged(ServiceEvent event) {
                dispatcher.fireServiceEvent(event);
            }
        });

        return new ContextImpl().setCommandLine(commandLine).setConfiguration(config).setOptionResolver(resolver)
                .setServiceRegistry(serviceRegistry).setEventDispatcher(dispatcher);
    }

    /**
     * Creates a Java runner based on "runner" option.
     *
     * @param resolver an option resolver
     *
     * @return a java runner
     */
    JavaRunner createJavaRunner(final OptionResolver resolver) {
        NullArgumentException.validateNotNull(resolver, "PropertyResolver");

        LOGGER.debug("Creating Java Runner");
        final String executor = resolver.get(OPTION_EXECUTOR);
        if (executor == null || executor.trim().length() == 0) {
            LOGGER.debug("Using default executor");
            return null;
        } else if ("noop".equalsIgnoreCase(executor)) {
            LOGGER.debug("Using noop executor");
            return new NoopJavaRunner();
        } else if ("script".equalsIgnoreCase(executor)) {
            LOGGER.debug("Using script executor");
            return new ScriptJavaRunner();
        } else if ("zip".equalsIgnoreCase(executor)) {
            LOGGER.debug("Using zip executor");
            return new ZipJavaRunner();
        } else if ("inProcess".equalsIgnoreCase(executor)) {
            LOGGER.debug("Using in process executor");
            return new InProcessJavaRunner();
        } else if (executor.startsWith("init.d")) {
            String[] data = executor.split(",");
            String appName = (data.length > 1 && data[1].length() > 0) ? data[1] : null;
            return new InitDScriptRunner(appName);
        } else if (executor.startsWith("daemon-start")) {
            LOGGER.debug("Using daemon-start executor");
            return new DaemonStartRunner(resolver.get(OPTION_DAEMON_TIMEOUT));
        } else if (executor.startsWith("daemon-stop")) {
            LOGGER.debug("Using daemon-stop executor");
            return new DaemonStopRunner();
        } else {
            try {
                final JavaRunner javaRunner = (JavaRunner) getClass().getClassLoader().loadClass(executor)
                        .newInstance();
                LOGGER.debug("Using " + executor + " executor");
                return javaRunner;
            } catch (Exception ignore) {
                LOGGER.debug("Connot load executor: " + executor + " reason: " + ignore.getMessage());
            }
        }
        throw new ConfigurationException("Executor [" + executor + "] is not supported");
    }

    /**
     * Installs url handler service configured handlers.
     *
     * @param context the running context
     */
    void installHandlers(final Context context) {
        LOGGER.debug("Installing handlers");
        final String option = context.getOptionResolver().get(OPTION_HANDLERS);
        if (option != null) {
            // first install each handler
            final Configuration config = context.getConfiguration();
            final String[] segments = option.split(",");
            for (String segment : segments) {
                NullArgumentException.validateNotEmpty(segment, "Handler entry");
                LOGGER.debug("Handler [" + segment + "]");
                final String activatorName = config.getProperty(segment);
                if (activatorName == null || activatorName.trim().length() == 0) {
                    throw new ConfigurationException("Handler [" + segment + "] is not supported");
                }
                createActivator(segment, activatorName, context);
            }
            // then install the handler service
            // maintain this order as in this way the bundle context will be easier to respond to getServiceListeners
            final String serviceActivatorName = config.getProperty(HANDLER_SERVICE);
            if (serviceActivatorName == null || serviceActivatorName.trim().length() == 0) {
                throw new ConfigurationException("Handler Service must be configured [" + HANDLER_SERVICE + "]");
            }
            createActivator(HANDLER_SERVICE, serviceActivatorName, context);
        }
    }

    /**
     * Installs provisioning service and configured scanners.
     *
     * @param context the running context
     *
     * @return installed provision service
     */
    ProvisionService installScanners(final Context context) {
        LOGGER.debug("Installing provisioning");
        final String option = context.getOptionResolver().getMandatory(OPTION_SCANNERS);
        // first install a dummy start level service that will record the start level set by scanners
        RunnerStartLevel.install(context.getServiceRegistry());
        // then install each scanner
        final String[] segments = option.split(",");
        for (String segment : segments) {
            NullArgumentException.validateNotEmpty(segment, "Scanner entry");
            LOGGER.debug("Scanner [" + segment + "]");
            final String activatorName = context.getConfiguration().getProperty(segment);
            if (activatorName == null || activatorName.trim().length() == 0) {
                throw new ConfigurationException("Scanner [" + segment + "] is not supported");
            }
            createActivator(segment, activatorName, context);
        }
        // then install the provisioning service
        // maintain this order as in this way the bundle context will be easier to respond to getServiceListeners
        final String serviceActivatorName = context.getConfiguration().getProperty(PROVISION_SERVICE);
        if (serviceActivatorName == null || serviceActivatorName.trim().length() == 0) {
            throw new ConfigurationException("Provision Service must be configured [" + PROVISION_SERVICE + "]");
        }
        final BundleContext bundleContext = createActivator(PROVISION_SERVICE, serviceActivatorName, context);
        // sanity check
        if (bundleContext == null) {
            throw new RuntimeException("Could not create bundle context for provision service");
        }
        final ServiceReference reference = bundleContext.getServiceReference(ProvisionService.class.getName());
        if (reference == null) {
            throw new RuntimeException("Could not resolve a provision service");
        }
        return (ProvisionService) bundleContext.getService(reference);
    }

    /**
     * Installs additional services.
     *
     * @param context the running context
     */
    void installServices(final Context context) {
        LOGGER.debug("Installing additional services");
        final String option = context.getOptionResolver().get(OPTION_SERVICES);
        if (option != null) {
            final Configuration config = context.getConfiguration();
            final String[] segments = option.split(",");
            for (String segment : segments) {
                NullArgumentException.validateNotEmpty(segment, "Service entry");
                LOGGER.debug("Installing service [" + segment + "]");
                final String activatorName = config.getProperty(segment);
                if (activatorName == null || activatorName.trim().length() == 0) {
                    throw new ConfigurationException("Service [" + segment + "] is not supported");
                }
                createActivator(segment, activatorName, context);
            }
        }
    }

    /**
     * By using provision service it installs provisioned bundles.
     *
     * @param provisionService installed provision service
     * @param schemaResolver   a provision schema resolver
     * @param context          the running context
     */
    void installBundles(final ProvisionService provisionService, final ProvisionSchemaResolver schemaResolver,
            final Context context) {
        if (provisionService == null) {
            throw new RuntimeException("Could not resolve a provision service");
        }
        // build list of provisioning specs out of command line arguments and profiles
        final List<String> provisionSpecs = new ArrayList<String>();
        provisionSpecs.addAll(context.getCommandLine().getArguments());
        provisionSpecs.addAll(transformProfilesToProvisionSpecs(context));

        // backup properties and replace them with audited properties
        final Properties sysPropsBackup = System.getProperties();
        try {
            context.setSystemProperties(new AuditedProperties(sysPropsBackup));
            System.setProperties(context.getSystemProperties());

            final Set<ScannedBundle> scannedBundles = new HashSet<ScannedBundle>();
            // then scan those url's
            for (String provisionSpec : provisionSpecs) {
                try {
                    try {
                        provisionService.wrap(filterUnique(scannedBundles, provisionService.scan(provisionSpec)))
                                .install();
                    } catch (UnsupportedSchemaException e) {
                        final String resolvedProvisionURL = schemaResolver.resolve(provisionSpec);
                        if (resolvedProvisionURL != null && !resolvedProvisionURL.equals(provisionSpec)) {
                            provisionService
                                    .wrap(filterUnique(scannedBundles, provisionService.scan(resolvedProvisionURL)))
                                    .install();
                        } else {
                            throw e;
                        }
                    }
                } catch (MalformedSpecificationException e) {
                    throw new RuntimeException(e);
                } catch (ScannerException e) {
                    throw new RuntimeException(e);
                } catch (BundleException e) {
                    throw new RuntimeException(e);
                }
            }
        } finally {
            // restore the backup-ed properties
            System.setProperties(sysPropsBackup);
        }
    }

    /**
     * Transforms requested profiles (--profiles option) to provisioning specs (scan-composite).
     *
     * @param context runner context
     *
     * @return list of transformed provisioning specs or an empty list if there are no profiles.
     */
    private List<String> transformProfilesToProvisionSpecs(final Context context) {
        final List<String> provisionSpecs = new ArrayList<String>();

        final String profilesOption = context.getOptionResolver().get(OPTION_PROFILES);
        if (profilesOption != null && profilesOption.trim().length() > 0) {
            final String profilesGroup = context.getOptionResolver().get(OPTION_PROFILES_GROUPID);
            final String[] profiles = profilesOption.split(":");
            for (String profile : profiles) {
                // TODO Maybe a nice/safe parsing of profile name into group/artifact/version ?
                final int startOfOptions = profile.indexOf(org.ops4j.pax.scanner.ServiceConstants.SEPARATOR_OPTION);
                String options = null;
                if (startOfOptions > 0) {
                    options = profile.substring(startOfOptions);
                    profile = profile.substring(0, startOfOptions);
                }
                final String[] parts = profile.split("/");
                provisionSpecs
                        .add(new StringBuilder().append(org.ops4j.pax.scanner.composite.ServiceConstants.SCHEMA)
                                .append(org.ops4j.pax.scanner.ServiceConstants.SEPARATOR_SCHEME)
                                .append(org.ops4j.pax.url.mvn.ServiceConstants.PROTOCOL).append(":")
                                .append(parts.length < 3 ? profilesGroup + "/" : "").append(profile)
                                .append(parts.length < 2 ? "/" : "").append("/composite")
                                .append(options != null ? options : "").toString());
            }
        }
        return provisionSpecs;
    }

    /**
     * Filter all scanned bundles that already exists in the provided set and add the unique ones to the set.
     *
     * @param alreadyScanned set of already scanned bundles
     * @param scannedBundles to be filtered
     *
     * @return unique list of scanned bundles (that were not already present in the provided set)
     */
    private List<ScannedBundle> filterUnique(final Set<ScannedBundle> alreadyScanned,
            final List<ScannedBundle> scannedBundles) {
        final Set<ScannedBundle> unique = new LinkedHashSet<ScannedBundle>(scannedBundles);
        unique.removeAll(alreadyScanned);
        alreadyScanned.addAll(unique);
        return new ArrayList<ScannedBundle>(unique);
    }

    /**
     * Installs platform extender and configured platform.
     *
     * @param context the running context
     *
     * @return installed platform
     */
    Platform installPlatform(final Context context) {
        LOGGER.debug("Installing platform");
        // first install platform
        final String platform = context.getOptionResolver().getMandatory(OPTION_PLATFORM);
        String version;
        if (Boolean.parseBoolean(context.getOptionResolver().get(OPTION_PLATFORM_VERSION_SNAPSHOT))) {
            version = PLATFORM_VERSION_SNAPSHOT;
        } else {
            version = context.getOptionResolver().get(OPTION_PLATFORM_VERSION);
        }
        if (version == null) {
            version = context.getOptionResolver().get(platform + "." + OPTION_PLATFORM_VERSION);
            if (version == null) {
                throw new ConfigurationException("Could not resolve a version for platform [" + platform + "]");
            }
        }
        version = version.toUpperCase();
        final String activatorName = context.getConfiguration().getProperty(platform + "." + version);
        if (activatorName == null || activatorName.trim().length() == 0) {
            throw new ConfigurationException("Platform [" + platform + " " + version + "] is not supported");
        }
        createActivator(platform, activatorName, context);
        // then install platform service
        final String serviceActivatorName = context.getConfiguration().getProperty(PLATFORM_SERVICE);
        if (serviceActivatorName == null || serviceActivatorName.trim().length() == 0) {
            throw new ConfigurationException("Platform Service must be configured [" + PLATFORM_SERVICE + "]");
        }
        final BundleContext bundleContext = createActivator(PLATFORM_SERVICE, serviceActivatorName, context);
        // sanity check
        if (bundleContext == null) {
            throw new RuntimeException("Could not create bundle context for platform service");
        }
        final ServiceReference[] references;
        try {
            references = bundleContext.getServiceReferences(Platform.class.getName(), "(version=" + version + ")");
        } catch (InvalidSyntaxException ignore) {
            // this should never happen
            throw new ConfigurationException("Platform [" + platform + " " + version + "] is not supported");
        }
        if (references == null || references.length == 0) {
            throw new RuntimeException("Could not resolve a platform");
        }
        final ServiceReference reference = references[0];
        return (Platform) bundleContext.getService(reference);
    }

    /**
     * Starts the installed platform.
     *
     * @param context  the running context
     * @param platform installed platform
     * @param runner   Java runner service
     */
    private void startPlatform(final Platform platform, final Context context, final JavaRunner runner) {
        LOGGER.debug("Starting platform");
        if (platform == null) {
            throw new RuntimeException("Could not resolve a platform");
        }
        final List<RunnerBundle> installedBundles = context.getBundles();
        final List<BundleReference> references = new ArrayList<BundleReference>();
        if (installedBundles != null) {
            for (RunnerBundle bundle : installedBundles) {
                LOGGER.info("Provision bundle [" + bundle + "]");
                references.add(new BundleReferenceBean(bundle.getLocationAsURL().toExternalForm(),
                        bundle.getLocationAsURL(), bundle.getStartLevel(), bundle.shouldStart(),
                        bundle.shouldUpdate()));
            }
        }
        try {
            platform.start(determineSystemFiles(context), references, context.getSystemProperties(), null, runner);
        } catch (PlatformException e) {
            throw new RuntimeException(e);
        }
    }

    List<SystemFileReference> determineSystemFiles(final Context context) {
        final List<SystemFileReference> systemFiles = new ArrayList<SystemFileReference>();
        try {
            final String[] bcppUrls = context.getOptionResolver().getMultiple(CommandLine.OPTION_BOOT_CP_PREPEND);
            if (bcppUrls.length > 0) {
                for (String url : bcppUrls) {
                    systemFiles.add(new SystemFileReferenceBean(url, new URL(url), true));
                }
            }
            final String[] bcpaUrls = context.getOptionResolver().getMultiple(CommandLine.OPTION_BOOT_CP_APPEND);
            if (bcpaUrls.length > 0) {
                for (String url : bcpaUrls) {
                    systemFiles.add(new SystemFileReferenceBean(url, new URL(url), false));
                }
            }
            String keepOriginalUrls = context.getOptionResolver().get(CommandLine.OPTION_KEEP_ORIGINAL_URLS);
            if (Boolean.valueOf(keepOriginalUrls)) {
                Configuration configuration = context.getConfiguration();
                String handlerUrls = configuration.getProperty(KEEP_ORIGINAL_HANDLER_URLS);
                if (handlerUrls != null) {
                    String[] urlKeys = handlerUrls.split(",");
                    if (urlKeys != null) {
                        for (String key : urlKeys) {
                            NullArgumentException.validateNotEmpty(key, "Handler URL entry");
                            String handlerUrl = configuration.getProperty(key);
                            LOGGER.debug("Handler URL [" + handlerUrl + "]");
                            if (handlerUrl == null || handlerUrl.trim().length() == 0) {
                                throw new ConfigurationException("Handler URL [" + key + "] is not supported");
                            }
                            systemFiles.add(new SystemFileReferenceBean(key, new URL(handlerUrl)));
                        }
                    }
                }
            }

        } catch (MalformedURLException e) {
            throw new RuntimeException(e);
        }
        return systemFiles;
    }

    /**
     * Activator factory method.
     *
     * @param bundleName     name of the bundle to be created
     * @param activatorClazz class name of the activator
     * @param context        the running context
     *
     * @return activator related bundle context
     */
    BundleContext createActivator(final String bundleName, final String activatorClazz, final Context context) {
        try {
            final BundleActivator activator = (BundleActivator) Class.forName(activatorClazz).newInstance();
            final BundleContext bundleContext = new RunnerBundleContext(context);
            activator.start(bundleContext);
            return bundleContext;
        } catch (Exception e) {
            throw new RuntimeException("Could not create [" + bundleName + "]", e);
        }
    }

    /**
     * Display ops4j logo to console.
     */
    private static void showLogo() {
        System.out.println("__________                 __________                                 ");
        System.out.println("\\______   \\_____  ___  ___ \\______   \\__ __  ____   ____   ___________");
        System.out.println("|     ___/\\__  \\ \\  \\/  /  |       _/  |  \\/    \\ /    \\_/ __ \\_  __ \\");
        System.out.println("|    |     / __ \\_>    <   |    |   \\  |  /   |  \\   |  \\  ___/|  | \\/");
        System.out.println("|____|    (____  /__/\\_ \\  |____|_  /____/|___|  /___|  /\\___  >__|   ");
        System.out.println("               \\/      \\/         \\/           \\/     \\/     \\/       ");
        System.out.println();
        final String logo = "Pax Runner " + getVersion() + "from OPS4J - http://www.ops4j.org";
        System.out.println(logo);
        System.out.println(
                "--------------------------------------------------------------------------------------------------------"
                        .substring(0, logo.length()));
        System.out.println();
    }

    /**
     * Discovers the Pax Runner version. If version cannot be determined returns an empty string.
     *
     * @return pax runner version
     */
    private static String getVersion() {
        try {
            final InputStream is = Run.class.getClassLoader().getResourceAsStream("META-INF/runner.version");
            if (is != null) {
                final Properties properties = new Properties();
                properties.load(is);
                final String version = properties.getProperty("version");
                if (version != null) {
                    return "(" + version + ") ";
                }
                return "";
            }
            return "";
        } catch (Exception ignore) {
            return "";
        }
    }

    /**
     * Show execution problem to console.
     *
     * @param t the problem
     */
    private static void showError(Throwable t) {
        Info.println();
        String message = t.getMessage();
        String debugInfo = "";

        if (LOGGER != null && !LOGGER.isDebugEnabled()) {
            debugInfo = "Use --" + OPTION_LOG + "=debug to see details.";
        }

        System.out.println("         ___");
        System.out.println("        /  /");
        System.out.println("       /  / Oops, there has been a problem!");
        System.out.println("      /  /  ");
        System.out.println("     /__/   " + message);
        System.out.println("    ___");
        System.out.println("   /__/     " + debugInfo);
        System.out.println();

        if (LOGGER == null) {
            // show error even when LOGGER was not initialised
            System.out.println("Exception caught during execution:");
            t.printStackTrace();
        } else {
            if (LOGGER.isDebugEnabled()) {
                LOGGER.error("Exception caught during execution:", t);
            }
        }

    }

    /**
     * Initialize the logger based on option "debug".
     *
     * @param commandLine command lin ein use
     */
    private static void initializeLogger(final CommandLine commandLine) {
        String debug = commandLine.getOption(OPTION_LOG);
        if (debug != null) {
            try {
                createLogger(LogLevel.valueOf(debug.toUpperCase()));
            } catch (Exception ignore) {
                createLogger(LogLevel.INFO);
                LOGGER.warn("Unknown debug option [" + debug + "], switching to INFO");
            }
        } else {
            createLogger(LogLevel.INFO);
        }
    }

    /**
     * Creates the logger to use at the specified log level. The log level is only supported by the "special" JCL
     * implementation embedded into Pax Runner. In case that the JCL in the classpath in snot the embedded one it will
     * fallback to standard JCL usage.
     *
     * @param logLevel log level to use
     */
    private static void createLogger(final LogLevel logLevel) {
        try {
            LOGGER = LogFactory.getLog(Run.class, logLevel);
        } catch (NoSuchMethodError ignore) {
            // fall back to standard JCL
            LOGGER = LogFactory.getLog(Run.class);
        }
    }

    /**
     * Creates a default logger at INFo level.
     */
    private static void createLogger() {
        try {
            createLogger(LogLevel.INFO);
        } catch (NoClassDefFoundError ignore) {
            // fall back to standard JCL
            LOGGER = LogFactory.getLog(Run.class);
        }
    }
}