public boolean initialise(final String config) {
    if (ActiveMQXARecoveryLogger.LOGGER.isTraceEnabled()) {
      ActiveMQXARecoveryLogger.LOGGER.trace(this + " intialise: " + config);
    }

    String[] configs = config.split(";");
    XARecoveryConfig[] xaRecoveryConfigs = new XARecoveryConfig[configs.length];
    for (int i = 0, configsLength = configs.length; i < configsLength; i++) {
      String s = configs[i];
      ConfigParser parser = new ConfigParser(s);
      String connectorFactoryClassName = parser.getConnectorFactoryClassName();
      Map<String, Object> connectorParams = parser.getConnectorParameters();
      String username = parser.getUsername();
      String password = parser.getPassword();
      TransportConfiguration transportConfiguration =
          new TransportConfiguration(connectorFactoryClassName, connectorParams);
      xaRecoveryConfigs[i] =
          new XARecoveryConfig(
              false,
              new TransportConfiguration[] {transportConfiguration},
              username,
              password,
              null,
              null);
    }

    res = new ActiveMQXAResourceWrapper(xaRecoveryConfigs);

    if (ActiveMQXARecoveryLogger.LOGGER.isTraceEnabled()) {
      ActiveMQXARecoveryLogger.LOGGER.trace(this + " initialised");
    }

    return true;
  }
  public XAResource getXAResource() {
    if (ActiveMQXARecoveryLogger.LOGGER.isTraceEnabled()) {
      ActiveMQXARecoveryLogger.LOGGER.trace(this + " getXAResource");
    }

    return res;
  }
  public boolean hasMoreResources() {
    if (ActiveMQXARecoveryLogger.LOGGER.isTraceEnabled()) {
      ActiveMQXARecoveryLogger.LOGGER.trace(this + " hasMoreResources");
    }

    /*
     * The way hasMoreResources is supposed to work is as follows:
     * For each "sweep" the recovery manager will call hasMoreResources, then if it returns
     * true it will call getXAResource.
     * It will repeat that until hasMoreResources returns false.
     * Then the sweep is over.
     * For the next sweep hasMoreResources should return true, etc.
     *
     * In our case where we only need to return one XAResource per sweep,
     * hasMoreResources should basically alternate between true and false.
     *
     *
     */

    hasMore = !hasMore;

    return hasMore;
  }
 public ActiveMQXAResourceRecovery() {
   if (trace) {
     ActiveMQXARecoveryLogger.LOGGER.trace("Constructing ActiveMQXAResourceRecovery");
   }
 }
/**
 * A XAResourceRecovery instance that can be used to recover any JMS provider.
 *
 * <p>In reality only recover, rollback and commit will be called but we still need to be implement
 * all methods just in case.
 *
 * <p>To enable this add the following to the jbossts-properties file
 *
 * <pre>
 * &lt;property name="com.arjuna.ats.jta.recovery.XAResourceRecovery.ACTIVEMQ1"
 *                 value="org.apache.activemq.artemis.jms.server.recovery.ActiveMQXAResourceRecovery;org.apache.activemq.artemis.core.remoting.impl.invm.InVMConnectorFactory"/&gt;
 * </pre>
 *
 * <p>you'll need something like this if the ActiveMQ Artemis Server is remote
 *
 * <pre>
 *      &lt;property name="com.arjuna.ats.jta.recovery.XAResourceRecovery.ACTIVEMQ2"
 *                  value="org.apache.activemq.artemis.jms.server.recovery.ActiveMQXAResourceRecovery;org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnectorFactory,guest,guest,host=localhost,port=61616"/&gt;
 * </pre>
 *
 * <p>you'll need something like this if the ActiveMQ Artemis Server is remote and has failover
 * configured
 *
 * <pre>
 *             &lt;property name="com.arjuna.ats.jta.recovery.XAResourceRecovery.ACTIVEMQ2"
 *                       value="org.apache.activemq.artemis.jms.server.recovery.ActiveMQXAResourceRecovery;org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnectorFactory,guest,guest,host=localhost,port=61616;org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnectorFactory,guest,guest,host=localhost2,port=61617"/&gt;
 * </pre>
 */
public class ActiveMQXAResourceRecovery {

  private final boolean trace = ActiveMQXARecoveryLogger.LOGGER.isTraceEnabled();

  private boolean hasMore;

