/*
* JBoss, Home of Professional Open Source.
* Copyright 2014, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wildfly.core.launcher;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import org.wildfly.core.launcher.Arguments.Argument;
/**
* Builds a list of commands used to launch a domain instance of WildFly.
* <p/>
* This builder is not thread safe and the same instance should not be used in multiple threads.
* <p/>
* The {@link #getJavaHome() default Java home} directory is used for the process controller and optionally for the
* host
* controller and the servers launched.
*
* @author <a href="mailto:jperkins@redhat.com">James R. Perkins</a>
*/
@SuppressWarnings("unused")
public class DomainCommandBuilder extends AbstractCommandBuilder<DomainCommandBuilder> implements CommandBuilder {
private static final String DOMAIN_BASE_DIR = "jboss.domain.base.dir";
private static final String DOMAIN_CONFIG_DIR = "jboss.domain.config.dir";
private static final String DOMAIN_LOG_DIR = "jboss.domain.log.dir";
private Path hostControllerJavaHome;
private Path serverJavaHome;
private Path baseDir;
private final Arguments hostControllerJavaOpts;
private final Arguments processControllerJavaOpts;
/**
* Creates a new command builder for a domain instance of WildFly.
* <p/>
* Note the {@code wildflyHome} and {@code javaHome} are not validated using the constructor. The static {@link
* #of(java.nio.file.Path)} is preferred.
*
* @param wildflyHome the WildFly home directory
* @param javaHome the default Java home directory
*/
private DomainCommandBuilder(final Path wildflyHome, final Path javaHome) {
super(wildflyHome, javaHome);
hostControllerJavaOpts = new Arguments();
hostControllerJavaOpts.addAll(DEFAULT_VM_ARGUMENTS);
processControllerJavaOpts = new Arguments();
processControllerJavaOpts.addAll(DEFAULT_VM_ARGUMENTS);
}
/**
* Creates a command builder for a domain instance of WildFly.
* <p/>
* Uses the system property {@code java.home} to find the java executable required for the default Java home.
*
* @param wildflyHome the path to the WildFly home directory
*
* @return a new builder
*/
public static DomainCommandBuilder of(final Path wildflyHome) {
return new DomainCommandBuilder(validateWildFlyDir(wildflyHome), Environment.getDefaultJavaHome());
}
/**
* Creates a command builder for a domain instance of WildFly.
* <p/>
* Uses the system property {@code java.home} to find the java executable required for the default Java home.
*
* @param wildflyHome the path to the WildFly home directory
*
* @return a new builder
*/
public static DomainCommandBuilder of(final String wildflyHome) {
return new DomainCommandBuilder(validateWildFlyDir(wildflyHome), Environment.getDefaultJavaHome());
}
/**
* Creates a command builder for a domain instance of WildFly.
*
* @param wildflyHome the path to the WildFly home directory
* @param javaHome the path to the default Java home directory
*
* @return a new builder
*/
public static DomainCommandBuilder of(final String wildflyHome, final String javaHome) {
return new DomainCommandBuilder(validateWildFlyDir(wildflyHome), validateJavaHome(javaHome));
}
/**
* Creates a command builder for a domain instance of WildFly.
*
* @param wildflyHome the path to the WildFly home directory
* @param javaHome the path default to the Java home directory
*
* @return a new builder
*/
public static DomainCommandBuilder of(final Path wildflyHome, final Path javaHome) {
return new DomainCommandBuilder(validateWildFlyDir(wildflyHome), validateJavaHome(javaHome));
}
/**
* Sets the option ({@code --backup} to keep a copy of the persistent domain configuration even if this host is not
* a domain controller.
*
* @return the builder
*/
public DomainCommandBuilder setBackup() {
addServerArgument("--backup");
return this;
}
/**
* Sets the option ({@code --cached-dc}) to boot using a locally cached copy of the domain configuration.
*
* @return the builder
*
* @see #setBackup()
*/
public DomainCommandBuilder setCachedDomainController() {
addServerArgument("--cached-dc");
return this;
}
/**
* Sets the address on which the host controller should listen for communication from the process controller
* ({@code interprocess-hc-address}). Ignores {@code null} values.
*
* @param address the address
*
* @return the builder
*/
public DomainCommandBuilder setInterProcessHostControllerAddress(final String address) {
if (address != null) {
setSingleServerArg("--interprocess-hc-address", address);
}
return this;
}
/**
* Sets the port on which the host controller should listen for communication from the process controller ({@code
* interprocess-hc-address}). Ignores {@code null} values or values less than 0.
*
* @param port the port
*
* @return the builder
*
* @throws java.lang.NumberFormatException if the port is not a valid integer
*/
public DomainCommandBuilder setInterProcessHostControllerPort(final String port) {
if (port != null) {
setInterProcessHostControllerPort(Integer.parseInt(port));
}
return this;
}
/**
* Sets the port on which the host controller should listen for communication from the process controller ({@code
* interprocess-hc-address}). Ignores values less than 0.
*
* @param port the port
*
* @return the builder
*/
public DomainCommandBuilder setInterProcessHostControllerPort(final int port) {
if (port > -1) {
setSingleServerArg("--interprocess-hc-port", Integer.toString(port));
}
return this;
}
/**
* Sets the system property {@code jboss.domain.master.address}. In a default slave host configuration this is used
* to configure the address of the master host controller. Ignores {@code null} values.
* <p/>
* <b>Note:</b> This option only works if the standard system property has not been removed from the remote host.
* If the system property was removed the address provided has no effect.
*
* @param address the address
*
* @return the builder
*/
public DomainCommandBuilder setMasterAddressHint(final String address) {
if (address != null) {
setSingleServerArg("--master-address", address);
}
return this;
}
/**
* Sets the system property {@code jboss.domain.master.port}. In a default slave host configuration this is used
* to configure the port of the master host controller. Ignores {@code null} values or values less than 0.
* <p/>
* <b>Note:</b> This option only works if the standard system property has not been removed from the remote host.
* If the system property was removed the port provided has no effect.
*
* @param port the port
*
* @return the builder
*
* @throws java.lang.NumberFormatException if the port is not a valid integer
*/
public DomainCommandBuilder setMasterPortHint(final String port) {
if (port != null) {
setMasterPortHint(Integer.parseInt(port));
}
return this;
}
/**
* Sets the system property {@code jboss.domain.master.port}. In a default slave host configuration this is used
* to configure the port of the master host controller. Ignores values less than 0.
* <p/>
* <b>Note:</b> This option only works if the standard system property has not been removed from the remote host.
* If the system property was removed the port provided has no effect.
*
* @param port the port
*
* @return the builder
*/
public DomainCommandBuilder setMasterPortHint(final int port) {
if (port > -1) {
setSingleServerArg("--master-port", Integer.toString(port));
}
return this;
}
/**
* Sets the address on which the process controller listens for communication from processes it controls. Ignores
* {@code null} values.
*
* @param address the address
*
* @return the builder
*/
public DomainCommandBuilder setProcessControllerAddress(final String address) {
if (address != null) {
setSingleServerArg("--pc-address", address);
}
return this;
}
/**
* Sets the port on which the process controller listens for communication from processes it controls. Ignores
* {@code null} values or values less than 0.
*
* @param port the port
*
* @return the builder
*
* @throws java.lang.NumberFormatException if the port is not a valid integer
*/
public DomainCommandBuilder setProcessControllerPort(final String port) {
if (port != null) {
setProcessControllerPort(Integer.parseInt(port));
}
return this;
}
/**
* Sets the port on which the process controller listens for communication from processes it controls. Ignores
* values less than 0.
*
* @param port the port
*
* @return the builder
*/
public DomainCommandBuilder setProcessControllerPort(final int port) {
if (port > -1) {
setSingleServerArg("--pc-port", Integer.toString(port));
}
return this;
}
/**
* Sets the base directory to use.
* <p/>
* The default is {@code $JBOSS_HOME/standalone}.
*
* @param baseDir the base directory or {@code null} to resolve the base directory
*
* @return the builder
*/
public DomainCommandBuilder setBaseDirectory(final String baseDir) {
this.baseDir = validateAndNormalizeDir(baseDir, true);
return this;
}
/**
* Sets the base directory to use.
* <p/>
* The default is {@code $JBOSS_HOME/standalone}.
*
* @param baseDir the base directory or {@code null} to resolve the base directory
*
* @return the builder
*/
public DomainCommandBuilder setBaseDirectory(final Path baseDir) {
this.baseDir = validateAndNormalizeDir(baseDir, true);
return this;
}
/**
* Sets the Java home for the host controller.
* <p/>
* If the {@code javaHome} is not {@code null} then the java executable will be resolved and used to launch the
* host processor. If the {@code javaHome} is {@code null} the same java executable will be used to launch the host
* controller that launched the process controller.
*
* @param javaHome the java home to set, can be {@code null} to use the default
*
* @return the builder
*/
public DomainCommandBuilder setHostControllerJavaHome(final String javaHome) {
if (javaHome == null) {
this.hostControllerJavaHome = null;
} else {
this.hostControllerJavaHome = validateJavaHome(javaHome);
}
return this;
}
/**
* Sets the Java home for the host controller.
* <p/>
* If the {@code javaHome} is not {@code null} then the java executable will be resolved and used to launch the
* host processor. If the {@code javaHome} is {@code null} the same java executable will be used to launch the host
* controller that launched the process controller.
*
* @param javaHome the java home to set, can be {@code null} to use the default
*
* @return the builder
*/
public DomainCommandBuilder setHostControllerJavaHome(final Path javaHome) {
if (javaHome == null) {
this.hostControllerJavaHome = null;
} else {
this.hostControllerJavaHome = validateJavaHome(javaHome);
}
return this;
}
/**
* Returns the Java home path the host controller will use.
* <p/>
* If the path was not previously set the default {@link #getJavaHome() Java home} will be used.
*
* @return the path to the Java home for the host controller
*/
public Path getHostControllerJavaHome() {
if (hostControllerJavaHome == null) {
return getJavaHome();
}
return hostControllerJavaHome;
}
/**
* Sets the configuration file for the host controller (host.xml). The file must be in the {@link
* #setConfigurationDirectory(String) configuration} directory. A value of {@code null} is ignored.
*
* @param configFile the configuration file name
*
* @return the builder
*/
public DomainCommandBuilder setHostConfiguration(final String configFile) {
if (configFile != null) {
setSingleServerArg("--host-config", configFile);
}
return this;
}
/**
* Returns the configuration file {@link #setHostConfiguration(String) set} or {@code null} if one was not set.
*
* @return the configuration file set or {@code null} if not set
*/
public String getHostConfiguration() {
return getServerArg("--host-config");
}
/**
* Sets the read only configuration file for the host controller (host.xml). The file must be in the {@link
* #setConfigurationDirectory(String) configuration} directory. A value of {@code null} is ignored
* <p/>
* This will override any previous value set.
*
* @param configFile the configuration file name or {@code null}
*
* @return the builder
*/
public DomainCommandBuilder setReadOnlyHostConfiguration(final String configFile) {
if (configFile != null) {
setSingleServerArg("--read-only-host-config", configFile);
}
return this;
}
/**
* Returns the configuration file {@link #setReadOnlyHostConfiguration(String)} set} or {@code null} if one was
* not set.
*
* @return the configuration file set or {@code null} if not set
*/
public String getReadOnlyHostConfiguration() {
return getServerArg("--read-only-host-config");
}
/**
* Sets the configuration file for the domain (domain.xml). The file must be in the {@link
* #setConfigurationDirectory(String) configuration} directory. A value of {@code null} is ignored.
* <p/>
* This will override any previous value set.
*
* @param configFile the configuration file name
*
* @return the builder
*/
public DomainCommandBuilder setDomainConfiguration(final String configFile) {
setSingleServerArg("-c", configFile);
return this;
}
/**
* Returns the configuration file {@link #setDomainConfiguration(String) set} or {@code null} if one was not set.
*
* @return the configuration file set or {@code null} if not set
*/
public String getDomainConfiguration() {
return getServerArg("-c");
}
/**
* Sets the read only configuration file for the domain (domain.xml). The file must be in the {@link
* #setConfigurationDirectory(String) configuration} directory. A value of {@code null} is ignored
* <p/>
* This will override any previous value set.
*
* @param configFile the configuration file name or {@code null}
*
* @return the builder
*/
public DomainCommandBuilder setReadOnlyDomainConfiguration(final String configFile) {
if (configFile != null) {
setSingleServerArg("--read-only-domain-config", configFile);
}
return this;
}
/**
* Returns the configuration file {@link #setReadOnlyDomainConfiguration(String)} set} or {@code null} if one was
* not set.
*
* @return the configuration file set or {@code null} if not set
*/
public String getReadOnlyDomainConfiguration() {
return getServerArg("--read-only-domain-config");
}
/**
* Adds a JVM argument to the host controller ignoring {@code null} values.
*
* @param arg the argument to add
*
* @return the builder
*/
public DomainCommandBuilder addHostControllerJavaOption(final String arg) {
if (arg != null && !arg.trim().isEmpty()) {
final Argument argument = Arguments.parse(arg);
switch (argument.getKey()) {
case DOMAIN_BASE_DIR:
if (argument.getValue() != null) {
setBaseDirectory(argument.getValue());
}
break;
case DOMAIN_CONFIG_DIR:
if (argument.getValue() != null) {
setConfigurationDirectory(argument.getValue());
}
break;
case DOMAIN_LOG_DIR:
if (argument.getValue() != null) {
setLogDirectory(argument.getValue());
}
break;
default:
hostControllerJavaOpts.add(argument);
break;
}
}
return this;
}
/**
* Adds a JVM arguments to the host controller ignoring {@code null} values.
*
* @param args the arguments to add
*
* @return the builder
*/
public DomainCommandBuilder addHostControllerJavaOptions(final String... args) {
if (args != null) {
for (String arg : args) {
addHostControllerJavaOption(arg);
}
}
return this;
}
/**
* Adds a JVM arguments to the host controller ignoring {@code null} values.
*
* @param args the arguments to add
*
* @return the builder
*/
public DomainCommandBuilder addHostControllerJavaOptions(final Iterable<String> args) {
if (args != null) {
for (String arg : args) {
addHostControllerJavaOption(arg);
}
}
return this;
}
/**
* Sets the JVM arguments for the host controller ignoring {@code null} values in the array.
* <p/>
* If the array is {@code null} the host controller JVM arguments are cleared and no new ones are added
*
* @param args the arguments to add
*
* @return the builder
*/
public DomainCommandBuilder setHostControllerJavaOptions(final String... args) {
hostControllerJavaOpts.clear();
return addHostControllerJavaOptions(args);
}
/**
* Sets the JVM arguments for the host controller ignoring {@code null} values in the collection.
* <p/>
* If the collection is {@code null} the host controller JVM arguments are cleared and no new ones are added
*
* @param args the arguments to add
*
* @return the builder
*/
public DomainCommandBuilder setHostControllerJavaOptions(final Iterable<String> args) {
hostControllerJavaOpts.clear();
return addHostControllerJavaOptions(args);
}
/**
* Returns the JVM arguments for the host controller.
*
* @return the JVM arguments
*/
public List<String> getHostControllerJavaOptions() {
return hostControllerJavaOpts.asList();
}
/**
* Adds a JVM argument to the process controller ignoring {@code null} values.
*
* @param arg the argument to add
*
* @return the builder
*/
public DomainCommandBuilder addProcessControllerJavaOption(final String arg) {
if (arg != null && !arg.trim().isEmpty()) {
final Argument argument = Arguments.parse(arg);
if (argument.getKey().equals(SECURITY_MANAGER_PROP)) {
setUseSecurityManager(true);
} else {
processControllerJavaOpts.add(argument);
}
}
return this;
}
/**
* Adds a JVM arguments to the process controller ignoring {@code null} values.
*
* @param args the arguments to add
*
* @return the builder
*/
public DomainCommandBuilder addProcessControllerJavaOptions(final String... args) {
if (args != null) {
for (String arg : args) {
addProcessControllerJavaOption(arg);
}
}
return this;
}
/**
* Adds a JVM arguments to the process controller ignoring {@code null} values.
*
* @param args the arguments to add
*
* @return the builder
*/
public DomainCommandBuilder addProcessControllerJavaOptions(final Iterable<String> args) {
if (args != null) {
for (String arg : args) {
addProcessControllerJavaOption(arg);
}
}
return this;
}
/**
* Sets the JVM arguments for the process controller ignoring {@code null} values in the array.
* <p/>
* If the array is {@code null} the process controller JVM arguments are cleared and no new ones are added
*
* @param args the arguments to add
*
* @return the builder
*/
public DomainCommandBuilder setProcessControllerJavaOptions(final String... args) {
processControllerJavaOpts.clear();
return addProcessControllerJavaOptions(args);
}
/**
* Sets the JVM arguments for the process controller ignoring {@code null} values in the collection.
* <p/>
* If the collection is {@code null} the process controller JVM arguments are cleared and no new ones are added
*
* @param args the arguments to add
*
* @return the builder
*/
public DomainCommandBuilder setProcessControllerJavaOptions(final Iterable<String> args) {
processControllerJavaOpts.clear();
return addProcessControllerJavaOptions(args);
}
/**
* Returns the JVM arguments used for the process controller.
*
* @return the JVM arguments
*/
public List<String> getProcessControllerJavaOptions() {
return processControllerJavaOpts.asList();
}
/**
* Sets the Java home for the servers that are launched in the domain.
* <p/>
* If the {@code javaHome} is not {@code null} then the java executable will be resolved and used to launch the
* servers in the domain. If the {@code javaHome} is {@code null} the same java executable will be used to launch
* the servers in the domain that launched the process controller.
*
* @param javaHome the java home to set, can be {@code null} to use the default
*
* @return the builder
*/
public DomainCommandBuilder setServerJavaHome(final String javaHome) {
if (javaHome == null) {
this.serverJavaHome = null;
} else {
this.serverJavaHome = validateJavaHome(javaHome);
}
return this;
}
/**
* Sets the Java home for the servers that are launched in the domain.
* <p/>
* If the {@code javaHome} is not {@code null} then the java executable will be resolved and used to launch the
* servers in the domain. If the {@code javaHome} is {@code null} the same java executable will be used to launch
* the servers in the domain that launched the process controller.
*
* @param javaHome the java home to set, can be {@code null} to use the default
*
* @return the builder
*/
public DomainCommandBuilder setServerJavaHome(final Path javaHome) {
if (javaHome == null) {
this.serverJavaHome = null;
} else {
this.serverJavaHome = validateJavaHome(javaHome);
}
return this;
}
/**
* Returns the Java home path the servers will use.
* <p/>
* If the path was not previously set the default {@link #getJavaHome() Java home} will be used.
*
* @return the path to the Java home for the servers
*/
public Path getServerJavaHome() {
if (serverJavaHome == null) {
return getJavaHome();
}
return serverJavaHome;
}
@Override
public List<String> buildArguments() {
final List<String> cmd = new ArrayList<>();
// Process Controller
cmd.add("-D[Process Controller]");
addSystemPropertyArg(cmd, HOME_DIR, getWildFlyHome());
// PROCESS_CONTROLLER_JAVA_OPTS
cmd.addAll(processControllerJavaOpts.asList());
cmd.add(getBootLogArgument("process-controller.log"));
cmd.add(getLoggingPropertiesArgument("logging.properties"));
cmd.add("-jar");
cmd.add(getModulesJarName());
if (useSecurityManager()) {
cmd.add(SECURITY_MANAGER_ARG);
}
cmd.add("-mp");
cmd.add(getModulePaths());
cmd.add("org.jboss.as.process-controller");
cmd.add("-jboss-home");
cmd.add(getWildFlyHome().toString());
cmd.add("-jvm");
cmd.add(getHostControllerJavaCommand());
cmd.add("-mp");
cmd.add(getModulePaths());
// Host Controller
cmd.add("--");
cmd.add(getBootLogArgument("host-controller.log"));
cmd.add(getLoggingPropertiesArgument("logging.properties"));
// HOST_CONTROLLER_JAVA_OPTS
cmd.addAll(hostControllerJavaOpts.asList());
cmd.add("--");
cmd.add("-default-jvm");
cmd.add(getServerJavaCommand());
addSystemPropertyArg(cmd, DOMAIN_BASE_DIR, getBaseDirectory());
addSystemPropertyArg(cmd, DOMAIN_LOG_DIR, getLogDirectory());
addSystemPropertyArg(cmd, DOMAIN_CONFIG_DIR, getConfigurationDirectory());
cmd.addAll(getServerArguments());
return cmd;
}
@Override
public List<String> build() {
final List<String> cmd = new ArrayList<>();
cmd.add(getJavaCommand());
cmd.addAll(buildArguments());
return cmd;
}
@Override
public Path getJavaHome() {
return environment.getJavaHome();
}
@Override
public Path getBaseDirectory() {
if (baseDir == null) {
return normalizePath("domain");
}
return baseDir;
}
@Override
protected DomainCommandBuilder getThis() {
return this;
}
private String getHostControllerJavaCommand() {
if (hostControllerJavaHome != null) {
return getJavaCommand(hostControllerJavaHome);
}
return getJavaCommand();
}
private String getServerJavaCommand() {
if (serverJavaHome != null) {
return getJavaCommand(serverJavaHome);
}
return getJavaCommand();
}
}