/* start a transaction and add to transaction table */
  public Transaction start() {
    Transaction t = new Transaction(random.nextInt(Integer.MAX_VALUE));
    t.addCommand("start", "start");
    ArrayList<RMmeta.RMtype> types = new ArrayList<RMmeta.RMtype>();
    transactionTable.put(t, types);
    types.add(null);

    List<RMmeta> rms = middleware.resourceManagers;
    synchronized (rms) {
      for (RMmeta rm : rms) {
        Socket s = rm.getSocket();
        synchronized (s) {
          try {
            BufferedReader inFromServer =
                new BufferedReader(new InputStreamReader(s.getInputStream()));
            DataOutputStream outToServer = new DataOutputStream(s.getOutputStream());
            outToServer.writeBytes("start," + t.getId() + '\n');
            System.out.println(inFromServer.readLine());
          } catch (Exception e) {
            e.printStackTrace();
          }
        }
      }
    }
    return t;
  }
  /* abort a transaction, return true if success, false if not */
  public boolean abort(Transaction t) {
    if (!transactionTable.keySet().contains(t)) {
      System.out.println("Oops where does this transaction come from. " + t.toString());
      return false;
    }
    System.out.println("ABORTING: " + t.toString());

    List<RMmeta> rms = middleware.resourceManagers;
    synchronized (rms) {
      for (RMmeta rm : rms) {
        Socket s = rm.getSocket();
        synchronized (s) {
          try {
            BufferedReader inFromServer =
                new BufferedReader(new InputStreamReader(s.getInputStream()));
            DataOutputStream outToServer = new DataOutputStream(s.getOutputStream());
            outToServer.writeBytes("abort," + t.getId() + '\n');
            System.out.println(inFromServer.readLine());
          } catch (Exception e) {
            e.printStackTrace();
          }
        }
      }
    }

    this.middleware.lockManager.UnlockAll(t.getId());
    t.addCommand("abort", "abort");
    transactionTable.remove(t);
    return true;
  }
  /* commit a transaction, return true if success, false if not */
  public boolean commit(Transaction t) {
    if (!transactionTable.keySet().contains(t)) {
      System.out.println("Oops where does this transaction come from. " + t.toString());
      return false;
    }
    System.out.println("COMMIT: " + t.toString());
    t.addCommand("commit", "commit");
    List<RMmeta> rms = middleware.resourceManagers;
    synchronized (rms) {
      boolean result = true;
      // ask each rm to vote
      for (RMmeta rm : rms) {
        Socket s = rm.getSocket();
        synchronized (s) {
          try {
            BufferedReader inFromServer =
                new BufferedReader(new InputStreamReader(s.getInputStream()));
            DataOutputStream outToServer = new DataOutputStream(s.getOutputStream());
            outToServer.writeBytes("vote," + t.getId() + '\n');

            // crash point
            if (middleware.crashType
                == MiddlewareCrashType
                    .CRASH_AFTER_SENDING_VOTE_REQUEST_AND_BEFORE_RECEIVING_ANY_REPLIES) {
              System.out.println(middleware.crashType.toString());
              System.exit(1);
            }

            String ret = inFromServer.readLine();
            // if any return null(crash) or no then result is false
            if (ret == null || ret.compareToIgnoreCase("no") == 0) result = false;
          } catch (Exception e) {
            e.printStackTrace();
          }
        }
      }
      // crash point
      if (middleware.crashType
          == MiddlewareCrashType.CRASH_AFTER_RECEIVING_ALL_REPLIES_BUT_BEFORE_DECIDING) {
        System.out.println(middleware.crashType.toString());
        System.exit(1);
      }

      // if all vote yes, then commit
      if (result) {
        System.out.println("Decide to commit:" + t.toString());
        // crash point
        if (middleware.crashType
            == MiddlewareCrashType.CRASH_AFTER_DECIDING_BUT_BEFORE_SENDING_DECISION) {
          System.out.println(middleware.crashType.toString());
          System.exit(1);
        }
        for (RMmeta rm : rms) {
          Socket s = rm.getSocket();
          synchronized (s) {
            try {
              BufferedReader inFromServer =
                  new BufferedReader(new InputStreamReader(s.getInputStream()));
              DataOutputStream outToServer = new DataOutputStream(s.getOutputStream());
              outToServer.writeBytes("commit," + t.getId() + '\n');
              System.out.println(inFromServer.readLine());

              // crash point
              if (middleware.crashType
                  == MiddlewareCrashType.CRASH_AFTER_SENDING_SOME_BUT_NOT_ALL_DECISIONS) {
                System.out.println(middleware.crashType.toString());
                System.exit(1);
              }

            } catch (Exception e) {
              e.printStackTrace();
            }
          }
        }
        t.addCommand("commit", "commit");
        // if any vote no, then abort
      } else {
        System.out.println("Decide to abort: " + t.toString());
        // crash point
        if (middleware.crashType
            == MiddlewareCrashType.CRASH_AFTER_DECIDING_BUT_BEFORE_SENDING_DECISION) {
          System.out.println(middleware.crashType.toString());
          System.exit(1);
        }
        for (RMmeta rm : rms) {
          Socket s = rm.getSocket();
          synchronized (s) {
            try {
              BufferedReader inFromServer =
                  new BufferedReader(new InputStreamReader(s.getInputStream()));
              DataOutputStream outToServer = new DataOutputStream(s.getOutputStream());
              outToServer.writeBytes("abort," + t.getId() + '\n');
              System.out.println(inFromServer.readLine());

              // crash point
              if (middleware.crashType
                  == MiddlewareCrashType.CRASH_AFTER_SENDING_SOME_BUT_NOT_ALL_DECISIONS) {
                System.out.println(middleware.crashType.toString());
                System.exit(1);
              }

            } catch (Exception e) {
              e.printStackTrace();
            }
          }
        }
        t.addCommand("abort", "abort");
      }
      // crash point
      if (middleware.crashType == MiddlewareCrashType.CRASH_AFTER_HAVING_SENT_ALL_DECISIONS) {
        System.out.println(middleware.crashType.toString());
        System.exit(1);
      }
    }
    this.middleware.lockManager.UnlockAll(t.getId());
    transactionTable.remove(t);
    return true;
  }