All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.mule.MuleServer Maven / Gradle / Ivy

There is a newer version: 3.9.0
Show newest version
/*
 * $Id: MuleServer.java 22252 2011-06-23 06:15:55Z dirk.olmes $
 * --------------------------------------------------------------------------------------
 * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
 *
 * The software in this package is published under the terms of the CPAL v1.0
 * license, a copy of which has been included with this distribution in the
 * LICENSE.txt file.
 */

package org.mule;

import org.mule.api.DefaultMuleException;
import org.mule.api.MuleContext;
import org.mule.api.MuleException;
import org.mule.api.config.ConfigurationBuilder;
import org.mule.api.config.ConfigurationException;
import org.mule.api.config.MuleConfiguration;
import org.mule.api.context.MuleContextBuilder;
import org.mule.api.context.MuleContextFactory;
import org.mule.config.ExceptionHelper;
import org.mule.config.PropertiesMuleConfigurationFactory;
import org.mule.config.StartupContext;
import org.mule.config.builders.SimpleConfigurationBuilder;
import org.mule.config.i18n.CoreMessages;
import org.mule.config.i18n.Message;
import org.mule.context.DefaultMuleContextBuilder;
import org.mule.context.DefaultMuleContextFactory;
import org.mule.util.ClassUtils;
import org.mule.util.IOUtils;
import org.mule.util.MuleUrlStreamHandlerFactory;
import org.mule.util.PropertiesUtils;
import org.mule.util.StringMessageUtils;
import org.mule.util.SystemUtils;

import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * MuleServer is a simple application that represents a local Mule
 * Server daemon. It is initialised with a mule-config.xml file.
 */
public class MuleServer implements Runnable
{
    public static final String CLI_OPTIONS[][] = {
        {"builder", "true", "Configuration Builder Type"},
        {"config", "true", "Configuration File"},
        {"appconfig", "true", "Application configuration File"},
        {"idle", "false", "Whether to run in idle (unconfigured) mode"},
        {"main", "true", "Main Class"},
        {"mode", "true", "Run Mode"},
        {"props", "true", "Startup Properties"},
        {"production", "false", "Production Mode"},
        {"debug", "false", "Configure Mule for JPDA remote debugging."}
    };

    /**
     * Don't use a class object so the core doesn't depend on mule-module-spring-config.
     */
    protected static final String CLASSNAME_DEFAULT_CONFIG_BUILDER = "org.mule.config.builders.AutoConfigurationBuilder";

    /**
     * This builder sets up the configuration for an idle Mule node - a node that
     * doesn't do anything initially but is fed configuration during runtime
     */
    protected static final String CLASSNAME_DEFAULT_IDLE_CONFIG_BUILDER = "org.mule.config.builders.MuleIdleConfigurationBuilder";

    /**
     * Required to support the '-config spring' shortcut. Don't use a class object so
     * the core doesn't depend on mule-module-spring.
     * for Mule 2.x
     */
    protected static final String CLASSNAME_SPRING_CONFIG_BUILDER = "org.mule.config.spring.SpringXmlConfigurationBuilder";

    /**
     * If the annotations module is on the classpath, also enable annotations config builder
     */
    public static final String CLASSNAME_ANNOTATIONS_CONFIG_BUILDER = "org.mule.config.AnnotationsConfigurationBuilder";

    /**
     * If the iBeans module is on the classpath, this config builder can be used to scan for iBeans annotations.
     */
    public static final String CLASSNAME_IBEANS_CONFIG_BUILDER = "org.mule.module.ibeans.config.IBeanHolderConfigurationBuilder";

    /**
     * logger used by this class
     */
    private static final Log logger = LogFactory.getLog(MuleServer.class);

    public static final String DEFAULT_CONFIGURATION = "mule-config.xml";

    public static final String DEFAULT_APP_CONFIGURATION = "mule-app.properties";

    /**
     * one or more configuration urls or filenames separated by commas
     */
    private String configurationResources = null;

    private String appConfigurationResource = null;

    /**
     * A FQN of the #configBuilder class, required in case MuleServer is
     * reinitialised.
     */
    private static String configBuilderClassName = null;

