public boolean enlist(int xid, ResourceManager rm) throws RemoteException {
    if (enlistList.containsKey(xid)) {
      Set<ResourceManager> set = enlistList.get(xid);
      Iterator<ResourceManager> i = set.iterator();
      ResourceManager r = null;
      while (i.hasNext()) {
        try {
          r = i.next();
          r.getMyRMIName();
        } catch (Exception e) {
          enlistList.get(xid).remove(r);
          System.out.println("A hole in enlist.");
        }
      }
      enlistList.get(xid).add(rm);
      protocolDB.get(xid).put(rm.getMyRMIName(), rm.getStatus(xid));
    } else {
      Set<ResourceManager> set = new HashSet<ResourceManager>();
      set.add(rm);
      enlistList.put(xid, set);

      HashMap<String, TwoPC_ST> map = new HashMap<String, TwoPC_ST>();
      map.put(rm.getMyRMIName(), TwoPC_ST.Initiated);
      protocolDB.put(xid, map);
    }
    return true;
  }
 public void abortOtherRMsExcept(String rmName, int xid)
     throws RemoteException, InvalidTransactionException {
   Set<ResourceManager> set = enlistList.get(xid);
   Iterator<ResourceManager> i = set.iterator();
   ResourceManager r = null;
   while (i.hasNext()) {
     r = i.next();
     if (r.getMyRMIName().equals(rmName)) {
       enlistList.get(xid).remove(r);
       break;
     }
   }
   abort(xid);
 }
 public void sendVote(ResourceManager rm, int xid, TwoPC_ST result) throws RemoteException {
   protocolDB.get(xid).put(rm.getMyRMIName(), result);
 }
  public static void main(String args[])
      throws RemoteException, InvalidTransactionException, TransactionAbortedException {
    System.setSecurityManager(new RMISecurityManager());

    String rmiPort = System.getProperty("rmiPort");
    if (rmiPort == null) {
      rmiPort = "";
    } else if (!rmiPort.equals("")) {
      rmiPort = "//:" + rmiPort + "/";
    }

    try {
      TransactionManagerImpl obj = new TransactionManagerImpl();
      Naming.rebind(rmiPort + TransactionManager.RMIName, obj);
      System.out.println("TM bound");
    } catch (Exception e) {
      System.err.println("TM not bound:" + e);
      System.exit(1);
    }

    enlistList = new HashMap<Integer, Set<ResourceManager>>();
    File f = new File(enlistFile);
    if (f.exists()) {
      try {
        ObjectInputStream fin = new ObjectInputStream(new FileInputStream(f));
        enlistList = (HashMap<Integer, Set<ResourceManager>>) fin.readObject();
        fin.close();
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
    protocolDB = new HashMap<Integer, Map<String, TwoPC_ST>>();
    File f2 = new File(protocolDBFile);
    if (f2.exists()) {
      try {
        ObjectInputStream fin2 = new ObjectInputStream(new FileInputStream(f2));
        protocolDB = (HashMap<Integer, Map<String, TwoPC_ST>>) fin2.readObject();
        fin2.close();
      } catch (Exception e) {
        e.printStackTrace();
      }
      // recovery
      for (Integer i : protocolDB.keySet()) {
        if (i > xidCounter) {
          xidCounter = i + 1;
        }
        Map<String, TwoPC_ST> lastST = protocolDB.get(i);
        boolean re1 = true;
        for (TwoPC_ST st : lastST.values()) re1 &= (st == TwoPC_ST.Committed);
        if (re1) {
          protocolDB.remove(i);
          enlistList.remove(i);
          continue;
        }

        System.out.println("TM recovery xid: " + i + " from half commit.");
        Set<ResourceManager> commitSet = enlistList.get(i);
        boolean re2 = true;
        Set<ResourceManager> commitSet2 = new HashSet<ResourceManager>();
        for (ResourceManager r : commitSet) {
          if (r.getStatus(i) == TwoPC_ST.Prepared) {
            System.out.println("TM recovery " + i + " in " + r.getMyRMIName());
            commitSet2.add(r);
          } else if (r.getStatus(i) == TwoPC_ST.Committed) ;
          else re2 = false;
        }
        System.out.println("here 1");
        if (re2) {
          for (ResourceManager r : commitSet2) {
            r.commit(i);
          }
          protocolDB.remove(i);
          enlistList.remove(i);
        }
      }
    }
  }
  public boolean commit(int xid)
      throws RemoteException, TransactionAbortedException, InvalidTransactionException {
    System.out.println("TM starts to commit " + xid);
    if (!xidIsValid(xid)) {
      File f = new File(logFile);
      if (f.exists()) throw new TransactionAbortedException(xid, "");
      else throw new InvalidTransactionException(xid, "");
    }
    if (!enlistList.containsKey(xid)) {
      throw new TransactionAbortedException(xid, "Nonexist xid for TM.");
    }

    Set<ResourceManager> commitSet = enlistList.get(xid);
    System.out.println(xid + " TM commitSet size: " + commitSet.size());
    ResourceManager rm = null;
    Iterator<ResourceManager> i = commitSet.iterator();
    try {
      while (i.hasNext()) {
        rm = i.next();
        rm.vote(xid, TwoPC_ST.Prepared);
        rm.getMyRMIName();
        System.out.println(rm.getMyRMIName() + " in TM commit " + xid);
      }
    } catch (Exception e) {
      System.out.println("When vote, there is an exception");
      enlistList.get(xid).remove(rm);
      abort(xid);
      throw new TransactionAbortedException(xid, "invalid rm");
    }

    if (dieTMBeforeCommit) dieNow();

    // log "committed" here, and enlistList
    try {
      File logF = new File(logFile);
      FileWriter fw = new FileWriter(logF.getAbsoluteFile(), true);
      bw = new BufferedWriter(fw);
      bw.write(Integer.toString(xid));
      bw.write(" committed\n");
      bw.close();

      ObjectOutputStream protocolDBBackup =
          new ObjectOutputStream(new FileOutputStream(protocolDBFile));
      protocolDBBackup.writeObject(protocolDB);
      protocolDBBackup.close();

      ObjectOutputStream enlistFileBackup =
          new ObjectOutputStream(new FileOutputStream(enlistFile));
      enlistFileBackup.writeObject(enlistList);
      enlistFileBackup.close();
    } catch (IOException e) {
      e.printStackTrace();
    }

    if (dieTMAfterCommit) dieNow();
    for (ResourceManager r : commitSet) {
      r.commit(xid);
    }
    protocolDB.remove(xid);
    enlistList.remove(xid);
    try {
      ObjectOutputStream protocolDBBackup =
          new ObjectOutputStream(new FileOutputStream(protocolDBFile));
      protocolDBBackup.writeObject(protocolDB);
      protocolDBBackup.close(); // enlistFile

      ObjectOutputStream enlistFileBackup =
          new ObjectOutputStream(new FileOutputStream(enlistFile));
      enlistFileBackup.writeObject(enlistList);
      enlistFileBackup.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
    return true;
  }