/**
   * Reads the remote execution handler from disk.
   *
   * @param directory Directory to read the handler from.
   * @param filename Filename used for the handler.
   */
  public static RemoteExecutionHandler readExecutionHandler(String directory, String filename) {
    try {
      ObjectInputStream inputOS =
          new ObjectInputStream(
              FileHelper.openR(
                  FileHelper.getFileInformation(directory, filename, Protocol.POSIX_COMPATIBLE)));

      return (RemoteExecutionHandler) inputOS.readObject();
    } catch (Exception exception) {
      System.err.println("Error opening user database: " + exception);

      return null;
    }
  }
  /**
   * Writes the remote execution handler into disk.
   *
   * @param directory Directory to write the handler to.
   * @param filename Filename used for the handler.
   * @param handler Handler to be written.
   */
  public static void writeExecutionHandler(
      String directory, String filename, RemoteExecutionHandler handler) {
    ObjectOutputStream outputOS;

    try {
      outputOS =
          new ObjectOutputStream(
              FileHelper.openW(
                  FileHelper.getFileInformation(directory, filename, Protocol.POSIX_COMPATIBLE)));

      outputOS.writeObject(handler);
    } catch (IOException exception) {
      System.err.println("Error writing user database:" + exception);
      exception.printStackTrace();
    }
  }
  public void run(String[] inputs, boolean useTCP, boolean initialSplit, boolean finalMerge) {
    int numberMappers;
    int numberReducers;

    numberMappers = numberReducers = inputs.length;

    Manager manager = (Manager) RMIHelper.locateRemoteObject(registryLocation, "Manager");

    // Create the MapReduce specification

    MapReduceSpecification mapReduceSpecification =
        new MapReduceSpecification("mapreduce", baseDirectory);

    // Insert the mappers

    Node[] nodesStage1 = new Node[numberMappers];

    for (int i = 0; i < nodesStage1.length; i++) {
      nodesStage1[i] = new CountingMapper<String>(numberReducers);
    }

    try {
      if (initialSplit) {
        mapReduceSpecification.insertMappers(
            FileHelper.getFileInformation(
                baseDirectory.getPath(), inputs[0], baseDirectory.getProtocol()),
            new ReaderSomeoneWriterSomeone(),
            nodesStage1);
      } else {
        // Create the input filenames

        Filename[] inputFilenames = new Filename[numberMappers];

        for (int i = 0; i < inputs.length; i++) {
          inputFilenames[i] =
              FileHelper.getFileInformation(
                  baseDirectory.getPath(), inputs[i], baseDirectory.getProtocol());
        }

        mapReduceSpecification.insertMappers(inputFilenames, nodesStage1);
      }
    } catch (InexistentInputException exception) {
      System.err.println(exception);

      System.exit(1);
    }

    // Insert the reducers

    Node[] nodesStage2 = new Node[numberReducers];

    for (int i = 0; i < nodesStage2.length; i++) {
      nodesStage2[i] = new CountingReducer<String>();
    }

    try {
      if (finalMerge) {
        mapReduceSpecification.insertReducers(
            FileHelper.getFileInformation(
                baseDirectory.getPath(), inputs[0] + ".out", baseDirectory.getProtocol()),
            new CountingMerger<String>(),
            nodesStage2);
      } else {
        // Append a ".out" extension to the input filenames to form the output filenames

        Filename[] outputFilenames = new Filename[numberReducers];

        for (int i = 0; i < inputs.length; i++) {
          outputFilenames[i] =
              FileHelper.getFileInformation(
                  baseDirectory.getPath(), inputs[i] + ".out", baseDirectory.getProtocol());
        }

        mapReduceSpecification.insertReducers(outputFilenames, nodesStage2);
      }
    } catch (OverlapingFilesException exception) {
      System.err.println(exception);

      System.exit(1);
    }

    try {
      mapReduceSpecification.setupCommunication(useTCP);
    } catch (OverlapingFilesException exception) {
      System.err.println(exception);

      System.exit(1);
    }

    try {
      manager.registerApplication(mapReduceSpecification);
    } catch (RemoteException exception) {
      System.err.println("Unable to contact manager");
      exception.printStackTrace();

      System.exit(1);
    }
  }