    /**
     * A properties file to be read at startup. This can be useful for setting
     * properties which depend on the run-time environment (dev, test, production).
     */
    private static String startupPropertiesFile = null;

    /**
     * The Runtime shutdown thread used to dispose this server
     */
    private static MuleShutdownHook muleShutdownHook;

    /**
     * The MuleContext should contain anything which does not belong in the Registry.
     * There is one MuleContext per Mule instance. Assuming it has been created, a
     * handle to the local MuleContext can be obtained from anywhere by calling
     * MuleServer.getMuleContext()
     */
    protected static MuleContext muleContext = null;

    /**
     * Application entry point.
     *
     * @param args command-line args
     * @throws Exception if there is an exception creating the MuleServer
     */
    public static void main(String[] args) throws Exception
    {
        MuleServer server = new MuleServer(args);
        server.start(false, true);
    }

    public MuleServer()
    {
        init(new String[]{});
    }

    public MuleServer(String configResources)
    {
        // setConfigurationResources(configResources);
        init(new String[]{"-config", configResources});
    }

    /**
     * Configure the server with command-line arguments.
     * @param args Command line args passed in from the {@link #main(String[])} method
     * @throws IllegalArgumentException if an argument is passed in that is not recognised by the Mule Server
     */
    public MuleServer(String[] args) throws IllegalArgumentException
    {
        init(args);
    }

    protected void init(String[] args) throws IllegalArgumentException
    {
        Map commandlineOptions;

        try
        {
            commandlineOptions = SystemUtils.getCommandLineOptions(args, CLI_OPTIONS);
        }
        catch (DefaultMuleException me)
        {
            throw new IllegalArgumentException(me.toString());
        }

        // set our own UrlStreamHandlerFactory to become more independent of system
        // properties
        MuleUrlStreamHandlerFactory.installUrlStreamHandlerFactory();

        String config = (String) commandlineOptions.get("config");
        // Try default if no config file was given.
        if (config == null && !commandlineOptions.containsKey("idle"))
        {
            logger.warn("A configuration file was not set, using default: " + DEFAULT_CONFIGURATION);
            // try to load the config as a file as well
            URL configUrl = IOUtils.getResourceAsUrl(DEFAULT_CONFIGURATION, MuleServer.class, true, false);
            if (configUrl != null)
            {
                config = configUrl.toExternalForm();
            }
            else
            {
                System.out.println(CoreMessages.configNotFoundUsage());
                System.exit(-1);
            }
        }

        if (config != null)
        {
            setConfigurationResources(config);
        }

        String appconfig = (String) commandlineOptions.get("appconfig");
        this.appConfigurationResource = appconfig;

        // Configuration builder
        String cfgBuilderClassName = (String) commandlineOptions.get("builder");

        if (commandlineOptions.containsKey("idle"))
        {
            setConfigurationResources("IDLE");
            cfgBuilderClassName = CLASSNAME_DEFAULT_IDLE_CONFIG_BUILDER;
        }

        // Configuration builder
        if (cfgBuilderClassName != null)
        {
            try
            {
                // Provide a shortcut for Spring: "-builder spring"
                if (cfgBuilderClassName.equalsIgnoreCase("spring"))
                {
                    cfgBuilderClassName = CLASSNAME_SPRING_CONFIG_BUILDER;
                }
                setConfigBuilderClassName(cfgBuilderClassName);
            }
            catch (Exception e)
            {
                logger.fatal(e);
                final Message message = CoreMessages.failedToLoad("Builder: " + cfgBuilderClassName);
                System.err.println(StringMessageUtils.getBoilerPlate("FATAL: " + message.toString()));
                System.exit(1);
            }
        }

        // Startup properties
        String propertiesFile = (String) commandlineOptions.get("props");
        if (propertiesFile != null)
        {
            setStartupPropertiesFile(propertiesFile);
        }

        StartupContext.get().setStartupOptions(commandlineOptions);
    }

    /**
     * Start the mule server
     *
     * @param ownThread determines if the server will run in its own daemon thread or
     *                  the current calling thread
     * @param registerShutdownHook whether to register the default Mule Server shutdown hock.  this will shut down mule cleanly if
     * the JVM is shutdown.  The only reason not to register this hook is to override it with a custom version
     */
    public void start(boolean ownThread, boolean registerShutdownHook)
    {
        if (registerShutdownHook)
        {
            registerShutdownHook();
        }
        if (ownThread)
        {
            Thread serverThread = new Thread(this, "MuleServer");
            serverThread.setDaemon(true);
            serverThread.start();
        }
        else
        {
            run();
        }
    }

