Fixes #914 Allow passing config to oracle/worker cmds (#916)

* This work was done to support running Fluo in Docker
* Fluo commands now support '-D key=value' arguments to override configuration.
* Refactored command-line options to use jcommander and inheritance
* Started passing fluo-conn.properties using Java system property
* Fixed bug in Fluo status command
* Updated oracle/worker commands. Processes are no longer treated like services.
* Log4j.properties defaults to console
diff --git a/docs/applications.md b/docs/applications.md
index 7d8557a..cc2001b 100644
--- a/docs/applications.md
+++ b/docs/applications.md
@@ -204,15 +204,13 @@
    are typically run with one oracle process and multiple worker processes. The commands below will start
    a Fluo oracle and two workers on your local machine:
 
-        fluo oracle myapp
-        fluo worker myapp
-        fluo worker myapp
+        fluo oracle myapp &> oracle.log &
+        fluo worker myapp &> worker1.log &
+        fluo worker myapp &> worker2.log &
 
    The commands will retrieve your application configuration and observer jars (using your
    application name) before starting the oracle or worker process.
 
-The oracle & worker logs can be found in the directory `logs/<applicationName>` of your Fluo installation.
-
 If you want to distribute the processes of your Fluo application across a cluster, you will need install
 Fluo on every node where you want to run a Fluo process and follow the instructions above on each node.
 
