blob: 4e08d8dc248e26babf4bfb19d7a4b96129adfcec [file] [log] [blame]
/*
*
* 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.qpid.server;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Set;
import java.util.TreeSet;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.apache.qpid.configuration.CommonProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.qpid.server.configuration.IllegalConfigurationException;
import org.apache.qpid.server.model.Protocol;
import org.apache.qpid.server.plugin.ProtocolEngineCreator;
import org.apache.qpid.server.plugin.QpidServiceLoader;
import org.apache.qpid.server.util.Action;
import org.apache.qpid.server.util.StringUtil;
import org.apache.qpid.util.FileUtils;
/**
* Main entry point for AMQPD.
*
*/
public class Main
{
private static final int MANAGEMENT_MODE_PASSWORD_LENGTH = 10;
private static final Option OPTION_HELP = new Option("h", "help", false, "print this message");
private static final Option OPTION_VERSION = new Option("v", "version", false, "print the version information and exit");
private static final Option OPTION_CONFIGURATION_STORE_PATH = OptionBuilder.withArgName("path").hasArg()
.withDescription("use given configuration store location").withLongOpt("store-path").create("sp");
private static final Option OPTION_CONFIGURATION_STORE_TYPE = OptionBuilder.withArgName("type").hasArg()
.withDescription("use given broker configuration store type").withLongOpt("store-type").create("st");
private static final Option OPTION_INITIAL_CONFIGURATION_PATH = OptionBuilder.withArgName("path").hasArg()
.withDescription("set the location of initial JSON config to use when creating/overwriting a broker configuration store").withLongOpt("initial-config-path").create("icp");
private static final Option OPTION_OVERWRITE_CONFIGURATION_STORE = OptionBuilder.withDescription("overwrite the broker configuration store with the current initial configuration")
.withLongOpt("overwrite-store").create("os");
private static final Option OPTION_CREATE_INITIAL_CONFIG = OptionBuilder.withArgName("path").hasOptionalArg().withDescription("create a copy of the initial config file, either to an" +
" optionally specified file path, or as " + BrokerOptions.DEFAULT_INITIAL_CONFIG_NAME + " in the current directory")
.withLongOpt("create-initial-config").create("cic");
private static final Option OPTION_CONFIGURATION_PROPERTY = OptionBuilder.withArgName("name=value").hasArg()
.withDescription("set a configuration property to use when resolving variables in the broker configuration store, with format \"name=value\"")
.withLongOpt("config-property").create("prop");
private static final Option OPTION_MANAGEMENT_MODE = OptionBuilder.withDescription("start broker in management mode, disabling the AMQP ports")
.withLongOpt("management-mode").create("mm");
private static final Option OPTION_MM_QUIESCE_VHOST = OptionBuilder.withDescription("make virtualhosts stay in the quiesced state during management mode.")
.withLongOpt("management-mode-quiesce-virtualhosts").create("mmqv");
private static final Option OPTION_MM_HTTP_PORT = OptionBuilder.withArgName("port").hasArg()
.withDescription("override http management port in management mode").withLongOpt("management-mode-http-port").create("mmhttp");
private static final Option OPTION_MM_PASSWORD = OptionBuilder.withArgName("password").hasArg()
.withDescription("Set the password for the management mode user " + BrokerOptions.MANAGEMENT_MODE_USER_NAME).withLongOpt("management-mode-password").create("mmpass");
private static final Option OPTION_INITIAL_SYSTEM_PROPERTIES = OptionBuilder.withArgName("path").hasArg()
.withDescription("set the location of initial properties file to set otherwise unset system properties").withLongOpt("system-properties-file").create("props");
private static final Options OPTIONS = new Options();
static
{
OPTIONS.addOption(OPTION_HELP);
OPTIONS.addOption(OPTION_VERSION);
OPTIONS.addOption(OPTION_CONFIGURATION_STORE_PATH);
OPTIONS.addOption(OPTION_CONFIGURATION_STORE_TYPE);
OPTIONS.addOption(OPTION_OVERWRITE_CONFIGURATION_STORE);
OPTIONS.addOption(OPTION_CREATE_INITIAL_CONFIG);
OPTIONS.addOption(OPTION_INITIAL_CONFIGURATION_PATH);
OPTIONS.addOption(OPTION_MANAGEMENT_MODE);
OPTIONS.addOption(OPTION_MM_QUIESCE_VHOST);
OPTIONS.addOption(OPTION_MM_HTTP_PORT);
OPTIONS.addOption(OPTION_MM_PASSWORD);
OPTIONS.addOption(OPTION_CONFIGURATION_PROPERTY);
OPTIONS.addOption(OPTION_INITIAL_SYSTEM_PROPERTIES);
CommonProperties.ensureIsLoaded();
}
protected CommandLine _commandLine;
public static void main(String[] args)
{
new Main(args);
}
public Main(final String[] args)
{
if (parseCommandline(args))
{
try
{
execute();
}
catch(Exception e)
{
System.err.println("Exception during startup: " + e);
e.printStackTrace();
shutdown(1);
}
}
}
protected boolean parseCommandline(final String[] args)
{
try
{
_commandLine = new PosixParser().parse(OPTIONS, args);
return true;
}
catch (ParseException e)
{
System.err.println("Error: " + e.getMessage());
HelpFormatter formatter = new HelpFormatter();
formatter.printHelp("Qpid", OPTIONS, true);
return false;
}
}
protected void execute() throws Exception
{
String initialProperties = _commandLine.getOptionValue(OPTION_INITIAL_SYSTEM_PROPERTIES.getOpt());
Broker.populateSystemPropertiesFromDefaults(initialProperties);
BrokerOptions options = new BrokerOptions();
if (initialProperties != null)
{
options.setInitialSystemProperties(initialProperties);
}
String initialConfigLocation = _commandLine.getOptionValue(OPTION_INITIAL_CONFIGURATION_PATH.getOpt());
if (initialConfigLocation != null)
{
options.setInitialConfigurationLocation(initialConfigLocation);
}
//process the remaining options
if (_commandLine.hasOption(OPTION_HELP.getOpt()))
{
final HelpFormatter formatter = new HelpFormatter();
formatter.printHelp("Qpid", OPTIONS, true);
}
else if (_commandLine.hasOption(OPTION_CREATE_INITIAL_CONFIG.getOpt()))
{
File destinationFile = null;
String destinationOption = _commandLine.getOptionValue(OPTION_CREATE_INITIAL_CONFIG.getOpt());
if (destinationOption != null)
{
destinationFile = new File(destinationOption);
}
else
{
destinationFile = new File(System.getProperty("user.dir"), BrokerOptions.DEFAULT_INITIAL_CONFIG_NAME);
}
copyInitialConfigFile(options, destinationFile);
System.out.println("Initial config written to: " + destinationFile.getAbsolutePath());
}
else if (_commandLine.hasOption(OPTION_VERSION.getOpt()))
{
final StringBuilder protocol = new StringBuilder("AMQP version(s) [major.minor]: ");
boolean first = true;
Set<Protocol> protocols = new TreeSet<>();
for(ProtocolEngineCreator installedEngine : (new QpidServiceLoader()).instancesOf(ProtocolEngineCreator.class))
{
protocols.add(installedEngine.getVersion());
}
for(Protocol supportedProtocol : protocols)
{
if (first)
{
first = false;
}
else
{
protocol.append(", ");
}
protocol.append(supportedProtocol.getProtocolVersion());
}
System.out.println(CommonProperties.getVersionString() + " (" + protocol + ")");
}
else
{
String[] configPropPairs = _commandLine.getOptionValues(OPTION_CONFIGURATION_PROPERTY.getOpt());
if(configPropPairs != null && configPropPairs.length > 0)
{
for(String s : configPropPairs)
{
int firstEquals = s.indexOf("=");
if(firstEquals == -1)
{
throw new IllegalArgumentException("Configuration property argument is not of the format name=value: " + s);
}
String name = s.substring(0, firstEquals);
String value = s.substring(firstEquals + 1);
if(name.equals(""))
{
throw new IllegalArgumentException("Configuration property argument is not of the format name=value: " + s);
}
options.setConfigProperty(name, value);
}
}
String configurationStore = _commandLine.getOptionValue(OPTION_CONFIGURATION_STORE_PATH.getOpt());
if (configurationStore != null)
{
options.setConfigurationStoreLocation(configurationStore);
}
String configurationStoreType = _commandLine.getOptionValue(OPTION_CONFIGURATION_STORE_TYPE.getOpt());
if (configurationStoreType != null)
{
options.setConfigurationStoreType(configurationStoreType);
}
boolean overwriteConfigurationStore = _commandLine.hasOption(OPTION_OVERWRITE_CONFIGURATION_STORE.getOpt());
options.setOverwriteConfigurationStore(overwriteConfigurationStore);
boolean managementMode = _commandLine.hasOption(OPTION_MANAGEMENT_MODE.getOpt());
if (managementMode)
{
options.setManagementMode(true);
String httpPort = _commandLine.getOptionValue(OPTION_MM_HTTP_PORT.getOpt());
if (httpPort != null)
{
options.setManagementModeHttpPortOverride(Integer.parseInt(httpPort));
}
boolean quiesceVhosts = _commandLine.hasOption(OPTION_MM_QUIESCE_VHOST.getOpt());
options.setManagementModeQuiesceVirtualHosts(quiesceVhosts);
String password = _commandLine.getOptionValue(OPTION_MM_PASSWORD.getOpt());
if (password == null)
{
password = new StringUtil().randomAlphaNumericString(MANAGEMENT_MODE_PASSWORD_LENGTH);
}
options.setManagementModePassword(password);
}
setExceptionHandler();
startBroker(options);
}
}
private void copyInitialConfigFile(final BrokerOptions options, final File destinationFile)
{
String initialConfigLocation = options.getInitialConfigurationLocation();
URL url = null;
try
{
url = new URL(initialConfigLocation);
}
catch (MalformedURLException e)
{
File locationFile = new File(initialConfigLocation);
try
{
url = locationFile.toURI().toURL();
}
catch (MalformedURLException e1)
{
throw new IllegalConfigurationException("Cannot create URL for file " + locationFile, e1);
}
}
InputStream in = null;
try
{
in = url.openStream();
FileUtils.copy(in, destinationFile);
}
catch (IOException e)
{
throw new IllegalConfigurationException("Cannot create file " + destinationFile
+ " by copying initial config from " + initialConfigLocation, e);
}
finally
{
if (in != null)
{
try
{
in.close();
}
catch (IOException e)
{
throw new IllegalConfigurationException("Cannot close initial config input stream: " + initialConfigLocation, e);
}
}
}
}
protected void setExceptionHandler()
{
Thread.UncaughtExceptionHandler handler = null;
String handlerClass = System.getProperty("qpid.broker.exceptionHandler");
if(handlerClass != null)
{
try
{
handler = (Thread.UncaughtExceptionHandler) Class.forName(handlerClass).newInstance();
}
catch (ClassNotFoundException e)
{
}
catch (InstantiationException e)
{
}
catch (IllegalAccessException e)
{
}
catch (ClassCastException e)
{
}
}
if(handler == null)
{
handler =
new Thread.UncaughtExceptionHandler()
{
public void uncaughtException(final Thread t, final Throwable e)
{
boolean continueOnError = Boolean.getBoolean("qpid.broker.exceptionHandler.continue");
try
{
System.err.println("########################################################################");
System.err.println("#");
System.err.print("# Unhandled Exception ");
System.err.print(e.toString());
System.err.print(" in Thread ");
System.err.println(t.getName());
System.err.println("#");
System.err.println(continueOnError ? "# Forced to continue by JVM setting 'qpid.broker.exceptionHandler.continue'" : "# Exiting");
System.err.println("#");
System.err.println("########################################################################");
e.printStackTrace(System.err);
Logger logger = LoggerFactory.getLogger("org.apache.qpid.server.Main");
logger.error("Uncaught exception, " + (continueOnError ? "continuing." : "shutting down."), e);
}
finally
{
if (!continueOnError)
{
Runtime.getRuntime().halt(1);
}
}
}
};
Thread.setDefaultUncaughtExceptionHandler(handler);
}
}
protected void startBroker(final BrokerOptions options) throws Exception
{
Broker broker = new Broker(new Action<Integer>()
{
@Override
public void performAction(final Integer exitStatusCode)
{
if (exitStatusCode != 0)
{
shutdown(exitStatusCode);
}
}
});
broker.startup(options);
}
protected void shutdown(final int status)
{
System.exit(status);
}
}