diff --git a/.gitignore b/.gitignore index f026df6c81..6d4eca990c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ target .project .settings +.classpath nbactions.xml .DS_Store diff --git a/nifi-bootstrap/pom.xml b/nifi-bootstrap/pom.xml new file mode 100644 index 0000000000..b620c84a78 --- /dev/null +++ b/nifi-bootstrap/pom.xml @@ -0,0 +1,18 @@ + + 4.0.0 + + + org.apache.nifi + nifi-parent + 0.0.1-SNAPSHOT + + + nifi-bootstrap + jar + + nifi-bootstrap + + + + diff --git a/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/RunNiFi.java b/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/RunNiFi.java new file mode 100644 index 0000000000..afa1f4713e --- /dev/null +++ b/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/RunNiFi.java @@ -0,0 +1,176 @@ +package org.apache.nifi.bootstrap; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FilenameFilter; +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + + +/** + * Bootstrap class to run Apache NiFi. + * + * This class looks for the bootstrap.conf file by looking in the following places (in order): + *
    + *
  1. First argument to the program
  2. + *
  3. Java System Property named {@code org.apache.nifi.bootstrap.config.file}
  4. + *
  5. ${NIFI_HOME}/./conf/bootstrap.conf, where ${NIFI_HOME} references an environment variable {@code NIFI_HOME}
  6. + *
  7. ./conf/bootstrap.conf, where {@code .} represents the working directory. + *
+ * + * If the {@code bootstrap.conf} file cannot be found, throws a {@code FileNotFoundException]. + */ +public class RunNiFi { + public static final String DEFAULT_CONFIG_FILE = "./conf/boostrap.conf"; + public static final String DEFAULT_NIFI_PROPS_FILE = "./conf/nifi.properties"; + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public static void main(final String[] args) throws IOException, InterruptedException { + final ProcessBuilder builder = new ProcessBuilder(); + + String configFilename = (args.length > 0) ? args[0] : System.getProperty("org.apache.nifi.boostrap.config.file"); + + if ( configFilename == null ) { + final String nifiHome = System.getenv("NIFI_HOME"); + if ( nifiHome != null ) { + final File nifiHomeFile = new File(nifiHome.trim()); + final File configFile = new File(nifiHomeFile, DEFAULT_CONFIG_FILE); + configFilename = configFile.getAbsolutePath(); + } + } + + if ( configFilename == null ) { + configFilename = DEFAULT_CONFIG_FILE; + } + + final File configFile = new File(configFilename); + if ( !configFile.exists() ) { + throw new FileNotFoundException(DEFAULT_CONFIG_FILE); + } + + final Properties properties = new Properties(); + try (final FileInputStream fis = new FileInputStream(configFile)) { + properties.load(fis); + } + + final Map props = new HashMap<>(); + props.putAll( (Map) properties ); + + final String specifiedWorkingDir = props.get("working.dir"); + if ( specifiedWorkingDir != null ) { + builder.directory(new File(specifiedWorkingDir)); + } + + final File workingDir = builder.directory(); + + final String libFilename = replaceNull(props.get("lib.dir"), "./lib").trim(); + File libDir = getFile(libFilename, workingDir); + + final String confFilename = replaceNull(props.get("conf.dir"), "./conf").trim(); + File confDir = getFile(confFilename, workingDir); + + String nifiPropsFilename = props.get("props.file"); + if ( nifiPropsFilename == null ) { + if ( confDir.exists() ) { + nifiPropsFilename = new File(confDir, "nifi.properties").getAbsolutePath(); + } else { + nifiPropsFilename = DEFAULT_CONFIG_FILE; + } + } + + nifiPropsFilename = nifiPropsFilename.trim(); + + final List javaAdditionalArgs = new ArrayList<>(); + for ( final Map.Entry entry : props.entrySet() ) { + final String key = entry.getKey(); + final String value = entry.getValue(); + + if ( key.startsWith("java.arg") ) { + javaAdditionalArgs.add(value); + } + } + + final File[] libFiles = libDir.listFiles(new FilenameFilter() { + @Override + public boolean accept(final File dir, final String filename) { + return filename.toLowerCase().endsWith(".jar"); + } + }); + + if ( libFiles == null || libFiles.length == 0 ) { + throw new RuntimeException("Could not find lib directory at " + libDir.getAbsolutePath()); + } + + final File[] confFiles = confDir.listFiles(); + if ( confFiles == null || confFiles.length == 0 ) { + throw new RuntimeException("Could not find conf directory at " + confDir.getAbsolutePath()); + } + + final Path workingDirPath = workingDir.toPath(); + final List cpFiles = new ArrayList<>(confFiles.length + libFiles.length); + cpFiles.add(confDir.getAbsolutePath()); + for ( final File file : libFiles ) { + final Path path = workingDirPath.relativize(file.toPath()); + final String cpPath = path.toString(); + cpFiles.add(cpPath); + } + + final StringBuilder classPathBuilder = new StringBuilder(); + for (int i=0; i < cpFiles.size(); i++) { + final String filename = cpFiles.get(i); + classPathBuilder.append(filename); + if ( i < cpFiles.size() - 1 ) { + classPathBuilder.append(File.pathSeparatorChar); + } + } + + final String classPath = classPathBuilder.toString(); + String javaCmd = props.get("java"); + if ( javaCmd == null ) { + javaCmd = "java"; + } + + final List cmd = new ArrayList<>(); + cmd.add(javaCmd); + cmd.add("-classpath"); + cmd.add(classPath); + cmd.addAll(javaAdditionalArgs); + cmd.add("-Dnifi.properties.file.path=" + nifiPropsFilename); + cmd.add("org.apache.nifi.NiFi"); + + builder.command(cmd).inheritIO(); + + final StringBuilder cmdBuilder = new StringBuilder(); + for ( final String s : cmd ) { + cmdBuilder.append(s).append(" "); + } + System.out.println("Starting Apache NiFi..."); + System.out.println("Working Directory: " + workingDir.getAbsolutePath()); + System.out.println("Command: " + cmdBuilder.toString()); + + final Process proc = builder.start(); + Runtime.getRuntime().addShutdownHook(new ShutdownHook(proc)); + final int statusCode = proc.waitFor(); + System.out.println("Apache NiFi exited with Status Code " + statusCode); + } + + + private static File getFile(final String filename, final File workingDir) { + File libDir = new File(filename); + if ( !libDir.isAbsolute() ) { + libDir = new File(workingDir, filename); + } + + return libDir; + } + + private static String replaceNull(final String value, final String replacement) { + return (value == null) ? replacement : value; + } +} diff --git a/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/ShutdownHook.java b/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/ShutdownHook.java new file mode 100644 index 0000000000..55e1f457d2 --- /dev/null +++ b/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/ShutdownHook.java @@ -0,0 +1,14 @@ +package org.apache.nifi.bootstrap; + +public class ShutdownHook extends Thread { + private final Process nifiProcess; + + public ShutdownHook(final Process nifiProcess) { + this.nifiProcess = nifiProcess; + } + + @Override + public void run() { + nifiProcess.destroy(); + } +}