  private ActiveMQXAResourceWrapper res;

  public ActiveMQXAResourceRecovery() {
    if (trace) {
      ActiveMQXARecoveryLogger.LOGGER.trace("Constructing ActiveMQXAResourceRecovery");
    }
  }

  public boolean initialise(final String config) {
    if (ActiveMQXARecoveryLogger.LOGGER.isTraceEnabled()) {
      ActiveMQXARecoveryLogger.LOGGER.trace(this + " intialise: " + config);
    }

    String[] configs = config.split(";");
    XARecoveryConfig[] xaRecoveryConfigs = new XARecoveryConfig[configs.length];
    for (int i = 0, configsLength = configs.length; i < configsLength; i++) {
      String s = configs[i];
      ConfigParser parser = new ConfigParser(s);
      String connectorFactoryClassName = parser.getConnectorFactoryClassName();
      Map<String, Object> connectorParams = parser.getConnectorParameters();
      String username = parser.getUsername();
      String password = parser.getPassword();
      TransportConfiguration transportConfiguration =
          new TransportConfiguration(connectorFactoryClassName, connectorParams);
      xaRecoveryConfigs[i] =
          new XARecoveryConfig(
              false,
              new TransportConfiguration[] {transportConfiguration},
              username,
              password,
              null,
              null);
    }

    res = new ActiveMQXAResourceWrapper(xaRecoveryConfigs);

    if (ActiveMQXARecoveryLogger.LOGGER.isTraceEnabled()) {
      ActiveMQXARecoveryLogger.LOGGER.trace(this + " initialised");
    }

    return true;
  }

  public boolean hasMoreResources() {
    if (ActiveMQXARecoveryLogger.LOGGER.isTraceEnabled()) {
      ActiveMQXARecoveryLogger.LOGGER.trace(this + " hasMoreResources");
    }

    /*
     * The way hasMoreResources is supposed to work is as follows:
     * For each "sweep" the recovery manager will call hasMoreResources, then if it returns
     * true it will call getXAResource.
     * It will repeat that until hasMoreResources returns false.
     * Then the sweep is over.
     * For the next sweep hasMoreResources should return true, etc.
     *
     * In our case where we only need to return one XAResource per sweep,
     * hasMoreResources should basically alternate between true and false.
     *
     *
     */

    hasMore = !hasMore;

    return hasMore;
  }

  public XAResource getXAResource() {
    if (ActiveMQXARecoveryLogger.LOGGER.isTraceEnabled()) {
      ActiveMQXARecoveryLogger.LOGGER.trace(this + " getXAResource");
    }

    return res;
  }

  public XAResource[] getXAResources() {
    return new XAResource[] {res};
  }

  @Override
  protected void finalize() {
    res.close();
  }

  public static class ConfigParser {

    private final String connectorFactoryClassName;

    private final Map<String, Object> connectorParameters;

    private String username;

    private String password;

    public ConfigParser(final String config) {
      if (config == null || config.length() == 0) {
        throw new IllegalArgumentException(
            "Must specify provider connector factory class name in config");
      }

      String[] strings = config.split(",");

      // First (mandatory) param is the connector factory class name
      if (strings.length < 1) {
        throw new IllegalArgumentException(
            "Must specify provider connector factory class name in config");
      }

      connectorFactoryClassName = strings[0].trim();

      // Next two (optional) parameters are the username and password to use for creating the
      // session for recovery

      if (strings.length >= 2) {

        username = strings[1].trim();
        if (username.length() == 0) {
          username = null;
        }

        if (strings.length == 2) {
          throw new IllegalArgumentException(
              "If username is specified, password must be specified too");
        }

        password = strings[2].trim();
        if (password.length() == 0) {
          password = null;
        }
      }

      // other tokens are for connector configurations
      connectorParameters = new HashMap<String, Object>();
      if (strings.length >= 3) {
        for (int i = 3; i < strings.length; i++) {
          String[] str = strings[i].split("=");
          if (str.length == 2) {
            connectorParameters.put(str[0].trim(), str[1].trim());
          }
        }
      }
    }

    public String getConnectorFactoryClassName() {
      return connectorFactoryClassName;
    }

    public Map<String, Object> getConnectorParameters() {
      return connectorParameters;
    }

    public String getUsername() {
      return username;
    }

    public String getPassword() {
      return password;
    }
  }
}