gt:                     throw new RuntimeException();
context: /*******************************************************************************
   * Copyright (c) 2014, 2019 IBM Corporation and others.
   * All rights reserved. This program and the accompanying materials
   * are made available under the terms of the Eclipse Public License v1.0
   * which accompanies this distribution, and is available at
   * http://www.eclipse.org/legal/epl-v10.html
   *
   * Contributors:
   *     IBM Corporation - initial API and implementation
   *******************************************************************************/
  package com.ibm.tx.jta.ut.util;
  
  import java.io.EOFException;
  import java.io.File;
  import java.io.FileInputStream;
  import java.io.FileNotFoundException;
  import java.io.FileOutputStream;
  import java.io.IOException;
  import java.io.ObjectInputStream;
  import java.io.ObjectOutputStream;
  import java.io.Serializable;
  import java.net.HttpURLConnection;
  import java.net.URL;
  import java.security.AccessController;
  import java.security.PrivilegedAction;
  import java.text.SimpleDateFormat;
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.Date;
  import java.util.List;
  import java.util.UUID;
  import java.util.concurrent.ConcurrentHashMap;
  import java.util.concurrent.atomic.AtomicInteger;
  
  import javax.transaction.SystemException;
  import javax.transaction.xa.XAException;
  import javax.transaction.xa.XAResource;
  import javax.transaction.xa.Xid;
  
  import com.ibm.tx.jta.TransactionManagerFactory;
  import com.ibm.tx.jta.impl.LocalTIDTable;
  import com.ibm.ws.Transaction.JTA.Util;
  
  public class XAResourceImpl implements XAResource, Serializable {
      static final long serialVersionUID = -2141508727147091254L;
  
      protected static ConcurrentHashMap<Integer, XAResourceData> _resources = new ConcurrentHashMap<Integer, XAResourceData>();
  
      protected static StateKeeper stateKeeper;
  
      static class StateKeeperImpl implements StateKeeper {
  
          /*
           * (non-Javadoc)
           *
           * @see com.ibm.tx.jta.ut.util.StateKeeper#dumpState()
           */
          @Override
          public void dumpState() {
              printState();
              FileOutputStream fos = null;
              ObjectOutputStream oos = null;
              try {
                  System.out.println("Dumping state to " + STATE_FILE);
                  fos = new FileOutputStream(STATE_FILE);
                  if (DEBUG_OUTPUT)
                      System.out.println("Dumping state to: "
                                         + System.getProperty("user.dir"));
                  oos = new ObjectOutputStream(fos);
  
                  for (XAResourceData xares : _resources.values()) {
                      if (DEBUG_OUTPUT)
                          System.out.println("Dump Object: " + xares + ", with key: "
                                             + xares.key + ", with xid: " + xares.getXid());
                      oos.writeObject(xares);
                  }
  
              } catch (FileNotFoundException e) {
                  e.printStackTrace();
              } catch (IOException e) {
                  e.printStackTrace();
              } finally {
                  try {
                      if (oos != null) {
                          oos.flush();
                          oos.close();
                      }
                      if (fos != null)
                          fos.close();
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
              }
          }
  
          /*
           * (non-Javadoc)
           *
           * @see com.ibm.tx.jta.ut.util.StateKeeper#loadState()
           */
          @Override
          public int loadState() {
              new Throwable("com.ibm.tx.jta.ut.util.StateKeeper#loadState()").printStackTrace(System.out);;
              int resourceCount = 0;
              _commitSequence.set(0);
              ObjectInputStream ois = null;
              int resKey = 0;
              FileInputStream fos = null;
  
              try {
                  fos = new FileInputStream(STATE_FILE);
  
                  ois = new ObjectInputStream(fos);
  
                  while (true) {
                      final XAResourceData xares = (XAResourceData) ois.readObject();
                      resKey = xares.key;
                      _resources.put(resKey, xares);
                      if (resKey >= _nextKey.get()) {
                          _nextKey.set(resKey + 1);
                      }
                      resourceCount++;
                  }
              } catch (EOFException e) {
                  System.out.println("Loaded " + resourceCount + " resources");
              } catch (FileNotFoundException e) {
                  System.out.println("Loaded " + resourceCount + " resources");
              } catch (Exception e) {
                  e.printStackTrace();
              } finally {
                  try {
                      if (ois != null)
                          ois.close();
                      if (fos != null)
                          fos.close();
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
              }
  
              return resourceCount;
          }
      }
  
      static {
          stateKeeper = new StateKeeperImpl();
      }
  
      private static List<XAEvent> _XAEvents = Collections.synchronizedList(new ArrayList<XAEvent>());
  
      protected Integer _key;
  
      private static AtomicInteger _commitSequence = new AtomicInteger(0);
  
      public static AtomicInteger _nextKey = new AtomicInteger(0);
  
      public static final int RUNTIME_EXCEPTION = -1000;
      public static final int DIE = -2000;
      public static final int SLEEP_COMMIT = -3000;
      public static final int SLEEP_ROLLBACK = -4000;
      public static final int RETURN_TRUE = -5000;
      public static final int RETURN_FALSE = -6000;
  
      public static final int NOT_STARTED = 1;
      public static final int COMMITTED = 2;
      public static final int ENDED = 4;
      public static final int STARTED = 8;
      public static final int PREPARED = 16;
      public static final int ROLLEDBACK = 32;
      public static final int FORGOTTEN = 64;
      public static final int RECOVERED = 128;
      public static final int COMMITTED_ONE_PHASE = 256;
  
      protected static String STATE_FILE = "XAResourceData.dat";
  
      // This variable may be set to true to allow more chatty output.
      protected static boolean DEBUG_OUTPUT = true;
  
      private static boolean _stateLoaded;
  
      public static final int DIRECTION_COMMIT = 0, DIRECTION_ROLLBACK = 1, DIRECTION_EITHER = 2;
  
      public int getExpectedDirection() {
          return self().getExpectedDirection();
      }
  
      public XAResourceImpl setExpectedDirection(int expectedDirection) {
          self().setExpectedDirection(expectedDirection);
  
          return this;
      }
  
      public static synchronized void setStateFile(String path) {
          System.out.println("setStateFile: " + path);
          STATE_FILE = path;
      }
  
      @Override
      public boolean equals(Object o) {
          if (this == o) {
              return true;
          }
  
          if (o instanceof XAResourceImpl) {
              if (_key.equals(((XAResourceImpl) o)._key)) {
                  return true;
              }
          }
  
          return false;
      }
  
      @Override
      public int hashCode() {
          return _key.hashCode();
      }
  
      public static int transactionCount() {
          final Object[] trans = LocalTIDTable.getAllTransactions();
  
          if (trans == null) {
              return 0;
          } else {
              return trans.length;
          }
      }
  
      public static int committedCount() {
          int committedCount = 0;
          for (XAResourceData res : _resources.values()) {
  
              if (res.inState(COMMITTED)) {
                  System.out.println("commitedCount: Resource " + res.key + " is in state COMMITTED");
                  committedCount++;
              } else {
                  System.out.println("commitedCount: Resource " + res.key + " is not in state COMMITTED");
              }
          }
          return committedCount;
      }
  
      public class XAResourceData implements Serializable {
          private static final long serialVersionUID = -253646295143893358L;
  
          public final int key;
          private UUID RM;
          private int prepareAction = XAResource.XA_OK;
          private int rollbackAction = XAResource.XA_OK;
          private int commitAction = XAResource.XA_OK;
          private int endAction = XAResource.XA_OK;
          private int startAction = XAResource.XA_OK;
          private int forgetAction = XAResource.XA_OK;
          private int recoverAction = XAResource.XA_OK;
          private int setTransactionTimeoutAction = RETURN_TRUE;
          private int expectedDirection = DIRECTION_EITHER;
          private int commitRepeatCount;
          private int rollbackRepeatCount;
          private int forgetRepeatCount;
          private int recoverRepeatCount;
          private int statusDuringCommit;
          private int statusDuringRollback;
          private int statusDuringPrepare;
          private int rollbackCount;
          private int forgetCount;
          private boolean heuristic;
          private int _sleepTime;
          private Xid _xid;
          private int _state = NOT_STARTED;
          private boolean busyInLongRunningQuery;
          private boolean queryAborted;
          private boolean commitSuicide = true;
          private final String stateFile;
  
          URL doomedServer;
  
          private int _commitOrder;
  
          public void setDoomedServer(URL url) {
              doomedServer = url;
          }
  
          public int getExpectedDirection() {
              return expectedDirection;
          }
  
          public void setExpectedDirection(int expectedDirection) {
              StringBuffer sb = new StringBuffer("setExpectedDirection(")
                              .append(_key)
                              .append(", ");
                              
              if (expectedDirection == DIRECTION_COMMIT) {
                  sb.append("commit");
              } else if (expectedDirection == DIRECTION_ROLLBACK) {
                  sb.append("rollback");
              } else if (expectedDirection == DIRECTION_EITHER) {
                  sb.append("either");
              }
              sb.append(")");
              System.out.println(sb.toString());
  
              this.expectedDirection = expectedDirection;
          }
  
          public URL getDoomedServer() {
              return doomedServer;
          }
  
          public void setCommitSuicide(boolean b) {
              commitSuicide = b;
          }
  
          public boolean getCommitSuicide() {
              return commitSuicide;
          }
  
          public void setSleepTime(int sleepTime) {
              _sleepTime = sleepTime;
          }
  
          public int getSleepTime() {
              return _sleepTime;
          }
  
          public Xid getXid() {
              return _xid;
          }
  
          public void setXid(Xid xid) {
              System.out.println("setXid(" + _key + ", " + xid + ")");
  
              _xid = new TestXidImpl(xid);
          }
  
          public int getState() {
              return _state;
          }
  
          public void setState(int state) {
              _state |= state;
          }
  
          public XAResourceData(int i) {
              key = i;
              RM = UUID.randomUUID();
              stateFile = STATE_FILE;
          }
  
          public int getCommitAction() {
              return commitAction;
          }
  
          public void setCommitAction(int commitAction) {
              System.out.println("setCommitAction(" + _key + ", " + actionFormatter(commitAction) + ")");
              this.commitAction = commitAction;
          }
  
          public int getSetTransactionTimeoutAction() {
              return setTransactionTimeoutAction;
          }
  
          public void setSetTransactionTimeoutAction(int action) {
              setTransactionTimeoutAction = action;
          }
  
          public int getPrepareAction() {
              return prepareAction;
          }
  
          public void setPrepareAction(int prepareAction) {
              System.out.println("setPrepareAction(" + _key + ", " + actionFormatter(prepareAction) + ")");
              this.prepareAction = prepareAction;
          }
  
          public UUID getRM() {
              return RM;
          }
  
          public void setRM(UUID rm) {
              RM = rm;
          }
  
          public int getRollbackAction() {
              return rollbackAction;
          }
  
          public void setRollbackAction(int rollbackAction) {
              System.out.println("setRollbackAction(" + _key + ", " + actionFormatter(rollbackAction) + ")");
              this.rollbackAction = rollbackAction;
          }
  
          public int getRecoverAction() {
              return recoverAction;
          }
  
          public void setRecoverAction(int recoverAction) {
              System.out.println("setRecoverAction(" + _key + ", " + actionFormatter(recoverAction) + ")");
              this.recoverAction = recoverAction;
          }
  
          public int getStatusDuringCommit() {
              return statusDuringCommit;
          }
  
          public void setStatusDuringCommit(int statusDuringCommit) {
              this.statusDuringCommit = statusDuringCommit;
          }
  
          public int getStatusDuringRollback() {
              return statusDuringRollback;
          }
  
          public void setStatusDuringRollback(int statusDuringRollback) {
              this.statusDuringRollback = statusDuringRollback;
          }
  
          public int getStatusDuringPrepare() {
              return statusDuringPrepare;
          }
  
          public void setStatusDuringPrepare(int statusDuringPrepare) {
              this.statusDuringPrepare = statusDuringPrepare;
          }
  
          public boolean isForgotten() {
              return (_state & FORGOTTEN) != 0;
          }
  
          public boolean isHeuristic() {
              return heuristic;
          }
  
          public void setHeuristic(boolean heuristic) {
              this.heuristic = heuristic;
          }
  
          public int getEndAction() {
              return endAction;
          }
  
          public void setEndAction(int endAction) {
              this.endAction = endAction;
          }
  
          public int getCommitRepeatCount() {
              return commitRepeatCount;
          }
  
          public void setCommitRepeatCount(int commitRepeatCount) {
              this.commitRepeatCount = commitRepeatCount;
          }
  
          public int getRecoverRepeatCount() {
              return recoverRepeatCount;
          }
  
          public void setRecoverRepeatCount(int recoverRepeatCount) {
              System.out.println("setRecoverRepeatCount(" + _key + ", " + recoverRepeatCount + ")");
              this.recoverRepeatCount = recoverRepeatCount;
          }
  
          public int getForgetRepeatCount() {
              return forgetRepeatCount;
          }
  
          public void setForgetRepeatCount(int forgetRepeatCount) {
              this.forgetRepeatCount = forgetRepeatCount;
          }
  
          public int getForgetAction() {
              return forgetAction;
          }
  
          public void setForgetAction(int forgetAction) {
              this.forgetAction = forgetAction;
          }
  
          public int getRollbackCount() {
              return rollbackCount;
          }
  
          public void setRollbackCount(int rollbackCount) {
              this.rollbackCount = rollbackCount;
          }
  
          public int getRollbackRepeatCount() {
              return rollbackRepeatCount;
          }
  
          public void setRollbackRepeatCount(int rollbackRepeatCount) {
              this.rollbackRepeatCount = rollbackRepeatCount;
          }
  
          public int getStartAction() {
              return startAction;
          }
  
          public void setStartAction(int startAction) {
              this.startAction = startAction;
          }
  
          public int getForgetCount() {
              return forgetCount;
          }
  
          public void setForgetCount(int forgetCount) {
              this.forgetCount = forgetCount;
          }
  
          public boolean inState(int state) {
              return (_state & state) != 0;
          }
  
          public void setAmBusyInLongRunningQuery(boolean busy) {
              this.busyInLongRunningQuery = busy;
          }
  
          public boolean isBusyInLongRunningQuery() {
              return this.busyInLongRunningQuery;
          }
  
          public void setQueryAborted() {
              this.queryAborted = true;
          }
  
          public boolean isQueryAborted() {
              return this.queryAborted;
          }
  
          @Override
          public String toString() {
              StringBuffer sb = new StringBuffer("Resource: " + key + "\n");
              sb.append("State: " + stateFormatter(_state));
              sb.append("\nXid: " + _xid);
              sb.append("\nCommit order: " + _commitOrder);
  
  /*
   * private UUID RM;
   * private int prepareAction = XAResource.XA_OK;
   * private int rollbackAction = XAResource.XA_OK;
   * private int commitAction = XAResource.XA_OK;
   * private int endAction = XAResource.XA_OK;
   * private int startAction = XAResource.XA_OK;
   * private int forgetAction = XAResource.XA_OK;
   * private int recoverAction = XAResource.XA_OK;
   * private int setTransactionTimeoutAction = RETURN_TRUE;
   * private int commitRepeatCount;
   * private int rollbackRepeatCount;
   * private int forgetRepeatCount;
   * private int recoverRepeatCount;
   * private int statusDuringCommit;
   * private int statusDuringRollback;
   * private int statusDuringPrepare;
   * private int rollbackCount;
   * private int forgetCount;
   * private boolean heuristic;
   * private int _sleepTime;
   * private Xid _xid;
   * private boolean busyInLongRunningQuery;
   * private boolean queryAborted;
   * private boolean commitSuicide = true;
   */
              return sb.toString();
          }
  
          private String stateFormatter(int state) {
              StringBuffer sb = new StringBuffer("NOT STARTED");
  
              if (inState(STARTED)) {
                  sb.append(", STARTED");
              }
              if (inState(ENDED)) {
                  sb.append(", ENDED");
              }
              if (inState(PREPARED)) {
                  sb.append(", PREPARED");
              }
              if (inState(COMMITTED)) {
                  sb.append(", COMMITTED");
              }
              if (inState(ROLLEDBACK)) {
                  sb.append(", ROLLEDBACK");
              }
              if (inState(FORGOTTEN)) {
                  sb.append(", FORGOTTEN");
              }
              if (inState(RECOVERED)) {
                  sb.append(", RECOVERED");
              }
              if (inState(COMMITTED_ONE_PHASE)) {
                  sb.append(", COMMITTED_ONE_PHASE");
              }
              
              return sb.toString();
          }
  
          class TestXidImpl implements Xid, Serializable {
  
              /**
              	 *
              	 */
              private static final long serialVersionUID = 1747768416841464440L;
  
              //
              // The format identifier for the Xid. A value of -1 indicates
              // that the NULL Xid
              //
              final protected int _formatId;
  
              //
              // Holds the Global Transaction ID for this Xid
              //
              final protected byte[] _gtrid;
  
              //
              // Holds the Branch Qualifier for this Xid
              //
              final protected byte[] _bqual;
  
              /**
               * Xid copy constructor that is used during recovery
               * and only used for Xids with our formatId.
               */
              public TestXidImpl(Xid xid) {
                  this._formatId = xid.getFormatId();
                  this._gtrid = Util.duplicateByteArray(xid.getGlobalTransactionId());
                  this._bqual = Util.duplicateByteArray(xid.getBranchQualifier());
              }
  
              @Override
              public byte[] getBranchQualifier() {
                  return _bqual;
              }
  
              @Override
              public int getFormatId() {
                  return _formatId;
              }
  
              @Override
              public byte[] getGlobalTransactionId() {
                  return _gtrid;
              }
  
              @Override
              public String toString() {
                  return "Format id: " + Integer.toHexString(_formatId) + "\n" +
                         "\tGtrid: " + Util.toHexString(_gtrid) + "\n" +
                         "\tBqual: " + Util.toHexString(_bqual);
              }
          }
  
          public int getCommitOrder() {
              return _commitOrder;
          }
  
          /**
           * @param commitOrder
           */
          public void setCommitOrder(int commitOrder) {
              _commitOrder = commitOrder;
          }
      }
  
      public XAResourceImpl() {
          synchronized (_resources) {
              _key = _nextKey.getAndIncrement();
              System.out.println("Constructing XAResourceImpl: " + _key);
              _resources.put(_key, new XAResourceData(_key));
          }
      }
  
      public XAResourceImpl(int i) {
          synchronized (_resources) {
              _key = i;
              if (!_resources.containsKey(i)) {
                  System.out.println("Constructing XAResourceImpl: " + _key);
                  _resources.put(_key, new XAResourceData(_key));
                  if (i >= _nextKey.get()) {
                      _nextKey.set(i + 1);
                  }
              } else {
                  System.out.println("XAResourceImpl exists already: " + _key);
              }
          }
      }
  
      public static XAResourceImpl getXAResourceImpl(int key) {
          return new XAResourceImpl(key);
      }
  
      @Override
      public void commit(Xid xid, boolean onePhase) throws XAException {
          System.out.println("commit(" + _key + ", " + xid + ", " + onePhase
                             + ")");
  
          self().setCommitOrder(_commitSequence.incrementAndGet());
  
          System.out.println("Commit order is " + self().getCommitOrder());
  
          _XAEvents.add(new XAEvent(XAEventCode.COMMIT, _key));
  
          try {
              if (DEBUG_OUTPUT) {
                  System.out.println("commit working against " + self());
                  System.out.println("commit using TM "
                                     + TransactionManagerFactory.getTransactionManager());
              }
              self().setStatusDuringCommit(
                                           TransactionManagerFactory.getTransactionManager()
                                                           .getStatus());
          } catch (SystemException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
          }
  
          final int commitAction = self().getCommitAction();
          if (commitAction != XAResource.XA_OK) {
              final int repeatCount = self().getCommitRepeatCount();
              self().setCommitRepeatCount(repeatCount - 1);
              if (repeatCount >= 0) {
                  switch (commitAction) {
                      case RUNTIME_EXCEPTION:
                          throw new RuntimeException();
  
                      case DIE:
                          System.out.println("Calling DIE on commit(" + _key + ", "
                                             + xid + ", " + onePhase + ")");
                          try {
                              killDoomedServers(true);
                          } catch (SecurityException se) {
                              System.out.println("Caught Security Exc: " + se
                                                 + " on commit(" + _key + ", " + xid + ", "
                                                 + onePhase + ")");
                          }
  
                      case SLEEP_COMMIT:
                          try {
                              Thread.sleep(self().getSleepTime());
                          } catch (InterruptedException e) {
                              // TODO Auto-generated catch block
                              e.printStackTrace();
                          }
                          break;
  
                      default:
                          throw new XAException(commitAction);
                  }
              }
          }
  
          if (self().getExpectedDirection() != DIRECTION_COMMIT && self().getExpectedDirection() != DIRECTION_EITHER) {
              System.out.println("Commit is not the expected direction! Test failed.");
              throw new XAException("Test failed because of wrong direction. Commit is not the expected direction.");
          }
  
          setState(COMMITTED);
          if (onePhase) {
              setState(COMMITTED_ONE_PHASE);
          }
          System.out.println("committed(" + _key + ", " + xid + ", " + onePhase
                             + ")");
      }
  
      private void killDoomedServers(boolean dumpState) {
          URL doomedServer = self().getDoomedServer();
          if (doomedServer != null) {
              // Kill the other guy
              System.out.println("killDoomedServers: " + doomedServer.toString());
              HttpURLConnection conn = null;
              try {
                  conn = (HttpURLConnection) doomedServer.openConnection();
                  conn.setDoInput(true);
                  conn.setDoOutput(true);
                  conn.setConnectTimeout(10000);
                  conn.setReadTimeout(10000);
                  conn.setRequestMethod("GET");
                  // Get a connection to the server & retrieve the output stream
                  conn.connect();
                  //OutputStream out = conn.getOutputStream();
                  int response_code = conn.getResponseCode();
                  if (response_code == HttpURLConnection.HTTP_OK) {
                      conn.getInputStream();
                      System.out.println("Should not reach here.");
                  }
              } catch (Exception e) {
                  //we want to get here!!
                  e.printStackTrace();
                  if (conn != null)
                      conn.disconnect();
                  System.out.println("Get expected exception in killServer " + e.toString());
              }
  
          }
  
          if (self().getCommitSuicide()) {
  //			Log.info(getClass(), "killDoomedServers", "Uh oh");
              if (dumpState) {
                  dumpState();
              }
              Runtime.getRuntime().halt(DIE);
          }
      }
  
      @Override
      public void end(Xid xid, int flags) throws XAException {
          System.out.println("end(" + _key + ", " + xid + ", " + flags + ")");
  
          _XAEvents.add(new XAEvent(XAEventCode.END, _key));
  
          final int endAction = self().getEndAction();
          if (endAction != XAResource.XA_OK) {
              switch (endAction) {
                  case RUNTIME_EXCEPTION:
  