private int runCommandLine(final Map<String, Object> options, final String[] commandLine)
      throws IOException {
    // initialize the startup log starting with a fresh log file (where all startup messages are
    // printed)
    final File startLogFile =
        IOUtils.tryGetCanonicalFileElseGetAbsoluteFile(
            new File(workingDirectory, startLogFileName));

    if (startLogFile.exists() && !startLogFile.delete()) {
      throw new IOException(
          LocalizedStrings.AgentLauncher_UNABLE_TO_DELETE_FILE_0.toLocalizedString(
              startLogFile.getAbsolutePath()));
    }

    Map<String, String> env = (Map<String, String>) options.get(ENVARGS);
    if (env == null) {
      env = new HashMap<String, String>();
    }
    // read the passwords from command line
    SocketCreator.readSSLProperties(env, true);

    printCommandLine(commandLine);

    final int pid = OSProcess.bgexec(commandLine, workingDirectory, startLogFile, false, env);

    System.out.println(
        LocalizedStrings.AgentLauncher_STARTING_JMX_AGENT_WITH_PID_0.toLocalizedString(pid));

    return pid;
  }
  /** Stops a running JMX Agent by setting the status to "shutdown pending". */
  public void stop(final String[] args) throws Exception {
    final Map<String, Object> options = getStopOptions(args);

    workingDirectory = IOUtils.tryGetCanonicalFileElseGetAbsoluteFile((File) options.get(DIR));

    int exitStatus = 1;

    if (new File(workingDirectory, statusFileName).exists()) {
      spinReadStatus();

      if (!isStatus(SHUTDOWN)) {
        writeStatus(createStatus(this.basename, SHUTDOWN_PENDING, status.pid));
      }

      pollAgentForShutdown();

      if (isStatus(SHUTDOWN)) {
        System.out.println(
            LocalizedStrings.AgentLauncher_0_HAS_STOPPED.toLocalizedString(this.basename));
        deleteStatus();
        exitStatus = 0;
      } else {
        System.out.println(
            LocalizedStrings.AgentLauncher_TIMEOUT_WAITING_FOR_0_TO_SHUTDOWN_STATUS_IS_1
                .toLocalizedString(this.basename, status));
      }
    } else {
      System.out.println(
          LocalizedStrings.AgentLauncher_THE_SPECIFIED_WORKING_DIRECTORY_0_CONTAINS_NO_STATUS_FILE
              .toLocalizedString(workingDirectory));
    }

    System.exit(exitStatus);
  }
  /** Starts the GemFire JMX Agent "server" process with the given command line arguments. */
  public void server(final String[] args) throws Exception {
    final Map<String, Object> options = getServerOptions(args);

    // make the process a UNIX daemon if possible
    String errMsg = makeDaemon();

    workingDirectory = IOUtils.tryGetCanonicalFileElseGetAbsoluteFile((File) options.get(DIR));

    Status status = createStatus(this.basename, STARTING, OSProcess.getId());
    status.msg = errMsg;
    writeStatus(status);

    Agent agent = startAgentVM((Properties) options.get(AGENT_PROPS), status);

    // periodically check and see if the JMX Agent has been told to stop
    pollAgentForPendingShutdown(agent);
  }
  /** Extracts configuration information used when launching the cache server VM. */
  protected Map<String, Object> getServerOptions(final String[] args) throws Exception {
    final Map<String, Object> options = new HashMap<String, Object>();

    options.put(APPENDTO_LOG_FILE, "false");
    options.put(DIR, IOUtils.tryGetCanonicalFileElseGetAbsoluteFile(new File(".")));

    final Properties agentProps = new Properties();
    options.put(AGENT_PROPS, agentProps);

    for (final String arg : args) {
      if (arg.startsWith("-classpath=")) {
        options.put(CLASSPATH, arg.substring("-classpath=".length()));
      } else if (arg.startsWith("-dir=")) {
        final File workingDirectory = processDirOption(options, arg.substring("-dir=".length()));
        System.setProperty(
            AgentConfigImpl.AGENT_PROPSFILE_PROPERTY_NAME,
            new File(workingDirectory, AgentConfig.DEFAULT_PROPERTY_FILE).getPath());
      } else if (arg.contains("=")) {
        final int index = arg.indexOf("=");
        final String key = arg.substring(0, index);
        final String value = arg.substring(index + 1);

        if (key.startsWith("-")) {
          options.put(key.substring(1), value);
        } else {
          // if appendto-log-file is set, put it in options; it is not set as an
          // agent prop
          if (key.equals(APPENDTO_LOG_FILE)) {
            options.put(APPENDTO_LOG_FILE, value);
            continue;
          }

          if (key.equals(AgentConfigImpl.PROPERTY_FILE_NAME)) {
            System.setProperty(AgentConfigImpl.AGENT_PROPSFILE_PROPERTY_NAME, value);
          }
          agentProps.setProperty(key, value);
        }
      }
      System.out.println();
    }

    // any last minute processing of environment variables or otherwise
    processServerEnv(agentProps);

    return options;
  }
  /**
   * Extracts configuration information for stopping a agent based on the contents of the command
   * line. This method can also be used with getting the status of a agent.
   */
  protected Map<String, Object> getStopOptions(final String[] args) throws Exception {
    final Map<String, Object> options = new HashMap<String, Object>();

    options.put(DIR, IOUtils.tryGetCanonicalFileElseGetAbsoluteFile(new File(".")));

    for (final String arg : args) {
      if (arg.equals("stop") || arg.equals("status")) {
        // expected
      } else if (arg.startsWith("-dir=")) {
        processDirOption(options, arg.substring("-dir=".length()));
      } else {
        throw new Exception(
            LocalizedStrings.AgentLauncher_UNKNOWN_ARGUMENT_0.toLocalizedString(arg));
      }
    }

    return options;
  }
  /**
   * After parsing the command line arguments, spawn the Java VM that will host the GemFire JMX
   * Agent.
   */
  public void start(final String[] args) throws Exception {
    final Map<String, Object> options = getStartOptions(args);

    workingDirectory = IOUtils.tryGetCanonicalFileElseGetAbsoluteFile((File) options.get(DIR));

    // verify that any GemFire JMX Agent process has been properly shutdown and delete any remaining
    // status files...
    verifyAndClearStatus();

    // start the GemFire JMX Agent process...
    runCommandLine(options, buildCommandLine(options));

    // wait for the GemFire JMX Agent process to complete startup and begin running...
    // it is also possible the Agent process may fail to start, so this should not wait indefinitely
    // unless
    // the status file was not successfully written to
    pollAgentUntilRunning();

    System.exit(0);
  }
 /** Prints the status of the GemFire JMX Agent running in the configured working directory. */
 public void status(final String[] args) throws Exception {
   this.workingDirectory =
       IOUtils.tryGetCanonicalFileElseGetAbsoluteFile((File) getStopOptions(args).get(DIR));
   System.out.println(getStatus());
   System.exit(0);
 }
  /**
   * Returns a map that maps the name of the start options to its value on the command line. If no
   * value is specified on the command line, a default one is provided.
   */
  protected Map<String, Object> getStartOptions(final String[] args) throws Exception {
    final Map<String, Object> options = new HashMap<String, Object>();

    options.put(APPENDTO_LOG_FILE, "false");
    options.put(DIR, IOUtils.tryGetCanonicalFileElseGetAbsoluteFile(new File(".")));

    final List<String> vmArgs = new ArrayList<String>();
    options.put(VMARGS, vmArgs);

    final Properties agentProps = new Properties();
    options.put(AGENT_PROPS, agentProps);

    final Map<String, String> envArgs = new HashMap<String, String>();
    options.put(ENVARGS, envArgs);

    for (final String arg : args) {
      if (arg.startsWith("-classpath=")) {
        options.put(CLASSPATH, arg.substring("-classpath=".length()));
      } else if (arg.startsWith("-dir=")) {
        final File workingDirectory = processDirOption(options, arg.substring("-dir=".length()));
        System.setProperty(
            AgentConfigImpl.AGENT_PROPSFILE_PROPERTY_NAME,
            new File(workingDirectory, AgentConfig.DEFAULT_PROPERTY_FILE).getPath());
      } else if (arg.startsWith("-J")) {
        vmArgs.add(arg.substring(2));
      } else if (arg.contains("=")) {
        final int index = arg.indexOf("=");
        final String key = arg.substring(0, index);
        final String value = arg.substring(index + 1);

        if (key.startsWith("-")) {
          processStartOption(key.substring(1), value, options, vmArgs, envArgs, agentProps);
        } else {
          // if appendto-log-file is set, put it in options; it is not set as an
          // agent prop
          if (key.equals(APPENDTO_LOG_FILE)) {
            options.put(APPENDTO_LOG_FILE, value);
            continue;
          }

          // verify the property is valid
          AgentConfigImpl.getPropertyDescription(key);

          // Note, the gfAgentPropertyFile System property is ultimately read
          // in the constructor of the AgentImpl class in order to make any
          // properties defined in this file not only accessible to the
          // DistributedSystem but to the GemFire Agent as well.
          if (key.equals(AgentConfigImpl.PROPERTY_FILE_NAME)) {
            System.setProperty(AgentConfigImpl.AGENT_PROPSFILE_PROPERTY_NAME, value);
          }

          // The Agent properties file (specified with the command-line
          //   key=value) is used to pass configuration settings to the GemFire
          // DistributedSystem. A property file can be passed using the
          // property-file command-line switch is a large number of properties
          // are specified, or the properties maybe individually specified on
          // the command-line as property=value arguments.
          processStartArg(key, value, options, vmArgs, agentProps);
        }
      } else if (arg.equalsIgnoreCase("-password")) {
        processStartOption(arg.substring(1), null, options, vmArgs, envArgs, agentProps);
      }
    }

    return options;
  }