blob: d444c13e365d98003b2595a10a1c7d62e2d513d6 [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.hop.www;
import com.google.common.annotations.VisibleForTesting;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.vfs2.FileObject;
import org.apache.hop.core.Const;
import org.apache.hop.core.HopClientEnvironment;
import org.apache.hop.core.HopEnvironment;
import org.apache.hop.core.Result;
import org.apache.hop.core.config.plugin.ConfigPlugin;
import org.apache.hop.core.config.plugin.ConfigPluginType;
import org.apache.hop.core.config.plugin.IConfigOptions;
import org.apache.hop.core.encryption.Encr;
import org.apache.hop.core.exception.HopException;
import org.apache.hop.core.extension.ExtensionPointHandler;
import org.apache.hop.core.extension.HopExtensionPoint;
import org.apache.hop.core.logging.ILogChannel;
import org.apache.hop.core.logging.LogChannel;
import org.apache.hop.core.logging.LogLevel;
import org.apache.hop.core.plugins.IPlugin;
import org.apache.hop.core.plugins.JarCache;
import org.apache.hop.core.plugins.PluginRegistry;
import org.apache.hop.core.util.Utils;
import org.apache.hop.core.variables.IVariables;
import org.apache.hop.core.variables.Variables;
import org.apache.hop.core.vfs.HopVfs;
import org.apache.hop.core.xml.XmlHandler;
import org.apache.hop.i18n.BaseMessages;
import org.apache.hop.metadata.api.IHasHopMetadataProvider;
import org.apache.hop.metadata.api.IHopMetadataSerializer;
import org.apache.hop.metadata.serializer.json.JsonMetadataProvider;
import org.apache.hop.metadata.serializer.multi.MultiMetadataProvider;
import org.apache.hop.metadata.util.HopMetadataUtil;
import org.apache.hop.pipeline.transform.TransformStatus;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import picocli.CommandLine;
import picocli.CommandLine.Parameters;
public class HopServer implements Runnable, IHasHopMetadataProvider {
private static final Class<?> PKG = HopServer.class; // For Translator
@Parameters(description = "One XML configuration file or a hostname and port", arity = "0..3")
private List<String> parameters;
@picocli.CommandLine.Option(
names = {"-k", "--kill"},
description =
"Stop the running hopServer server. This is only allowed when using the hostname/port form of the command. Use the -s and -u options to authenticate")
private boolean killServer;
@picocli.CommandLine.Option(
names = {"-p", "--password"},
description =
"The server password. Required for administrative operations only, not for starting the server.")
private String password;
@picocli.CommandLine.Option(
names = {"-u", "--userName"},
description =
"The server user name. Required for administrative operations only, not for starting the server.")
private String username;
@picocli.CommandLine.Option(
names = {"-l", "--level"},
description =
"The debug level, one of NOTHING, ERROR, MINIMAL, BASIC, DETAILED, DEBUG, ROWLEVEL")
private String level;
@CommandLine.Option(
names = {"-s", "--system-properties"},
description = "A comma separated list of KEY=VALUE pairs",
split = ",")
private String[] systemProperties = null;
@CommandLine.Option(
names = {"-gs", "--general-status"},
description = "List the general status of the server")
private boolean generalStatus;
@CommandLine.Option(
names = {"-ps", "--pipeline-status"},
description = "List the status of the pipeline with this name (also specify the -id option)")
private String pipelineName;
@CommandLine.Option(
names = {"-ws", "--workflow-status"},
description = "List the status of the workflow with this name (also specify the -id option)")
private String workflowName;
@CommandLine.Option(
names = {"-id"},
description = "Specify the ID of the pipeline or workflow to query")
private String id;
@CommandLine.Option(
names = {"-n", "--server-name"},
description = "The name of the server to start as defined in the metadata.")
private String serverName;
private WebServer webServer;
private HopServerConfig config;
private boolean allOK;
private IVariables variables;
private picocli.CommandLine cmd;
private ILogChannel log;
private MultiMetadataProvider metadataProvider;
private Boolean joinOverride;
private String realFilename;
public HopServer() {
this.config = new HopServerConfig();
this.joinOverride = null;
org.apache.hop.server.HopServer defaultServer =
new org.apache.hop.server.HopServer(
"local8080", "localhost", "8080", "8079", "cluster", "cluster");
this.config.setHopServer(defaultServer);
this.config.setJoining(true);
}
public void runHopServer() throws Exception {
allOK = true;
HopServerSingleton.setHopServerConfig(config);
log = HopServerSingleton.getInstance().getLog();
final PipelineMap pipelineMap = HopServerSingleton.getInstance().getPipelineMap();
pipelineMap.setHopServerConfig(config);
final WorkflowMap workflowMap = HopServerSingleton.getInstance().getWorkflowMap();
workflowMap.setHopServerConfig(config);
org.apache.hop.server.HopServer hopServer = config.getHopServer();
String hostname = hopServer.getHostname();
int port = WebServer.PORT;
int shutdownPort = WebServer.SHUTDOWN_PORT;
if (!Utils.isEmpty(hopServer.getPort())) {
port = parsePort(hopServer);
}
if (!Utils.isEmpty(hopServer.getShutdownPort())) {
shutdownPort = parseShutdownPort(hopServer);
}
if (allOK) {
boolean shouldJoin = config.isJoining();
if (joinOverride != null) {
shouldJoin = joinOverride;
}
this.webServer =
new WebServer(
log,
pipelineMap,
workflowMap,
hostname,
port,
shutdownPort,
shouldJoin,
config.getPasswordFile(),
hopServer.getSslConfig());
}
ExtensionPointHandler.callExtensionPoint(
log, variables, HopExtensionPoint.HopServerShutdown.id, this);
}
private int parsePort(org.apache.hop.server.HopServer hopServer) {
try {
return Integer.parseInt(hopServer.getPort());
} catch (Exception e) {
log.logError(
BaseMessages.getString(
PKG,
"HopServer.Error.CanNotPartPort",
hopServer.getHostname(),
"" + hopServer.getPort()),
e);
allOK = false;
}
return -1;
}
private int parseShutdownPort(org.apache.hop.server.HopServer hopServer) {
try {
return Integer.parseInt(hopServer.getShutdownPort());
} catch (Exception e) {
log.logError(
BaseMessages.getString(
PKG, "HopServer.Error.CanNotPartShutdownPort", hopServer.getShutdownPort()),
e);
allOK = false;
}
return -1;
}
@Override
public void run() {
try {
log = new LogChannel("HopServer");
log.setLogLevel(determineLogLevel());
log.logDetailed("Start of Hop Server");
// Allow plugins to modify the elements loaded so far, before the server is started
//
ExtensionPointHandler.callExtensionPoint(
log, variables, HopExtensionPoint.HopServerInit.id, this);
// Handle the options of the configuration plugins
//
Map<String, Object> mixins = cmd.getMixins();
for (String key : mixins.keySet()) {
Object mixin = mixins.get(key);
if (mixin instanceof IConfigOptions) {
IConfigOptions configOptions = (IConfigOptions) mixin;
configOptions.handleOption(log, this, variables);
}
}
// If the server name was specified we make it look like 2 parameters were specified
//
if (CollectionUtils.isEmpty(parameters)) {
if (StringUtils.isNotEmpty(serverName)) {
setupByServerName();
}
}
// Build the server configuration from the options...
//
// Load from an XML file that describes the complete configuration...
//
if (CollectionUtils.size(parameters) == 1) {
if (killServer) {
throw new HopServerCommandException(
BaseMessages.getString(PKG, "HopServer.Error.illegalStop"));
}
setupByFileName();
}
if ((CollectionUtils.size(parameters) == 2 || (CollectionUtils.size(parameters) == 3))
&& StringUtils.isNotEmpty(parameters.get(0))
&& StringUtils.isNotEmpty(parameters.get(1))) {
String hostname = parameters.get(0);
String port = parameters.get(1);
String shutdownPort =
CollectionUtils.size(parameters) == 3
? parameters.get(2)
: Integer.toString(WebServer.SHUTDOWN_PORT);
if (killServer) {
String user = variables.resolve(username);
String pwd = variables.resolve(this.password);
shutdown(hostname, port, shutdownPort, user, pwd);
System.exit(0);
}
setupByHostNameAndPort(hostname, port, shutdownPort);
}
// Pass the variables and metadata provider
//
config.setVariables(variables);
config.setMetadataProvider(metadataProvider);
// See if we need to add the metadata folder (legacy)
//
addMetadataFolderProvider();
// Only query?
//
if (handleQueryOptions()) {
System.exit(0);
}
// At long last, run the actual server...
//
runHopServer();
} catch (Exception e) {
throw new picocli.CommandLine.ExecutionException(
cmd, "There was an error during the startup of the Hop server", e);
}
}
private void setupByHostNameAndPort(String hostname, String port, String shutdownPort) {
org.apache.hop.server.HopServer hopServer =
new org.apache.hop.server.HopServer(
hostname + ":" + port, hostname, port, shutdownPort, null, null);
config = new HopServerConfig();
config.setHopServer(hopServer);
config.setJoining(true);
}
private void setupByFileName() throws HopException {
// Calculate the filename, allow plugins to intervene...
//
calculateRealFilename();
FileObject file = HopVfs.getFileObject(realFilename);
Document document = XmlHandler.loadXmlFile(file);
Node configNode = XmlHandler.getSubNode(document, HopServerConfig.XML_TAG);
config = new HopServerConfig(new LogChannel("Hop server config"), configNode);
config.setFilename(parameters.get(0));
}
private void setupByServerName() throws HopException {
IHopMetadataSerializer<org.apache.hop.server.HopServer> serializer =
metadataProvider.getSerializer(org.apache.hop.server.HopServer.class);
String name = variables.resolve(serverName);
org.apache.hop.server.HopServer hopServer = serializer.load(name);
if (hopServer == null) {
throw new HopException(
"Unable to find Hop Server '" + name + "' couldn't be found in the server metadata");
}
String hostname = variables.resolve(hopServer.getHostname());
String port = variables.resolve(hopServer.getPort());
String shutDownPort = variables.resolve(hopServer.getShutdownPort());
parameters = List.of(Const.NVL(hostname, ""), Const.NVL(port, ""), Const.NVL(shutDownPort, ""));
}
private boolean handleQueryOptions() {
boolean queried = false;
try {
// Handle username / password
//
if (generalStatus
|| StringUtils.isNotEmpty(pipelineName)
|| StringUtils.isNotEmpty(workflowName)) {
if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
throw new HopException(
"Please specify the username and password to query the server status");
}
config.getHopServer().setUsername(variables.resolve(username));
config.getHopServer().setPassword(variables.resolve(password));
}
if (generalStatus) {
queried = true;
HopServerStatus status = config.getHopServer().getStatus(variables);
// List the pipelines...
//
System.out.println("Pipelines: " + status.getPipelineStatusList().size() + " found.");
for (HopServerPipelineStatus pipelineStatus : status.getPipelineStatusList()) {
printPipelineStatus(pipelineStatus, false);
}
System.out.println();
// List the workflows...
//
System.out.println("Workflows: " + status.getWorkflowStatusList().size() + " found.");
for (HopServerWorkflowStatus workflowStatus : status.getWorkflowStatusList()) {
printWorkflowStatus(workflowStatus, false);
}
} else if (StringUtils.isNotEmpty(pipelineName)) {
queried = true;
if (StringUtils.isEmpty(id)) {
throw new HopException(
"Please specify the ID of the pipeline execution to see its status.");
}
HopServerPipelineStatus pipelineStatus =
config.getHopServer().getPipelineStatus(variables, pipelineName, id, 0);
printPipelineStatus(pipelineStatus, true);
} else if (StringUtils.isNotEmpty(workflowName)) {
queried = true;
if (StringUtils.isEmpty(id)) {
throw new HopException(
"Please specify the ID of the workflow execution to see its status.");
}
HopServerWorkflowStatus workflowStatus =
config.getHopServer().getWorkflowStatus(variables, workflowName, id, 0);
printWorkflowStatus(workflowStatus, true);
}
} catch (Exception e) {
log.logError("Error querying server", e);
System.exit(8);
}
return queried;
}
private void printPipelineStatus(HopServerPipelineStatus pipelineStatus, boolean printDetails) {
Result result = pipelineStatus.getResult();
System.out.println(" ID: " + pipelineStatus.getId());
System.out.println(" Name: " + pipelineStatus.getPipelineName());
System.out.println(" Status: " + pipelineStatus.getStatusDescription());
System.out.println(" Start: " + formatDate(pipelineStatus.getExecutionStartDate()));
System.out.println(" End: " + formatDate(pipelineStatus.getExecutionEndDate()));
System.out.println(" Log date: " + formatDate(pipelineStatus.getLogDate()));
if (result != null) {
System.out.println(" Errors: " + result.getNrErrors());
}
if (printDetails) {
// Print logging & transform metrics
//
System.out.println(
" Transforms: " + pipelineStatus.getTransformStatusList().size() + " found.");
int nr = 1;
for (TransformStatus transformStatus : pipelineStatus.getTransformStatusList()) {
System.out.println(" " + nr++);
System.out.println(" Name: " + transformStatus.getTransformName());
System.out.println(" Copy: " + transformStatus.getCopy());
System.out.println(" Status: " + transformStatus.getStatusDescription());
System.out.println(" Input: " + transformStatus.getLinesInput());
System.out.println(" Output: " + transformStatus.getLinesOutput());
System.out.println(" Read: " + transformStatus.getLinesRead());
System.out.println(" Written: " + transformStatus.getLinesWritten());
System.out.println(" Rejected: " + transformStatus.getLinesRejected());
System.out.println(" Updated: " + transformStatus.getLinesUpdated());
System.out.println(" Errors: " + transformStatus.getErrors());
}
printLoggingString(pipelineStatus.getLoggingString());
}
}
private void printLoggingString(String loggingString) {
if (StringUtils.isEmpty(loggingString)) {
return;
}
System.out.println(" Logging: ");
String[] lines = loggingString.split("\n");
for (String line : lines) {
System.out.println(" " + line);
}
}
private void printWorkflowStatus(HopServerWorkflowStatus workflowStatus, boolean printDetails) {
Result result = workflowStatus.getResult();
System.out.println(" ID: " + workflowStatus.getId());
System.out.println(" Name: " + workflowStatus.getWorkflowName());
System.out.println(" Status: " + workflowStatus.getStatusDescription());
System.out.println(" Log date: " + formatDate(workflowStatus.getLogDate()));
if (result != null) {
System.out.println(" Result: " + result.getResult());
System.out.println(" Errors: " + result.getNrErrors());
}
if (printDetails) {
printLoggingString(workflowStatus.getLoggingString());
}
}
private String formatDate(Date date) {
if (date == null) {
return "-";
}
return XmlHandler.date2string(date);
}
/**
* This way we can actually use environment variables to parse the real filename. We also allow
* plugins to look for the filename. In our case, relative to a project folder for example.
*/
private void calculateRealFilename() throws HopException {
realFilename = variables.resolve(parameters.get(0));
ExtensionPointHandler.callExtensionPoint(
log, variables, HopExtensionPoint.HopServerCalculateFilename.id, this);
}
private LogLevel determineLogLevel() {
return LogLevel.getLogLevelForCode(variables.resolve(level));
}
public void applySystemProperties() {
// Set some System properties if there were any
//
if (systemProperties != null) {
for (String parameter : systemProperties) {
String[] split = parameter.split("=");
String key = split.length > 0 ? split[0] : null;
String value = split.length > 1 ? split[1] : null;
if (StringUtils.isNotEmpty(key) && StringUtils.isNotEmpty(value)) {
System.setProperty(key, value);
}
}
}
}
private void buildVariableSpace() {
// Also grabs the system properties from hop.config.
//
variables = Variables.getADefaultVariableSpace();
}
public static void main(String[] args) {
String[] arguments =
Stream.of(args)
.flatMap(a -> Stream.of(a.split("(?=--)")))
.filter(a -> !a.isEmpty())
.toArray(String[]::new);
HopServer hopServer = new HopServer();
try {
// Create the command line options...
//
picocli.CommandLine cmd = new picocli.CommandLine(hopServer);
// Apply the system properties to the JVM
//
hopServer.applySystemProperties();
// Initialize the Hop environment: load plugins and more
//
HopClientEnvironment.getInstance().setClient(HopClientEnvironment.ClientType.SERVER);
HopEnvironment.init();
// Picks up the system settings in the variables
//
hopServer.buildVariableSpace();
// Clear the jar file cache so that we don't waste memory...
//
JarCache.getInstance().clear();
// Set up the metadata to use
//
hopServer.metadataProvider =
HopMetadataUtil.getStandardHopMetadataProvider(hopServer.variables);
// Now add server configuration plugins...
//
List<IPlugin> configPlugins = PluginRegistry.getInstance().getPlugins(ConfigPluginType.class);
for (IPlugin configPlugin : configPlugins) {
// Load only the plugins of the "run" category
if (ConfigPlugin.CATEGORY_SERVER.equals(configPlugin.getCategory())) {
IConfigOptions configOptions =
PluginRegistry.getInstance().loadClass(configPlugin, IConfigOptions.class);
cmd.addMixin(configPlugin.getIds()[0], configOptions);
}
}
hopServer.setCmd(cmd);
// Add optional metadata folder (legacy)
//
hopServer.addMetadataFolderProvider();
// This will calculate the option values and put them in HopRun or the plugin classes
//
picocli.CommandLine.ParseResult parseResult = cmd.parseArgs(arguments);
if (picocli.CommandLine.printHelpIfRequested(parseResult)) {
printExtraUsageExamples();
System.exit(1);
} else {
hopServer.run();
// If we exit now it's because the server was stopped and this is not an error
//
System.exit(0);
}
} catch (picocli.CommandLine.ParameterException e) {
System.err.println(e.getMessage());
hopServer.cmd.usage(System.err);
printExtraUsageExamples();
System.exit(9);
} catch (picocli.CommandLine.ExecutionException e) {
System.err.println("Error found during execution!");
System.err.println(Const.getStackTracker(e));
System.exit(1);
} catch (Exception e) {
System.err.println("General error found, something went horribly wrong!");
System.err.println(Const.getStackTracker(e));
System.exit(2);
}
}
private void addMetadataFolderProvider() {
// Do we need to add one more provider for the metadata map?
String metadataFolder = config.getMetadataFolder();
if (StringUtils.isNotEmpty(metadataFolder)) {
// Get the metadata from the specified metadata folder...
//
metadataProvider
.getProviders()
.add(new JsonMetadataProvider(Encr.getEncoder(), metadataFolder, variables));
}
}
private static void printExtraUsageExamples() {
System.err.println();
System.err.println(
BaseMessages.getString(PKG, "HopServer.Usage.Example") + ": hop-server.sh 0.0.0.0 8080");
System.err.println(
BaseMessages.getString(PKG, "HopServer.Usage.Example")
+ ": hop-server.sh 192.168.1.221 8081 8082");
System.err.println();
System.err.println(
BaseMessages.getString(PKG, "HopServer.Usage.Example")
+ ": hop-server.sh -e aura-gcp gs://apachehop/hop-server-config.xml");
System.err.println(
BaseMessages.getString(PKG, "HopServer.Usage.Example")
+ ": hop-server.sh 127.0.0.1 8080 --kill --userName cluster --password cluster");
}
/**
* @return the webServer
*/
public WebServer getWebServer() {
return webServer;
}
/**
* @param webServer the webServer to set
*/
public void setWebServer(WebServer webServer) {
this.webServer = webServer;
}
/**
* @return the hop server (HopServer) configuration
*/
public HopServerConfig getConfig() {
return config;
}
/**
* @param config the hop server (HopServer) configuration
*/
public void setConfig(HopServerConfig config) {
this.config = config;
}
private static void shutdown(
String hostname, String port, String shutdownPort, String username, String password) {
try {
callStopHopServerRestService(hostname, port, shutdownPort, username, password);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Checks that HopServer is running and if so, shuts down the HopServer server
*
* @param hostname
* @param port
* @param username
* @param password
* @throws HopServerCommandException
*/
@VisibleForTesting
static void callStopHopServerRestService(
String hostname, String port, String shutdownPort, String username, String password)
throws HopServerCommandException {
// get information about the remote connection
try {
HopClientEnvironment.init();
HttpAuthenticationFeature authFeature =
HttpAuthenticationFeature.basicBuilder()
.credentials(username, Encr.decryptPasswordOptionallyEncrypted(password))
.build();
ClientConfig clientConfig = new ClientConfig();
Client client = ClientBuilder.newClient(clientConfig);
client.register(authFeature);
// check if the user can access the hop server. Don't really need this call but may want to
// check it's output at
// some point
String contextURL = "http://" + hostname + ":" + port + "/hop";
WebTarget target = client.target(contextURL + "/status/?xml=Y");
String response = target.request().get(String.class);
if (response == null || !response.contains("<serverstatus>")) {
throw new HopServerCommandException(
BaseMessages.getString(PKG, "HopServer.Error.NoServerFound", hostname, "" + port));
}
Socket s = new Socket(InetAddress.getByName(hostname), Integer.parseInt(shutdownPort));
OutputStream out = s.getOutputStream();
out.write(("\r\n").getBytes());
out.flush();
s.close();
} catch (Exception e) {
throw new HopServerCommandException(
BaseMessages.getString(PKG, "HopServer.Error.NoServerFound", hostname, "" + port), e);
}
}
/** Exception generated when command line fails */
public static class HopServerCommandException extends Exception {
private static final long serialVersionUID = 1L;
public HopServerCommandException(final String message) {
super(message);
}
public HopServerCommandException(final String message, final Throwable cause) {
super(message, cause);
}
}
/**
* Gets parameters
*
* @return value of parameters
*/
public List<String> getParameters() {
return parameters;
}
/**
* @param parameters The parameters to set
*/
public void setParameters(List<String> parameters) {
this.parameters = parameters;
}
/**
* Gets systemProperties
*
* @return value of systemProperties
*/
public String[] getSystemProperties() {
return systemProperties;
}
/**
* @param systemProperties The systemProperties to set
*/
public void setSystemProperties(String[] systemProperties) {
this.systemProperties = systemProperties;
}
/**
* Gets stopServer
*
* @return value of stopServer
*/
public boolean isKillServer() {
return killServer;
}
/**
* @param killServer The stopServer to set
*/
public void setKillServer(boolean killServer) {
this.killServer = killServer;
}
/**
* Gets stopPassword
*
* @return value of stopPassword
*/
public String getPassword() {
return password;
}
/**
* @param password The stopPassword to set
*/
public void setPassword(String password) {
this.password = password;
}
/**
* Gets stopUsername
*
* @return value of stopUsername
*/
public String getUsername() {
return username;
}
/**
* @param username The stopUsername to set
*/
public void setUsername(String username) {
this.username = username;
}
/**
* Gets level
*
* @return value of level
*/
public String getLevel() {
return level;
}
/**
* @param level The level to set
*/
public void setLevel(String level) {
this.level = level;
}
/**
* Gets allOK
*
* @return value of allOK
*/
public boolean isAllOK() {
return allOK;
}
/**
* @param allOK The allOK to set
*/
public void setAllOK(boolean allOK) {
this.allOK = allOK;
}
/**
* Gets variables
*
* @return value of variables
*/
public IVariables getVariables() {
return variables;
}
/**
* @param variables The variables to set
*/
public void setVariables(IVariables variables) {
this.variables = variables;
}
/**
* Gets cmd
*
* @return value of cmd
*/
public CommandLine getCmd() {
return cmd;
}
/**
* @param cmd The cmd to set
*/
public void setCmd(CommandLine cmd) {
this.cmd = cmd;
}
/**
* Gets log
*
* @return value of log
*/
public ILogChannel getLog() {
return log;
}
/**
* @param log The log to set
*/
public void setLog(ILogChannel log) {
this.log = log;
}
/**
* Gets metadataProvider
*
* @return value of metadataProvider
*/
@Override
public MultiMetadataProvider getMetadataProvider() {
return metadataProvider;
}
/**
* @param metadataProvider The metadataProvider to set
*/
public void setMetadataProvider(MultiMetadataProvider metadataProvider) {
this.metadataProvider = metadataProvider;
}
/**
* Gets joinOverride
*
* @return value of joinOverride
*/
public Boolean getJoinOverride() {
return joinOverride;
}
/**
* @param joinOverride The joinOverride to set
*/
public void setJoinOverride(Boolean joinOverride) {
this.joinOverride = joinOverride;
}
/**
* Gets realFilename
*
* @return value of realFilename
*/
public String getRealFilename() {
return realFilename;
}
/**
* @param realFilename The realFilename to set
*/
public void setRealFilename(String realFilename) {
this.realFilename = realFilename;
}
}