public int getStartHostID(InetAddress hostAddress) throws NoSuchElementException {
    WorkerEntry entry = null;
    synchronized (this.entryMap) {
      entry = this.entryMap.get(hostAddress);
    }

    if (entry == null) {
      throw new NoSuchElementException("There is no entry: " + hostAddress.getHostName());
    }

    return entry.getStartHostID();
  }
  public synchronized HostAndPort getWorkerHostAndPort(int hostID) {
    this.searchKey.startHostID = hostID + 1;
    SortedSet<WorkerEntry> headSet = this.entrySet.headSet(this.searchKey);

    if (headSet == null) {
      return null;
    }

    HostAndPort addr = null;
    try {
      WorkerEntry target = headSet.last();
      addr = target.getHostAndPort();
    } catch (NoSuchElementException e) {
      addr = null;
    }

    return addr;
  }
  /**
   * Generates a String representation of this instance. This String can be parsed by {@link
   * RemoteControlPipeTable#parseString(String) parseString} method.
   */
  public String getStringRepresentation() { // generates an argument for -w option
    StringBuilder sb = new StringBuilder();
    boolean firstEntry = true;

    for (WorkerEntry w : this.entrySet) {
      if (firstEntry) {
        firstEntry = false;
      } else {
        sb.append(",");
      }

      sb.append(w.getHostAndPort());
      sb.append(",");
      sb.append(w.getStartHostID());
    }

    return sb.toString();
  }
  public Set<Thread> establishControlPipes(
      String dir, String javaPath, String jvmOption, PrintStream out) {
    if (this.pipeEstablished) return null;

    // prepare arguments
    StringBuilder sb = new StringBuilder();

    if (dir != null) {
      sb.append("cd ");
      sb.append(dir);
      sb.append(" && ");
    }

    sb.append("exec ");

    if (true) {
      if (javaPath != null) {
        sb.append(javaPath);
        if (!javaPath.endsWith(File.separator)) {
          sb.append(File.separator);
        }
      }
    } else {
      if (javaPath != null) {
        sb.append("env PATH=");
        sb.append(javaPath);
        sb.append(" ");
      }
    }
    sb.append(Main.JAVA_COMMAND);

    if (jvmOption != null) {
      sb.append(" ");
      sb.append(jvmOption);
    }

    sb.append(" ");
    sb.append(Main.class.getName());
    sb.append(" -w ");
    sb.append(this.getStringRepresentation());

    String remoteCommand = sb.toString();

    Set<Thread> threadSet = new HashSet<Thread>();
    for (WorkerEntry w : this.entrySet) {
      InetAddress hostAddress = null;
      try {
        hostAddress = w.getHostAndPort().getHostAddress();
      } catch (UnknownHostException e) {
        System.err.println("Could not resolve a hostname: " + w.getHostAndPort().getHostName());
        System.exit(1);
      }

      if (this.pipeMap.get(hostAddress) != null) continue;

      // remote invocation
      out.println(
          "execute: " + Main.RSH_COMMAND + " " + hostAddress.getHostName() + " " + remoteCommand);

      ProcessBuilder pb =
          new ProcessBuilder(Main.RSH_COMMAND, hostAddress.getHostName(), remoteCommand);
      pb.redirectErrorStream(true);
      Process proc = null;
      try {
        proc = pb.start();
      } catch (IOException e) {
        System.err.println("Failed to start a remote shell:");
        e.printStackTrace(System.err);
        System.exit(1);
      }

      // input and output stream
      Thread t =
          this.outputRedirector.redirect(
              proc.getInputStream(), "Redirector for " + hostAddress.getHostAddress());
      threadSet.add(t);

      BufferedWriter controlPipe = null;
      try {
        controlPipe =
            new BufferedWriter(new OutputStreamWriter(proc.getOutputStream(), Main.ENCODING));
      } catch (UnsupportedEncodingException e) {
        // NOTREACHED
      }

      this.pipeMap.put(hostAddress, controlPipe);
    }

    this.pipeEstablished = true;

    return threadSet;
  }