diff --git a/modules/command/src/main/java/org/apache/fluo/command/BaseOpts.java b/modules/command/src/main/java/org/apache/fluo/command/BaseOpts.java
new file mode 100644
index 0000000..c700afe
--- /dev/null
+++ b/modules/command/src/main/java/org/apache/fluo/command/BaseOpts.java
@@ -0,0 +1,43 @@
+/*
+ * 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.fluo.command;
+
+import com.beust.jcommander.JCommander;
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.ParameterException;
+
+public class BaseOpts {
+
+  @Parameter(names = {"-h", "-help", "--help"}, help = true, description = "Prints help")
+  boolean help;
+
+  public static void parse(String programName, BaseOpts opts, String[] args) {
+    JCommander jcommand = new JCommander(opts);
+    jcommand.setProgramName(programName);
+    try {
+      jcommand.parse(args);
+    } catch (ParameterException e) {
+      System.err.println(e.getMessage());
+      jcommand.usage();
+      System.exit(-1);
+    }
+
+    if (opts.help) {
+      jcommand.usage();
+      System.exit(1);
+    }
+  }
+}
diff --git a/modules/command/src/main/java/org/apache/fluo/command/CommandUtil.java b/modules/command/src/main/java/org/apache/fluo/command/CommandUtil.java
index 2f2ba83..ee839f4 100644
--- a/modules/command/src/main/java/org/apache/fluo/command/CommandUtil.java
+++ b/modules/command/src/main/java/org/apache/fluo/command/CommandUtil.java
@@ -15,11 +15,11 @@
 
 package org.apache.fluo.command;
 
-import org.apache.curator.framework.CuratorFramework;
-import org.apache.fluo.api.client.FluoAdmin;
+import java.io.File;
+
+import com.google.common.base.Preconditions;
 import org.apache.fluo.api.config.FluoConfiguration;
 import org.apache.fluo.core.client.FluoAdminImpl;
-import org.apache.fluo.core.util.CuratorUtil;
 
 public class CommandUtil {
 
@@ -34,11 +34,23 @@
   public static void verifyAppRunning(FluoConfiguration config) {
     verifyAppInitialized(config);
     try (FluoAdminImpl admin = new FluoAdminImpl(config)) {
-      if (admin.applicationRunning()) {
+      if (!admin.applicationRunning()) {
         System.out.println("A Fluo '" + config.getApplicationName()
-            + "' application is initialized " + "but is not running!");
+            + "' application is initialized but is not running!");
         System.exit(-1);
       }
     }
   }
+
+  public static FluoConfiguration resolveFluoConfig() {
+    String connPropsPath = System.getProperty("fluo.conn.props");
+    if (connPropsPath == null) {
+      return new FluoConfiguration();
+    } else {
+      File connPropsFile = new File(connPropsPath);
+      Preconditions.checkArgument(connPropsFile.exists(),
+          "System property 'fluo.conn.props' is set to file that doesn't exist: " + connPropsPath);
+      return new FluoConfiguration(connPropsFile);
+    }
+  }
 }
diff --git a/modules/command/src/main/java/org/apache/fluo/command/CommonOpts.java b/modules/command/src/main/java/org/apache/fluo/command/CommonOpts.java
new file mode 100644
index 0000000..004c2ae
--- /dev/null
+++ b/modules/command/src/main/java/org/apache/fluo/command/CommonOpts.java
@@ -0,0 +1,34 @@
+/*
+ * 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.fluo.command;
+
+import com.beust.jcommander.Parameter;
+
+class CommonOpts extends ConfigOpts {
+
+  @Parameter(names = "-a", required = true, description = "Fluo application name")
+  private String applicationName;
+
+  String getApplicationName() {
+    return applicationName;
+  }
+
+  public static CommonOpts parse(String programName, String[] args) {
+    CommonOpts opts = new CommonOpts();
+    parse(programName, opts, args);
+    return opts;
+  }
+}
diff --git a/modules/command/src/main/java/org/apache/fluo/command/ConfigOpts.java b/modules/command/src/main/java/org/apache/fluo/command/ConfigOpts.java
new file mode 100644
index 0000000..5101a02
--- /dev/null
+++ b/modules/command/src/main/java/org/apache/fluo/command/ConfigOpts.java
@@ -0,0 +1,56 @@
+/*
+ * 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.fluo.command;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.beust.jcommander.Parameter;
+import org.apache.fluo.api.config.FluoConfiguration;
+
+public class ConfigOpts extends BaseOpts {
+
+  @Parameter(names = "-D",
+      description = "Sets configuration property. Expected format: <name>=<value>")
+  private List<String> properties = new ArrayList<>();
+
+  List<String> getProperties() {
+    return properties;
+  }
+
+  void overrideFluoConfig(FluoConfiguration config) {
+    for (String prop : getProperties()) {
+      String[] propArgs = prop.split("=", 2);
+      if (propArgs.length == 2) {
+        String key = propArgs[0].trim();
+        String value = propArgs[1].trim();
+        if (key.isEmpty() || value.isEmpty()) {
+          throw new IllegalArgumentException("Invalid command line -D option: " + prop);
+        } else {
+          config.setProperty(key, value);
+        }
+      } else {
+        throw new IllegalArgumentException("Invalid command line -D option: " + prop);
+      }
+    }
+  }
+
+  public static ConfigOpts parse(String programName, String[] args) {
+    ConfigOpts opts = new ConfigOpts();
+    parse(programName, opts, args);
+    return opts;
+  }
+}
diff --git a/modules/command/src/main/java/org/apache/fluo/command/FluoConfig.java b/modules/command/src/main/java/org/apache/fluo/command/FluoConfig.java
index 3c0b02d..467b928 100644
--- a/modules/command/src/main/java/org/apache/fluo/command/FluoConfig.java
+++ b/modules/command/src/main/java/org/apache/fluo/command/FluoConfig.java
@@ -15,45 +15,20 @@
 
 package org.apache.fluo.command;
 
-import java.io.File;
-import java.net.URI;
 import java.util.Map;
-import java.util.Objects;
 
-import com.google.common.base.Preconditions;
-import org.apache.commons.io.FileUtils;
 import org.apache.fluo.api.client.FluoAdmin;
 import org.apache.fluo.api.client.FluoFactory;
 import org.apache.fluo.api.config.FluoConfiguration;
-import org.apache.fluo.api.config.SimpleConfiguration;
-import org.apache.fluo.core.client.FluoAdminImpl;
-import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.fs.FileSystem;
-import org.apache.hadoop.fs.Path;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 public class FluoConfig {
 
-  private static final Logger log = LoggerFactory.getLogger(FluoConfig.class);
-
   public static void main(String[] args) {
-    if (args.length != 2) {
-      System.err.println("Usage: FluoConfig <connectionPropsPath> <applicationName>");
-      System.exit(-1);
-    }
-    String connectionPropsPath = args[0];
-    String applicationName = args[1];
-    Objects.requireNonNull(connectionPropsPath);
-    Objects.requireNonNull(applicationName);
-    File connectionPropsFile = new File(connectionPropsPath);
-    Preconditions.checkArgument(connectionPropsFile.exists(), connectionPropsPath
-        + " does not exist");
-
-    FluoConfiguration config = new FluoConfiguration(connectionPropsFile);
-    config.setApplicationName(applicationName);
+    CommonOpts opts = CommonOpts.parse("fluo config", args);
+    FluoConfiguration config = CommandUtil.resolveFluoConfig();
+    config.setApplicationName(opts.getApplicationName());
+    opts.overrideFluoConfig(config);
     CommandUtil.verifyAppInitialized(config);
-
     try (FluoAdmin admin = FluoFactory.newAdmin(config)) {
       for (Map.Entry<String, String> entry : admin.getApplicationConfig().toMap().entrySet()) {
         System.out.println(entry.getKey() + " = " + entry.getValue());
diff --git a/modules/command/src/main/java/org/apache/fluo/command/FluoExec.java b/modules/command/src/main/java/org/apache/fluo/command/FluoExec.java
index 61c04a2..22bb407 100644
--- a/modules/command/src/main/java/org/apache/fluo/command/FluoExec.java
+++ b/modules/command/src/main/java/org/apache/fluo/command/FluoExec.java
@@ -15,14 +15,11 @@
 
 package org.apache.fluo.command;
 
-import java.io.File;
 import java.lang.reflect.Method;
 import java.util.Arrays;
-import java.util.Objects;
 
 import javax.inject.Provider;
 
-import com.google.common.base.Preconditions;
 import com.google.inject.AbstractModule;
 import com.google.inject.Guice;
 import org.apache.fluo.api.config.FluoConfiguration;
@@ -48,19 +45,14 @@
   }
 
   public static void main(String[] args) throws Exception {
-    if (args.length < 3) {
-      System.err.println("Usage: FluoExec <connectionPropsPath> <applicationName> <class> args...");
+    if (args.length < 2) {
+      System.err.println("Usage: fluo exec <app> <class> args...");
       System.exit(-1);
     }
-    final String connectionPropsPath = args[0];
-    final String applicationName = args[1];
-    final String className = args[2];
-    Objects.requireNonNull(connectionPropsPath);
-    File connectionPropsFile = new File(connectionPropsPath);
-    Preconditions.checkArgument(connectionPropsFile.exists(), connectionPropsPath
-        + " does not exist");
+    final String applicationName = args[0];
+    final String className = args[1];
 
-    FluoConfiguration fluoConfig = new FluoConfiguration(connectionPropsFile);
+    FluoConfiguration fluoConfig = CommandUtil.resolveFluoConfig();
     fluoConfig.setApplicationName(applicationName);
     CommandUtil.verifyAppInitialized(fluoConfig);
     fluoConfig = FluoAdminImpl.mergeZookeeperConfig(fluoConfig);
diff --git a/modules/command/src/main/java/org/apache/fluo/command/FluoGetJars.java b/modules/command/src/main/java/org/apache/fluo/command/FluoGetJars.java
index a866515..d4f8c7b 100644
--- a/modules/command/src/main/java/org/apache/fluo/command/FluoGetJars.java
+++ b/modules/command/src/main/java/org/apache/fluo/command/FluoGetJars.java
@@ -17,9 +17,8 @@
 
 import java.io.File;
 import java.net.URI;
-import java.util.Objects;
 
-import com.google.common.base.Preconditions;
+import com.beust.jcommander.Parameter;
 import org.apache.commons.io.FileUtils;
 import org.apache.fluo.api.config.FluoConfiguration;
 import org.apache.fluo.core.client.FluoAdminImpl;
@@ -33,40 +32,45 @@
 
   private static final Logger log = LoggerFactory.getLogger(FluoGetJars.class);
 
-  public static void main(String[] args) {
-    if (args.length != 3) {
-      System.err
-          .println("Usage: FluoGetJars <connectionPropsPath> <applicationName> <downloadPath>");
-      System.exit(-1);
+  public static class GetJarsOpts extends CommonOpts {
+
+    @Parameter(names = "-d", required = true, description = "Download directory path")
+    private String downloadPath;
+
+    String getDownloadPath() {
+      return downloadPath;
     }
-    String connectionPropsPath = args[0];
-    String applicationName = args[1];
-    String downloadPath = args[2];
-    Objects.requireNonNull(connectionPropsPath);
-    Objects.requireNonNull(applicationName);
-    File connectionPropsFile = new File(connectionPropsPath);
-    Preconditions.checkArgument(connectionPropsFile.exists(), connectionPropsPath
-        + " does not exist");
 
-    FluoConfiguration config = new FluoConfiguration(connectionPropsFile);
-    config.setApplicationName(applicationName);
+    public static GetJarsOpts parse(String[] args) {
+      GetJarsOpts opts = new GetJarsOpts();
+      parse("fluo get-jars", opts, args);
+      return opts;
+    }
+  }
+
+  public static void main(String[] args) {
+
+    GetJarsOpts opts = GetJarsOpts.parse(args);
+
+    FluoConfiguration config = CommandUtil.resolveFluoConfig();
+    config.setApplicationName(opts.getApplicationName());
+    opts.overrideFluoConfig(config);
+
     CommandUtil.verifyAppInitialized(config);
-
     config = FluoAdminImpl.mergeZookeeperConfig(config);
-
     if (config.getObserverJarsUrl().isEmpty()) {
-      log.info("No observer jars found for the '{}' Fluo application!", applicationName);
+      log.info("No observer jars found for the '{}' Fluo application!", opts.getApplicationName());
       return;
     }
 
     try {
       if (config.getObserverJarsUrl().startsWith("hdfs://")) {
         FileSystem fs = FileSystem.get(new URI(config.getDfsRoot()), new Configuration());
-        File downloadPathFile = new File(downloadPath);
+        File downloadPathFile = new File(opts.getDownloadPath());
         if (downloadPathFile.exists()) {
           FileUtils.deleteDirectory(downloadPathFile);
         }
-        fs.copyToLocalFile(new Path(config.getObserverJarsUrl()), new Path(downloadPath));
+        fs.copyToLocalFile(new Path(config.getObserverJarsUrl()), new Path(opts.getDownloadPath()));
       } else {
         log.error("Unsupported url prefix for {}={}", FluoConfiguration.OBSERVER_JARS_URL_PROP,
             config.getObserverJarsUrl());
diff --git a/modules/command/src/main/java/org/apache/fluo/command/FluoGetProp.java b/modules/command/src/main/java/org/apache/fluo/command/FluoGetProp.java
deleted file mode 100644
index 61e3254..0000000
--- a/modules/command/src/main/java/org/apache/fluo/command/FluoGetProp.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.fluo.command;
-
-import java.io.File;
-import java.net.URI;
-import java.util.Objects;
-
-import com.google.common.base.Preconditions;
-import org.apache.commons.io.FileUtils;
-import org.apache.fluo.api.config.FluoConfiguration;
-import org.apache.fluo.core.client.FluoAdminImpl;
-import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.fs.FileSystem;
-import org.apache.hadoop.fs.Path;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class FluoGetProp {
-
-  public static void main(String[] args) {
-    if (args.length != 3) {
-      System.err
-          .println("Usage: FluoGetProps <connectionPropsPath> <applicationPropsPath> <property>");
-      System.exit(-1);
-    }
-    final String connectionPropsPath = args[0];
-    final String applicationPropsPath = args[1];
-    final String prop = args[2];
-    Objects.requireNonNull(connectionPropsPath);
-    Objects.requireNonNull(applicationPropsPath);
-    File connectionPropsFile = new File(connectionPropsPath);
-    File applicationPropsFile = new File(applicationPropsPath);
-    Preconditions.checkArgument(connectionPropsFile.exists(), connectionPropsPath
-        + " does not exist");
-    Preconditions.checkArgument(applicationPropsFile.exists(), applicationPropsPath
-        + " does not exist");
-
-    FluoConfiguration config = new FluoConfiguration(connectionPropsFile);
-    config.load(applicationPropsFile);
-
-    if (config.containsKey(prop)) {
-      System.out.println(config.getString(prop));
-    }
-  }
-}
diff --git a/modules/command/src/main/java/org/apache/fluo/command/FluoInit.java b/modules/command/src/main/java/org/apache/fluo/command/FluoInit.java
index 0532c5f..12d2021 100644
--- a/modules/command/src/main/java/org/apache/fluo/command/FluoInit.java
+++ b/modules/command/src/main/java/org/apache/fluo/command/FluoInit.java
@@ -19,12 +19,8 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStreamReader;
-import java.util.Arrays;
-import java.util.Objects;
 
-import com.beust.jcommander.JCommander;
 import com.beust.jcommander.Parameter;
-import com.beust.jcommander.ParameterException;
 import com.google.common.base.Preconditions;
 import org.apache.fluo.api.client.FluoAdmin;
 import org.apache.fluo.api.config.FluoConfiguration;
@@ -32,7 +28,10 @@
 
 public class FluoInit {
 
-  public static class InitOptions {
+  public static class InitOptions extends CommonOpts {
+
+    @Parameter(names = "-p", required = true, description = "Path to application properties file")
+    private String appPropsPath;
 
     @Parameter(names = {"-f", "--force"},
         description = "Skip all prompts and clears Zookeeper and Accumulo table.  Equivalent to "
@@ -48,8 +47,13 @@
     @Parameter(names = {"-u", "--update"}, description = "Update Fluo configuration in Zookeeper")
     private boolean update;
 
-    @Parameter(names = {"-h", "-help", "--help"}, help = true, description = "Prints help")
-    boolean help;
+    @Parameter(names = "--retrieveProperty",
+        description = "Gets specified property without initializing")
+    private String retrieveProperty;
+
+    String getAppPropsPath() {
+      return appPropsPath;
+    }
 
     boolean getForce() {
       return force;
@@ -66,10 +70,20 @@
     boolean getUpdate() {
       return update;
     }
+
+    String getRetrieveProperty() {
+      return retrieveProperty;
+    }
+
+    public static InitOptions parse(String[] args) {
+      InitOptions opts = new InitOptions();
+      parse("fluo init", opts, args);
+      return opts;
+    }
   }
 
   private static boolean readYes() {
-    String input = "unk";
+    String input;
     while (true) {
       BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
       try {
@@ -88,50 +102,27 @@
   }
 
   public static void main(String[] args) {
-    if (args.length < 1) {
-      System.err
-          .println("Usage: FluoInit <connectionPropsPath> <appName> <applicationPropsPath> userArgs...");
-      System.exit(-1);
-    }
-    String connectionPropsPath = args[0];
-    Objects.requireNonNull(connectionPropsPath);
-    Preconditions.checkArgument(!connectionPropsPath.isEmpty(), "<connectionPropsPath> is empty");
-    File connectionPropsFile = new File(connectionPropsPath);
-    Preconditions.checkArgument(connectionPropsFile.exists(), connectionPropsPath
+
+    InitOptions opts = InitOptions.parse(args);
+    File applicationPropsFile = new File(opts.getAppPropsPath());
+    Preconditions.checkArgument(applicationPropsFile.exists(), opts.getAppPropsPath()
         + " does not exist");
 
-    String[] userArgs = Arrays.copyOfRange(args, 3, args.length);
-
-    InitOptions commandOpts = new InitOptions();
-    JCommander jcommand = new JCommander(commandOpts);
-    jcommand.setProgramName("fluo init <app> <appProps>");
-    try {
-      jcommand.parse(userArgs);
-    } catch (ParameterException e) {
-      System.err.println(e.getMessage());
-      jcommand.usage();
-      System.exit(-1);
-    }
-
-    if (commandOpts.help) {
-      jcommand.usage();
-      System.exit(1);
-    }
-
-    String applicationName = args[1];
-    Objects.requireNonNull(applicationName);
-    String applicationPropsPath = args[2];
-    Objects.requireNonNull(applicationPropsPath);
-    File applicationPropsFile = new File(applicationPropsPath);
-    Preconditions.checkArgument(applicationPropsFile.exists(), applicationPropsPath
-        + " does not exist");
-
-    FluoConfiguration config = new FluoConfiguration(connectionPropsFile);
+    FluoConfiguration config = CommandUtil.resolveFluoConfig();
     config.load(applicationPropsFile);
-    config.setApplicationName(applicationName);
+    config.setApplicationName(opts.getApplicationName());
+    opts.overrideFluoConfig(config);
+
+    String propKey = opts.getRetrieveProperty();
+    if (propKey != null && !propKey.isEmpty()) {
+      if (config.containsKey(propKey)) {
+        System.out.println(config.getString(propKey));
+      }
+      System.exit(0);
+    }
 
     if (!config.hasRequiredAdminProps()) {
-      System.err.println("Error - Required properties are not set in " + applicationPropsPath);
+      System.err.println("Error - Required properties are not set in " + opts.getAppPropsPath());
       System.exit(-1);
     }
     try {
@@ -152,18 +143,18 @@
 
       FluoAdmin.InitializationOptions initOpts = new FluoAdmin.InitializationOptions();
 
-      if (commandOpts.getUpdate()) {
+      if (opts.getUpdate()) {
         System.out.println("Updating configuration for the Fluo '" + config.getApplicationName()
-            + "' application in Zookeeper using " + applicationPropsPath);
+            + "' application in Zookeeper using " + opts.getAppPropsPath());
         admin.updateSharedConfig();
         System.out.println("Update is complete.");
         System.exit(0);
       }
 
-      if (commandOpts.getForce()) {
+      if (opts.getForce()) {
         initOpts.setClearZookeeper(true).setClearTable(true);
       } else {
-        if (commandOpts.getClearZookeeper()) {
+        if (opts.getClearZookeeper()) {
           initOpts.setClearZookeeper(true);
         } else if (admin.zookeeperInitialized()) {
           System.out.print("A Fluo '" + config.getApplicationName()
@@ -178,7 +169,7 @@
           }
         }
 
-        if (commandOpts.getClearTable()) {
+        if (opts.getClearTable()) {
           initOpts.setClearTable(true);
         } else if (admin.accumuloTableExists()) {
           System.out.print("The Accumulo table '" + config.getAccumuloTable()
@@ -193,7 +184,7 @@
       }
 
       System.out.println("Initializing Fluo '" + config.getApplicationName()
-          + "' application using " + applicationPropsPath);
+          + "' application using " + opts.getAppPropsPath());
       try {
         admin.initialize(initOpts);
       } catch (Exception e) {
diff --git a/modules/command/src/main/java/org/apache/fluo/command/FluoList.java b/modules/command/src/main/java/org/apache/fluo/command/FluoList.java
index 262821a..02f9768 100644
--- a/modules/command/src/main/java/org/apache/fluo/command/FluoList.java
+++ b/modules/command/src/main/java/org/apache/fluo/command/FluoList.java
@@ -15,12 +15,9 @@
 
 package org.apache.fluo.command;
 
-import java.io.File;
 import java.util.Collections;
 import java.util.List;
-import java.util.Objects;
 
-import com.google.common.base.Preconditions;
 import org.apache.curator.framework.CuratorFramework;
 import org.apache.fluo.api.config.FluoConfiguration;
 import org.apache.fluo.core.client.FluoAdminImpl;
@@ -29,17 +26,10 @@
 public class FluoList {
 
   public static void main(String[] args) throws Exception {
-    if (args.length != 1) {
-      System.err.println("Usage: FluoList <connectionPropsPath>");
-      System.exit(-1);
-    }
-    String connectionPropsPath = args[0];
-    Objects.requireNonNull(connectionPropsPath);
-    File connectionPropsFile = new File(connectionPropsPath);
-    Preconditions.checkArgument(connectionPropsFile.exists(), connectionPropsPath
-        + " does not exist");
 
-    FluoConfiguration config = new FluoConfiguration(connectionPropsFile);
+    ConfigOpts commandOpts = ConfigOpts.parse("fluo list", args);
+    FluoConfiguration config = CommandUtil.resolveFluoConfig();
+    commandOpts.overrideFluoConfig(config);
 
     try (CuratorFramework curator = CuratorUtil.newFluoCurator(config)) {
       curator.start();
diff --git a/modules/command/src/main/java/org/apache/fluo/command/FluoOracle.java b/modules/command/src/main/java/org/apache/fluo/command/FluoOracle.java
index febaf6d..3cea36a 100644
--- a/modules/command/src/main/java/org/apache/fluo/command/FluoOracle.java
+++ b/modules/command/src/main/java/org/apache/fluo/command/FluoOracle.java
@@ -15,10 +15,6 @@
 
 package org.apache.fluo.command;
 
-import java.io.File;
-import java.util.Objects;
-
-import com.google.common.base.Preconditions;
 import org.apache.fluo.api.client.FluoFactory;
 import org.apache.fluo.api.config.FluoConfiguration;
 import org.apache.fluo.core.util.UtilWaitThread;
@@ -30,22 +26,12 @@
   private static final Logger log = LoggerFactory.getLogger(FluoOracle.class);
 
   public static void main(String[] args) {
-    if (args.length != 2) {
-      System.err.println("Usage: FluoOracle <connectionPropsPath> <applicationName>");
-      System.exit(-1);
-    }
-    String connectionPropsPath = args[0];
-    String applicationName = args[1];
-    Objects.requireNonNull(connectionPropsPath);
-    Objects.requireNonNull(applicationName);
-    File connectionPropsFile = new File(connectionPropsPath);
-    Preconditions.checkArgument(connectionPropsFile.exists(), connectionPropsPath
-        + " does not exist");
-
+    CommonOpts opts = CommonOpts.parse("fluo oracle", args);
+    FluoConfiguration config = CommandUtil.resolveFluoConfig();
+    config.setApplicationName(opts.getApplicationName());
+    opts.overrideFluoConfig(config);
+    CommandUtil.verifyAppInitialized(config);
     try {
-      FluoConfiguration config = new FluoConfiguration(connectionPropsFile);
-      config.setApplicationName(applicationName);
-      CommandUtil.verifyAppInitialized(config);
       org.apache.fluo.api.service.FluoOracle oracle = FluoFactory.newOracle(config);
       oracle.start();
       while (true) {
diff --git a/modules/command/src/main/java/org/apache/fluo/command/FluoScan.java b/modules/command/src/main/java/org/apache/fluo/command/FluoScan.java
index 432ffed..28caa07 100644
--- a/modules/command/src/main/java/org/apache/fluo/command/FluoScan.java
+++ b/modules/command/src/main/java/org/apache/fluo/command/FluoScan.java
@@ -15,16 +15,10 @@
 
 package org.apache.fluo.command;
 
-import java.io.File;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
-import java.util.Objects;
 
-import com.beust.jcommander.JCommander;
 import com.beust.jcommander.Parameter;
-import com.beust.jcommander.ParameterException;
-import com.google.common.base.Preconditions;
 import org.apache.fluo.api.config.FluoConfiguration;
 import org.apache.fluo.core.util.ScanUtil;
 import org.apache.log4j.Level;
@@ -32,7 +26,7 @@
 
 public class FluoScan {
 
-  public static class ScanOptions {
+  public static class ScanOptions extends CommonOpts {
 
     @Parameter(names = "-s", description = "Start row (inclusive) of scan")
     private String startRow;
@@ -50,9 +44,6 @@
     @Parameter(names = "-p", description = "Row prefix to scan")
     private String rowPrefix;
 
-    @Parameter(names = {"-h", "-help", "--help"}, help = true, description = "Prints help")
-    public boolean help;
-
     @Parameter(names = {"-esc", "--escape-non-ascii"}, help = true,
         description = "Hex encode non ascii bytes", arity = 1)
     public boolean hexEncNonAscii = true;
@@ -91,43 +82,23 @@
       return new ScanUtil.ScanOpts(startRow, endRow, columns, exactRow, rowPrefix, help,
           hexEncNonAscii, scanAccumuloTable);
     }
+
+    public static ScanOptions parse(String[] args) {
+      ScanOptions opts = new ScanOptions();
+      parse("fluo scan", opts, args);
+      return opts;
+    }
   }
 
   public static void main(String[] args) {
-    if (args.length < 2) {
-      System.err.println("Usage: FluoScan <connectionPropsPath> <appName> userArgs...");
-      System.exit(-1);
-    }
-    final String connectionPropsPath = args[0];
-    final String applicationName = args[1];
-    Objects.requireNonNull(connectionPropsPath);
-    File connectionPropsFile = new File(connectionPropsPath);
-    Preconditions.checkArgument(connectionPropsFile.exists(), connectionPropsPath
-        + " does not exist");
-
-    String[] userArgs = Arrays.copyOfRange(args, 2, args.length);
 
     Logger.getRootLogger().setLevel(Level.ERROR);
     Logger.getLogger("org.apache.fluo").setLevel(Level.ERROR);
 
-    ScanOptions options = new ScanOptions();
-    JCommander jcommand = new JCommander(options);
-    jcommand.setProgramName("fluo scan <app>");
-    try {
-      jcommand.parse(userArgs);
-    } catch (ParameterException e) {
-      System.err.println(e.getMessage());
-      jcommand.usage();
-      System.exit(-1);
-    }
-
-    if (options.help) {
-      jcommand.usage();
-      System.exit(0);
-    }
-
-    FluoConfiguration config = new FluoConfiguration(connectionPropsFile);
-    config.setApplicationName(applicationName);
+    ScanOptions options = ScanOptions.parse(args);
+    FluoConfiguration config = CommandUtil.resolveFluoConfig();
+    config.setApplicationName(options.getApplicationName());
+    options.overrideFluoConfig(config);
     CommandUtil.verifyAppRunning(config);
 
     if (options.scanAccumuloTable) {
diff --git a/modules/command/src/main/java/org/apache/fluo/command/FluoStatus.java b/modules/command/src/main/java/org/apache/fluo/command/FluoStatus.java
index da56009..4cd227f 100644
--- a/modules/command/src/main/java/org/apache/fluo/command/FluoStatus.java
+++ b/modules/command/src/main/java/org/apache/fluo/command/FluoStatus.java
@@ -15,39 +15,20 @@
 
 package org.apache.fluo.command;
 
-import java.io.File;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-
-import com.google.common.base.Preconditions;
-import org.apache.curator.framework.CuratorFramework;
 import org.apache.fluo.api.config.FluoConfiguration;
 import org.apache.fluo.core.client.FluoAdminImpl;
-import org.apache.fluo.core.util.CuratorUtil;
 
 public class FluoStatus {
 
   public static void main(String[] args) throws Exception {
-    if (args.length != 2) {
-      System.err.println("Usage: FluoStatus <connectionPropsPath> <applicationName>");
-      System.exit(-1);
-    }
-    String connectionPropsPath = args[0];
-    String applicationName = args[1];
-    Objects.requireNonNull(connectionPropsPath);
-    File connectionPropsFile = new File(connectionPropsPath);
-    Preconditions.checkArgument(connectionPropsFile.exists(), connectionPropsPath
-        + " does not exist");
-
-    FluoConfiguration config = new FluoConfiguration(connectionPropsFile);
-    config.setApplicationName(applicationName);
-
+    CommonOpts opts = CommonOpts.parse("fluo status", args);
+    FluoConfiguration config = CommandUtil.resolveFluoConfig();
+    config.setApplicationName(opts.getApplicationName());
+    opts.overrideFluoConfig(config);
     try (FluoAdminImpl admin = new FluoAdminImpl(config)) {
       if (!admin.zookeeperInitialized()) {
         System.out.println("NOT_FOUND");
-      }
-      if (admin.applicationRunning()) {
+      } else if (admin.applicationRunning()) {
         System.out.println("RUNNING");
       } else {
         System.out.println("STOPPED");
diff --git a/modules/command/src/main/java/org/apache/fluo/command/FluoWait.java b/modules/command/src/main/java/org/apache/fluo/command/FluoWait.java
index 33fae21..2bba0c7 100644
--- a/modules/command/src/main/java/org/apache/fluo/command/FluoWait.java
+++ b/modules/command/src/main/java/org/apache/fluo/command/FluoWait.java
@@ -15,11 +15,6 @@
 
 package org.apache.fluo.command;
 
-import java.io.File;
-import java.util.Objects;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
 import com.google.common.collect.Iterables;
 import org.apache.accumulo.core.client.Scanner;
 import org.apache.accumulo.core.client.TableNotFoundException;
@@ -47,9 +42,8 @@
     return sleep;
   }
 
-  @VisibleForTesting
-  public static long countNotifications(Environment env) {
-    Scanner scanner = null;
+  private static long countNotifications(Environment env) {
+    Scanner scanner;
     try {
       scanner = env.getConnector().createScanner(env.getTable(), env.getAuthorizations());
     } catch (TableNotFoundException e) {
@@ -62,7 +56,7 @@
     return Iterables.size(scanner);
   }
 
-  public static void waitUntilFinished(FluoConfiguration config) {
+  private static void waitUntilFinished(FluoConfiguration config) {
     try (Environment env = new Environment(config)) {
       log.info("The wait command will exit when all notifications are processed");
       while (true) {
@@ -93,24 +87,13 @@
     }
   }
 
-
   public static void main(String[] args) throws Exception {
-    if (args.length != 2) {
-      System.err.println("Usage: FluoWait <connectionPropsPath> <applicationName>");
-      System.exit(-1);
-    }
-    String connectionPropsPath = args[0];
-    String applicationName = args[1];
-    Objects.requireNonNull(connectionPropsPath);
-    File connectionPropsFile = new File(connectionPropsPath);
-    Preconditions.checkArgument(connectionPropsFile.exists(), connectionPropsPath
-        + " does not exist");
-
-    FluoConfiguration fluoConfig = new FluoConfiguration(connectionPropsFile);
-    fluoConfig.setApplicationName(applicationName);
-    CommandUtil.verifyAppRunning(fluoConfig);
-    fluoConfig = FluoAdminImpl.mergeZookeeperConfig(fluoConfig);
-
-    waitUntilFinished(fluoConfig);
+    CommonOpts opts = CommonOpts.parse("fluo wait", args);
+    FluoConfiguration config = CommandUtil.resolveFluoConfig();
+    config.setApplicationName(opts.getApplicationName());
+    opts.overrideFluoConfig(config);
+    CommandUtil.verifyAppRunning(config);
+    config = FluoAdminImpl.mergeZookeeperConfig(config);
+    waitUntilFinished(config);
   }
 }
diff --git a/modules/command/src/main/java/org/apache/fluo/command/FluoWorker.java b/modules/command/src/main/java/org/apache/fluo/command/FluoWorker.java
index bb64446..6a0f982 100644
--- a/modules/command/src/main/java/org/apache/fluo/command/FluoWorker.java
+++ b/modules/command/src/main/java/org/apache/fluo/command/FluoWorker.java
@@ -15,10 +15,6 @@
 
 package org.apache.fluo.command;
 
-import java.io.File;
-import java.util.Objects;
-
-import com.google.common.base.Preconditions;
 import org.apache.fluo.api.client.FluoFactory;
 import org.apache.fluo.api.config.FluoConfiguration;
 import org.apache.fluo.core.util.UtilWaitThread;
@@ -30,22 +26,14 @@
   private static final Logger log = LoggerFactory.getLogger(FluoWorker.class);
 
   public static void main(String[] args) {
-    if (args.length != 2) {
-      System.err.println("Usage: FluoWorker <connectionPropsPath> <applicationName>");
-      System.exit(-1);
-    }
-    String connectionPropsPath = args[0];
-    String applicationName = args[1];
-    Objects.requireNonNull(connectionPropsPath);
-    Objects.requireNonNull(applicationName);
-    File connectionPropsFile = new File(connectionPropsPath);
-    Preconditions.checkArgument(connectionPropsFile.exists(), connectionPropsPath
-        + " does not exist");
+
+    CommonOpts opts = CommonOpts.parse("fluo worker", args);
+    FluoConfiguration config = CommandUtil.resolveFluoConfig();
+    config.setApplicationName(opts.getApplicationName());
+    opts.overrideFluoConfig(config);
+    CommandUtil.verifyAppInitialized(config);
 
     try {
-      FluoConfiguration config = new FluoConfiguration(connectionPropsFile);
-      config.setApplicationName(applicationName);
-      CommandUtil.verifyAppInitialized(config);
       org.apache.fluo.api.service.FluoWorker worker = FluoFactory.newWorker(config);
       worker.start();
       while (true) {
diff --git a/modules/command/src/test/java/org/apache/fluo/command/ScanTest.java b/modules/command/src/test/java/org/apache/fluo/command/ScanTest.java
index 810d689..5998e89 100644
--- a/modules/command/src/test/java/org/apache/fluo/command/ScanTest.java
+++ b/modules/command/src/test/java/org/apache/fluo/command/ScanTest.java
@@ -41,38 +41,38 @@
   public void testValidInput() {
     SnapshotScanner.Opts config;
 
-    config = parseArgs("");
+    config = parseArgs("-a app");
     Assert.assertEquals(RowColumn.EMPTY, config.getSpan().getStart());
     Assert.assertEquals(RowColumn.EMPTY, config.getSpan().getEnd());
     Assert.assertEquals(0, config.getColumns().size());
 
-    config = parseArgs("-s start -e end -c col1,col2");
+    config = parseArgs("-a app -s start -e end -c col1,col2");
     Assert.assertEquals(new RowColumn("start"), config.getSpan().getStart());
     Assert.assertEquals(new RowColumn("end").following(), config.getSpan().getEnd());
     Assert.assertEquals(2, config.getColumns().size());
     Assert.assertTrue(config.getColumns().contains(new Column("col1")));
     Assert.assertTrue(config.getColumns().contains(new Column("col2")));
 
-    config = parseArgs("-s start -c cf:cq");
+    config = parseArgs("-a app -s start -c cf:cq");
     Assert.assertEquals(new RowColumn("start"), config.getSpan().getStart());
     Assert.assertEquals(RowColumn.EMPTY, config.getSpan().getEnd());
     Assert.assertEquals(1, config.getColumns().size());
     Assert.assertTrue(config.getColumns().contains(new Column("cf", "cq")));
 
-    config = parseArgs("-e end");
+    config = parseArgs("-a app -e end");
     Assert.assertEquals(RowColumn.EMPTY, config.getSpan().getStart());
     Assert.assertEquals(new RowColumn("end").following(), config.getSpan().getEnd());
     Assert.assertEquals(0, config.getColumns().size());
 
-    config = parseArgs("-p myprefix");
+    config = parseArgs("-a app -p myprefix");
     Assert.assertEquals(Span.prefix("myprefix"), config.getSpan());
     Assert.assertEquals(0, config.getColumns().size());
 
-    config = parseArgs("-r exactRow");
+    config = parseArgs("-a app -r exactRow");
     Assert.assertEquals(Span.exact("exactRow"), config.getSpan());
     Assert.assertEquals(0, config.getColumns().size());
 
-    config = parseArgs("-c cf1:cq1,cf2:cq2");
+    config = parseArgs("-a app -c cf1:cq1,cf2:cq2");
     Assert.assertEquals(RowColumn.EMPTY, config.getSpan().getStart());
     Assert.assertEquals(RowColumn.EMPTY, config.getSpan().getEnd());
     Assert.assertEquals(2, config.getColumns().size());
@@ -84,7 +84,7 @@
   public void testBadInputs() {
     for (String extraArg : new String[] {"-r exactRow", "-s start", "-e end", "-s start -e end"}) {
       try {
-        parseArgs("-p prefix " + extraArg);
+        parseArgs("-a app -p prefix " + extraArg);
         Assert.fail();
       } catch (IllegalArgumentException e) {
       }
@@ -92,14 +92,14 @@
 
     for (String extraArg : new String[] {"-p prefix", "-s start", "-e end", "-s start -e end"}) {
       try {
-        parseArgs("-r exactRow " + extraArg);
+        parseArgs("-a app -r exactRow " + extraArg);
         Assert.fail();
       } catch (IllegalArgumentException e) {
       }
     }
 
     try {
-      parseArgs("-c col1,cf:cq:oops");
+      parseArgs("-a app -c col1,cf:cq:oops");
       Assert.fail();
     } catch (IllegalArgumentException e) {
     }
diff --git a/modules/distribution/src/main/config/fluo-env.sh b/modules/distribution/src/main/config/fluo-env.sh
index eac5ed8..e027f14 100755
--- a/modules/distribution/src/main/config/fluo-env.sh
+++ b/modules/distribution/src/main/config/fluo-env.sh
@@ -28,22 +28,15 @@
 ## Fluo connection properties
 export FLUO_CONN_PROPS="${FLUO_CONN_PROPS:-${conf}/fluo-conn.properties}"
 
-###########################################################
-# Variables for running Fluo services (i.e oracle, worker).
-# Defaults below work but can be edited.
-###########################################################
+####################################################
+# Build JAVA_OPTS variable used by all Fluo commands
+####################################################
 
-## Fluo logs directory. Referenced by logger config.
-export FLUO_LOG_DIR="${FLUO_LOG_DIR:-${basedir}/logs}"
 ## Fluo log4j configuration
 export FLUO_LOG4J_CONFIG="${FLUO_LOG4J_CONFIG:-${conf}/log4j.properties}"
-## Fluo log identifier
-export FLUO_LOG_ID="${cmd}_$(hostname)_$(date +%s)"
-## Java options for Fluo services
-SERVICE_OPTS=("-Dlog4j.configuration=file:${FLUO_LOG4J_CONFIG}"
-           "-Dfluo.log.dir=${FLUO_LOG_DIR}/${app}"
-           "-Dfluo.log.id=${FLUO_LOG_ID}")
-export SERVICE_OPTS
+## Java options for Fluo command
+JAVA_OPTS=("-Dlog4j.configuration=file:${FLUO_LOG4J_CONFIG}")
+export JAVA_OPTS
 
 ##########################
 # Build CLASSPATH variable
diff --git a/modules/distribution/src/main/config/log4j.properties b/modules/distribution/src/main/config/log4j.properties
index 7b2feb7..e042cef 100644
--- a/modules/distribution/src/main/config/log4j.properties
+++ b/modules/distribution/src/main/config/log4j.properties
@@ -14,20 +14,17 @@
 # limitations under the License.
 
 ## Log4j 1.2 file that configures logging for Fluo processes
-## The system properties referenced below are configured by fluo-env.sh
 
-## Define a log file appender
-log4j.appender.file=org.apache.log4j.RollingFileAppender
-log4j.appender.file.File=${fluo.log.dir}/${fluo.log.id}.log
-log4j.appender.file.MaxFileSize=100MB
-log4j.appender.file.MaxBackupIndex=10
-log4j.appender.file.Threshold=INFO
-log4j.appender.file.layout=org.apache.log4j.PatternLayout
-log4j.appender.file.layout.ConversionPattern=%d{ISO8601} [%-8c{2}] %-5p: %m%n
+## Define a console appender
+log4j.appender.console=org.apache.log4j.ConsoleAppender
+log4j.appender.console.Target=System.out
+log4j.appender.console.Threshold=ALL
+log4j.appender.console.layout.ConversionPattern=%d{ISO8601} [%-8c{2}] %-5p: %m%n
+log4j.appender.console.layout=org.apache.log4j.PatternLayout
 
 ## Constrain some particularly spammy loggers
 log4j.logger.org.apache.zookeeper=ERROR
 log4j.logger.org.apache.curator=ERROR
 
-## Append most logs to file
-log4j.rootLogger=DEBUG, file
+## Append most logs to console
+log4j.rootLogger=INFO, console
diff --git a/modules/distribution/src/main/scripts/fluo b/modules/distribution/src/main/scripts/fluo
index 60b617f..7934ad4 100755
--- a/modules/distribution/src/main/scripts/fluo
+++ b/modules/distribution/src/main/scripts/fluo
@@ -36,7 +36,10 @@
 fi
 source "$conf/fluo-env.sh"
 export CLASSPATH
-
+JAVA="java ${JAVA_OPTS[*]}"
+if [ -f "$FLUO_CONN_PROPS" ]; then
+  JAVA="$JAVA -Dfluo.conn.props=$FLUO_CONN_PROPS"
+fi
 
 deprecated_fluo_props=$conf/fluo.properties
 
@@ -62,23 +65,23 @@
 function print_usage {
   echo -e "Usage: fluo <command> (<argument> ...)\n"
   echo -e "Possible commands:\n"
-  echo "  init <app> <appProps> {<arg>} Initializes Fluo application for <app> using <appProps>. Run with -h to see additional args."
+  echo "  init -a <app> -p <appProps>   Initializes Fluo application for <app> using <appProps>. Run with -h to see additional args."
   echo "  classpath                     Prints the classpath setup in fluo-env.sh"
-  echo "  config <app>                  Prints application configuration stored in Zookeeper for <app>"
-  echo "  get-jars <app> <dir>          Copies <app> jars from DFS to local <dir>"
+  echo "  config -a <app>               Prints application configuration stored in Zookeeper for <app>"
+  echo "  get-jars -a <app> -d <dir>    Copies <app> jars from DFS to local <dir>"
   echo "  list                          Lists all Fluo applications in Fluo instance"
-  echo "  scan <app>                    Prints snapshot of data in Fluo <app>"
-  echo "  status <app>                  Prints status of Fluo application for <app>"
-  echo "  stop <app>                    Stops Fluo application processes on this machine for <app>"
-  echo "  oracle <app>                  Starts Fluo Oracle process for <app>"
-  echo "  worker <app>                  Starts Fluo Worker process for <app>"
+  echo "  scan -a <app>                 Prints snapshot of data in Fluo <app>"
+  echo "  status -a <app>               Prints status of Fluo application for <app>"
+  echo "  oracle -a <app>               Starts Fluo Oracle process for <app>"
+  echo "  worker -a <app>               Starts Fluo Worker process for <app>"
   echo "  version                       Prints the version of Fluo"
-  echo "  wait <app>                    Waits until all notifications are processed for <app>"
+  echo "  wait -a <app>                 Waits until all notifications are processed for <app>"
   echo "  exec <app> <class> {<arg>}    Executes <class> with <args> using classpath for <app>";
 
   echo -e "\nDeprecated commands (available if fluo.properties exists):\n"
   echo "  new <app>     (Deprecated) Creates configuration for new application in apps/"
   echo "  start <app>   (Deprecated) Starts Fluo application on cluster"
+  echo "  stop <app>    (Deprecated) Stops Fluo application on cluster"
   echo "  init <app>    (Deprecated) Initializes Fluo application using configuration in apps/<app>/conf/fluo.properties"
   echo "  kill <app>    (Deprecated) Kills Fluo application on cluster"
   echo "  info <app>    (Deprecated) Prints information about containers of Fluo application"
@@ -136,55 +139,42 @@
 }
 
 function setup_service {
-  verify_app "$1"
-  check_conn_props
-  app_run_dir=$basedir/run/$app
-  mkdir -p "$app_run_dir" 2>/dev/null
-  app_log_dir=$FLUO_LOG_DIR/$app
-  mkdir -p "$app_log_dir" 2>/dev/null
-  app_lib=$lib/apps/$1
-  mkdir -p "$app_lib"
-  java org.apache.fluo.command.FluoGetJars "$FLUO_CONN_PROPS" "$1" "$app_lib"
-  export CLASSPATH="$conf:$app_lib/*:$CLASSPATH"
+  if [[ "$@" =~ ^.*-a\ *([^\ ]*).*$ ]]; then
+    app=${BASH_REMATCH[1]}
+    verify_app "$app"
+    check_conn_props
+    app_lib=$lib/apps/$1
+    mkdir -p "$app_lib"
+    $JAVA org.apache.fluo.command.FluoGetJars -d "$app_lib" "$@"
+    export CLASSPATH="$conf:$app_lib/*:$CLASSPATH"
+  else
+    echo "Application name must be set!"
+    print_usage
+    exit 1
+  fi
 }
 
 case "$1" in
 config)
-  verify_app "$2"
   check_conn_props
-  java org.apache.fluo.command.FluoConfig "$FLUO_CONN_PROPS" "$2"
+  $JAVA org.apache.fluo.command.FluoConfig "${@:2}"
   ;;
 get-jars)
-  verify_app "$2"
-  if [ ! -d "$3" ]; then
-    echo "Directory '$3' does not exist"
-    exit 1
-  fi
-  java org.apache.fluo.command.FluoGetJars "$FLUO_CONN_PROPS" "$2" "$3"
+  check_conn_props
+  $JAVA org.apache.fluo.command.FluoGetJars "${@:2}"
   ;;
 init)
   if [ -f "$FLUO_CONN_PROPS" ]; then
-    check_conn_props
-    if [ -z "$app" ]; then
-      echo -e "The application name (set by <app>) cannot be an empty string!\n"
-      print_usage
+    if [[ $2 = *"-h"* ]]; then
+      $JAVA org.apache.fluo.command.FluoInit -h
+      exit 0
     fi
-    if [[ "$app" = *"-h"* ]]; then
-      java org.apache.fluo.command.FluoInit "$FLUO_CONN_PROPS" none /dev/null "$2"
-      exit 1
-    fi
-    app_props=$3
-    if [ ! -f "$app_props" ]; then
-      echo "<appProps> is set to path '$app_props' that does not exist"
-      print_usage
-      exit 1
-    fi
-    init_dir=$(java org.apache.fluo.command.FluoGetProp "$FLUO_CONN_PROPS" "$app_props" fluo.observer.init.dir)
+    init_dir=$($JAVA org.apache.fluo.command.FluoInit "${@:2}" --retrieveProperty fluo.observer.init.dir)
     if [ -d "$init_dir" ]; then
       echo "Adding $init_dir/* to CLASSPATH"
       export CLASSPATH="$init_dir/*:$CLASSPATH"
     fi
-    java org.apache.fluo.command.FluoInit "$FLUO_CONN_PROPS" "$app" "$app_props" ${*:4}
+    $JAVA org.apache.fluo.command.FluoInit "${@:2}"
   else
     deprecated_verify_full "$2"
     check_hadoop
@@ -193,50 +183,38 @@
   fi
   ;;
 oracle)
-  setup_service "$2"
-  nohup java "${SERVICE_OPTS[@]}" org.apache.fluo.command.FluoOracle "$FLUO_CONN_PROPS" "$2" > "${app_log_dir}/${FLUO_LOG_ID}.out" 2> "${app_log_dir}/${FLUO_LOG_ID}.err" &
-  echo "$!" > "${app_run_dir}/${FLUO_LOG_ID}.pid"
-  echo "Started Oracle for '$2' Fluo application. Logs can be found in $app_log_dir"
+  if [[ $2 = *"-h"* ]]; then
+    $JAVA org.apache.fluo.command.FluoOracle -h
+    exit 0
+  fi
+  setup_service "${@:2}"
+  $JAVA org.apache.fluo.command.FluoOracle "${@:2}"
   ;;
 worker)
-  setup_service "$2"
-  nohup java "${SERVICE_OPTS[@]}" org.apache.fluo.command.FluoWorker "$FLUO_CONN_PROPS" "$2" > "${app_log_dir}/${FLUO_LOG_ID}.out" 2> "${app_log_dir}/${FLUO_LOG_ID}.err" &
-  echo "$!" > "${app_run_dir}/${FLUO_LOG_ID}.pid"
-  echo "Started Worker for '$2' Fluo application. Logs can be found in $app_log_dir"
+  if [[ $2 = *"-h"* ]]; then
+    $JAVA org.apache.fluo.command.FluoWorker -h
+    exit 0
+  fi
+  setup_service "${@:2}"
+  $JAVA org.apache.fluo.command.FluoWorker "${@:2}"
   ;;
 scan)
   if [ -f "$FLUO_CONN_PROPS" ]; then
-    verify_app "$2"
-    java org.apache.fluo.command.FluoScan "$FLUO_CONN_PROPS" ${*:2}
+    $JAVA org.apache.fluo.command.FluoScan "${@:2}"
   else
     check_hadoop
     java org.apache.fluo.cluster.command.FluoCommand "$basedir" "$HADOOP_PREFIX" "$@"
   fi
   ;;
-stop)
-  if [ -f "$FLUO_CONN_PROPS" ]; then
-    verify_app "$2"
-    echo "Stopping all processes for ${2} application"
-    for pid_file in $basedir/run/$2/*.pid; do
-      if [ -f "$pid_file" ]; then
-        kill -s KILL "$(cat "$pid_file")" 2>/dev/null
-        rm -f "${pid_file}" 2>/dev/null
-      fi 
-    done
-  else 
-    check_hadoop
-    java org.apache.fluo.cluster.command.FluoCommand "$basedir" "$HADOOP_PREFIX" "$@"
-  fi
-  ;;
 ps) 
   jps -m | grep Fluo
   ;;
 list)
   if [ -f "$FLUO_CONN_PROPS" ]; then
-    java org.apache.fluo.command.FluoList "$FLUO_CONN_PROPS"
+    $JAVA org.apache.fluo.command.FluoList "${@:2}"
   else
     check_hadoop
-    java org.apache.fluo.cluster.command.FluoCommand "$basedir" "$HADOOP_PREFIX" list app ${*:2}
+    java org.apache.fluo.cluster.command.FluoCommand "$basedir" "$HADOOP_PREFIX" list app "${@:2}"
   fi
   ;;
 classpath)
@@ -244,8 +222,8 @@
   ;;
 exec)
   if [ -f "$FLUO_CONN_PROPS" ]; then
-    setup_service $2
-    java org.apache.fluo.command.FluoExec "$FLUO_CONN_PROPS" ${*:2}
+    setup_service "$2"
+    $JAVA org.apache.fluo.command.FluoExec "$FLUO_CONN_PROPS" "${@:2}"
   else
     deprecated_verify "$2"
     export CLASSPATH="$APP_LIB_DIR/*:$CLASSPATH"
@@ -254,8 +232,7 @@
   ;;
 status)
   if [ -f "$FLUO_CONN_PROPS" ]; then
-    verify_app "$2"
-    java org.apache.fluo.command.FluoStatus "$FLUO_CONN_PROPS" "$2"
+    $JAVA org.apache.fluo.command.FluoStatus "${@:2}"
   else
     check_hadoop
     java org.apache.fluo.cluster.command.FluoCommand "$basedir" "$HADOOP_PREFIX" "$@"
@@ -266,8 +243,7 @@
   ;;
 wait)
   if [ -f "$FLUO_CONN_PROPS" ]; then
-    verify_app "$2"
-    java org.apache.fluo.command.FluoWait "$FLUO_CONN_PROPS" $2
+    $JAVA org.apache.fluo.command.FluoWait "${@:2}"
   else
     deprecated_verify "$2"
     export CLASSPATH="$APP_LIB_DIR/*:$CLASSPATH"
@@ -300,6 +276,10 @@
   export CLASSPATH="$APP_LIB_DIR/*:$CLASSPATH"
   java org.apache.fluo.cluster.command.FluoCommand "$basedir" "$HADOOP_PREFIX" "$@"
   ;;
+stop)
+  check_hadoop
+  java org.apache.fluo.cluster.command.FluoCommand "$basedir" "$HADOOP_PREFIX" "$@"
+  ;;
 kill|info)
   deprecated_verify "$2"
   check_hadoop