    /**
     * Overloaded the [main] thread run method. This calls initialise and shuts down
     * if an exception occurs
     */
    public void run()
    {
        try
        {
            logger.info("Mule Server initializing...");
            initialize();
            logger.info("Mule Server starting...");
            muleContext.start();
        }
        catch (Throwable e)
        {
            shutdown(e);
        }
    }

    /**
     * Sets the configuration builder to use for this server. Note that if a builder
     * is not set and the server's start method is called the default is an instance
     * of SpringXmlConfigurationBuilder.
     *
     * @param builderClassName the configuration builder FQN to use
     * @throws ClassNotFoundException if the class with the given name can not be
     *                                loaded
     */
    public static void setConfigBuilderClassName(String builderClassName) throws ClassNotFoundException
    {
        if (builderClassName != null)
        {
            Class cls = ClassUtils.loadClass(builderClassName, MuleServer.class);
            if (ConfigurationBuilder.class.isAssignableFrom(cls))
            {
                MuleServer.configBuilderClassName = builderClassName;
            }
            else
            {
                throw new IllegalArgumentException("Not a usable ConfigurationBuilder class: "
                        + builderClassName);
            }
        }
        else
        {
            MuleServer.configBuilderClassName = null;
        }
    }

    /**
     * Returns the class name of the configuration builder used to create this
     * MuleServer.
     *
     * @return FQN of the current config builder
     */
    public static String getConfigBuilderClassName()
    {
        if (configBuilderClassName != null)
        {
            return configBuilderClassName;
        }
        else
        {
            return CLASSNAME_DEFAULT_CONFIG_BUILDER;
        }
    }

    /**
     * Initializes this daemon. Derived classes could add some extra behaviour if
     * they wish.
     *
     * @throws Exception if failed to initialize
     */
    public void initialize() throws Exception
    {
        if (configurationResources == null)
        {
            logger.warn("A configuration file was not set, using default: " + DEFAULT_CONFIGURATION);
            configurationResources = DEFAULT_CONFIGURATION;
        }

        // create a new ConfigurationBuilder that is disposed afterwards
        ConfigurationBuilder cfgBuilder = createConfigurationBuilder();

        if (!cfgBuilder.isConfigured())
        {
            List configBuilders = new ArrayList(3);

            // need to add the annotations config builder before Spring so we can use Mule
            // annotations in Spring
            addAnnotationsConfigBuilder(configBuilders);
            addStartupPropertiesConfigBuilder(configBuilders);
            configBuilders.add(cfgBuilder);

            MuleConfiguration configuration = createMuleConfiguration();

            MuleContextBuilder contextBuilder = new DefaultMuleContextBuilder();
            contextBuilder.setMuleConfiguration(configuration);

            MuleContextFactory contextFactory = new DefaultMuleContextFactory();
            muleContext = contextFactory.createMuleContext(configBuilders, contextBuilder);
        }
    }

    protected ConfigurationBuilder createConfigurationBuilder() throws ConfigurationException
    {
        try
        {
            return (ConfigurationBuilder) ClassUtils.instanciateClass(getConfigBuilderClassName(),
                    new Object[]{ configurationResources }, MuleServer.class);
        }
        catch (Exception e)
        {
            throw new ConfigurationException(CoreMessages.failedToLoad(getConfigBuilderClassName()), e);
        }
    }

    /**
     * If the annotations module is on the classpath, add the annotations config builder to the
     * list. This will enable annotations config for this instance.
     */
    protected void addAnnotationsConfigBuilder(List builders) throws Exception
    {
        if (ClassUtils.isClassOnPath(CLASSNAME_ANNOTATIONS_CONFIG_BUILDER, getClass()))
        {
            Object configBuilder = ClassUtils.instanciateClass(CLASSNAME_ANNOTATIONS_CONFIG_BUILDER,
                ClassUtils.NO_ARGS, getClass());
            builders.add((ConfigurationBuilder) configBuilder);
        }
    }

    protected void addStartupPropertiesConfigBuilder(List builders) throws IOException
    {
        Properties startupProperties = null;
        if (getStartupPropertiesFile() != null)
        {
            startupProperties = PropertiesUtils.loadProperties(getStartupPropertiesFile(), getClass());
        }

        builders.add(new SimpleConfigurationBuilder(startupProperties));
    }

    protected MuleConfiguration createMuleConfiguration()
    {
        String appPropertiesFile = null;
        if (this.appConfigurationResource == null)
        {
            appPropertiesFile = PropertiesMuleConfigurationFactory.getMuleAppConfiguration(this.configurationResources);
        }
        else
        {
            appPropertiesFile = this.appConfigurationResource;
        }

        return new PropertiesMuleConfigurationFactory(appPropertiesFile).createConfiguration();
    }

    /**
     * Will shut down the server displaying the cause and time of the shutdown
     *
     * @param e the exception that caused the shutdown
     */
    public void shutdown(Throwable e)
    {
        doShutdown();
        unregisterShutdownHook();

        Message msg = CoreMessages.fatalErrorWhileRunning();
        MuleException muleException = ExceptionHelper.getRootMuleException(e);
        int exitCode = 1;
        if (muleException != null)
        {
            logger.fatal(muleException.getDetailedMessage());
            exitCode = muleException.getExceptionCode();
        }
        else
        {
            logger.fatal(msg.toString() + " " + e.getMessage(), e);
        }
        List msgs = new ArrayList();
        msgs.add(msg.getMessage());
        Throwable root = ExceptionHelper.getRootException(e);
        msgs.add(root.getMessage() + " (" + root.getClass().getName() + ")");
        msgs.add(" ");
        msgs.add(CoreMessages.fatalErrorInShutdown().getMessage());
        String shutdownMessage = StringMessageUtils.getBoilerPlate(msgs, '*', 80);
        logger.fatal(shutdownMessage);

        System.exit(exitCode);
    }

    /**
     * shutdown the server. This just displays the time the server shut down
     */
    public void shutdown()
    {
        logger.info("Mule server shutting down due to normal shutdown request");

        unregisterShutdownHook();
        doShutdown();
        System.exit(0);
    }

    protected void doShutdown()
    {
        if (muleContext != null)
        {
            muleContext.dispose();
            muleContext = null;
        }
    }

    public Log getLogger()
    {
        return logger;
    }

    public void registerShutdownHook()
    {
        if (muleShutdownHook == null)
        {
            muleShutdownHook = new MuleShutdownHook();
        }
        else
        {
            Runtime.getRuntime().removeShutdownHook(muleShutdownHook);
        }
        Runtime.getRuntime().addShutdownHook(muleShutdownHook);
    }

    public void unregisterShutdownHook()
    {
        if (muleShutdownHook != null)
        {
            Runtime.getRuntime().removeShutdownHook(muleShutdownHook);
        }
    }

    // /////////////////////////////////////////////////////////////////
    // Getters and setters
    // /////////////////////////////////////////////////////////////////

    /**
     * Getter for property messengerURL.
     *
     * @return Value of property messengerURL.
     */
    public String getConfigurationResources()
    {
        return configurationResources;
    }

    /**
     * Setter for property configurationResources.
     *
     * @param configurationResources New value of property configurationResources.
     */
    public void setConfigurationResources(String configurationResources)
    {
        this.configurationResources = configurationResources;
    }

    public static String getStartupPropertiesFile()
    {
        return startupPropertiesFile;
    }

    public static void setStartupPropertiesFile(String startupPropertiesFile)
    {
        MuleServer.startupPropertiesFile = startupPropertiesFile;
    }

    public MuleContext getMuleContext()
    {
        return muleContext;
    }

    /**
     * This class is installed only for MuleServer running as commandline app. A
     * clean Mule shutdown can be achieved by disposing the
     * {@link org.mule.DefaultMuleContext}.
     */
    private class MuleShutdownHook extends Thread
    {
        public MuleShutdownHook()
        {
            super();
        }

        @Override
        public void run()
        {
            doShutdown();
            System.exit(0);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy