Package org.objectweb.joram.client.connector

Source Code of org.objectweb.joram.client.connector.JoramAdapter

/*
* JORAM: Java(TM) Open Reliable Asynchronous Messaging
* Copyright (C) 2004 - 2011 ScalAgent Distributed Technologies
* Copyright (C) 2004 - 2006 Bull SA
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
* USA.
*
* Initial developer(s): Frederic Maistre (Bull SA)
* Contributor(s): ScalAgent Distributed Technologies
*                 Benoit Pelletier (Bull SA)
*/
package org.objectweb.joram.client.connector;

import java.io.FileNotFoundException;
import java.lang.reflect.Method;
import java.net.ConnectException;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.Vector;

import javax.jms.ExceptionListener;
import javax.jms.JMSException;
import javax.jms.Session;
import javax.jms.XAConnection;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.resource.NotSupportedException;
import javax.resource.ResourceException;
import javax.resource.spi.ActivationSpec;
import javax.resource.spi.BootstrapContext;
import javax.resource.spi.CommException;
import javax.resource.spi.IllegalStateException;
import javax.resource.spi.ResourceAdapter;
import javax.resource.spi.ResourceAdapterInternalException;
import javax.resource.spi.endpoint.MessageEndpointFactory;
import javax.resource.spi.work.WorkManager;
import javax.transaction.xa.XAResource;

import org.objectweb.joram.client.jms.ConnectionFactory;
import org.objectweb.joram.client.jms.ConnectionMetaData;
import org.objectweb.joram.client.jms.Destination;
import org.objectweb.joram.client.jms.Queue;
import org.objectweb.joram.client.jms.Topic;
import org.objectweb.joram.client.jms.admin.AdminException;
import org.objectweb.joram.client.jms.admin.AdminModule;
import org.objectweb.joram.client.jms.admin.User;
import org.objectweb.joram.client.jms.ha.local.HALocalConnectionFactory;
import org.objectweb.joram.client.jms.ha.tcp.HATcpConnectionFactory;
import org.objectweb.joram.client.jms.local.LocalConnectionFactory;
import org.objectweb.joram.client.jms.tcp.TcpConnectionFactory;
import org.objectweb.joram.shared.security.SimpleIdentity;
import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;

import com.scalagent.jmx.JMXServer;

import fr.dyade.aaa.agent.AgentServer;
import fr.dyade.aaa.common.Debug;
import fr.dyade.aaa.util.management.MXWrapper;

/**
* A <code>JoramAdapter</code> instance manages connectivities to an underlying
* JORAM server: outbound connectivity (JCA connection management contract) and
* inbound connectivity (asynchronous message delivery as specified by the JCA
* message inflow contract).
*/
public final class JoramAdapter implements ResourceAdapter, JoramAdapterMBean, ExceptionListener {
  /** Define serialVersionUID for interoperability. */
  private static final long serialVersionUID = 1L;

  public static Logger logger = Debug.getLogger(JoramAdapter.class.getName());

  /** <code>true</code> if the adapter has been started. */
  private boolean started = false;
  /** <code>true</code> if the adapter has been stopped. */
  private boolean stopped = false;
 
  /** <code>true</code> if admin connection connection is active. */
  private boolean isActive = false;
  /** The duration of admin connection before change state.*/
  private long adminDurationState = 0;

  // ------------------------------------------
  // --- JavaBean setter and getter methods ---
  // ------------------------------------------

  /** <code>true</code> if the underlying JORAM server is collocated. */
  boolean collocated = false;

  public void setCollocatedServer(Boolean collocatedServer) {
    collocated = collocatedServer.booleanValue();
  }

  public Boolean getCollocatedServer() {
    return new Boolean(collocated);
  }

  /** Host name or IP of the underlying JORAM server. */
  String hostName = "localhost";

  public String getHostName() {
    return hostName;
  }

  public void setHostName(String hostName) {
    this.hostName = hostName;
  }

  /** Port number of the underlying JORAM server. */
  int serverPort = 16010;

  public Integer getServerPort() {
    return new Integer(serverPort);
  }

  public void setServerPort(Integer serverPort) {
    this.serverPort = serverPort.intValue();
  }

  /** URL hajoram (for collocated mode). */
  String haURL = null;

  public String getHAURL() {
    return haURL;
  }

  public void setHAURL(String haURL) {
    this.haURL = haURL;
  }

  /** login name for administrator. */
  String rootName = "root";

  public String getRootName() {
    return rootName;
  }

  public void setRootName(String rn) {
    rootName = rn;
  }

  /** password for administrator */
  String rootPasswd = "root";
 
  public String getRootPasswd() {
    return rootPasswd;
  }

  public void setRootPasswd(String rp) {
    rootPasswd = rp;
  }
 
  /** Identity class needed for authentication */
  String identityClass = SimpleIdentity.class.getName();

  public String getIdentityClass() {
    return identityClass;
  }

  public void setIdentityClass(String identityClass) {
    this.identityClass = identityClass;
  }

  /** Identifier of the JORAM server to start. */
  short serverId = 0;

  public Short getServerId() {
    return new Short(serverId);
  }
 
  public void setServerId(Short serverId) {
    this.serverId = serverId.shortValue();
  }

  /** Name of the JORAM server to start. */
  private String serverName = "s0";

  public String getServerName() {
    return serverName;
  }

  public void setServerName(String serverName) {
    this.serverName = serverName;
  }

  /** Identifier of the JORAM replica to start in case of HA. */
  short clusterId = AgentServer.NULL_ID;

  /** <code>true</code> if the underlying a JORAM HA server is defined */
  boolean isHa = false;

  public Short getClusterId() {
    return new Short(clusterId);
  }
 
  public void setClusterId(Short clusterId) {
    this.clusterId = clusterId.shortValue();
    if (this.clusterId != AgentServer.NULL_ID){
      this.isHa = true;
    }
  }

  /**
   * Path to the directory containing JORAM's configuration files
   * (<code>a3servers.xml</code>, <code>a3debug.cfg</code>
   * and admin file), needed when starting the collocated JORAM server.
   */
  private String platformConfigDir;

  public String getPlatformConfigDir() {
    return platformConfigDir;
  }
 
  public void setPlatformConfigDir(String platformConfigDir) {
    this.platformConfigDir = platformConfigDir;
  }

  /** <code>true</code> if the JORAM server to start is persistent. */
  private boolean persistentPlatform = false;

  public Boolean getPersistentPlatform() {
    return new Boolean(persistentPlatform);
  }

  public void setPersistentPlatform(Boolean persistentPlatform) {
    this.persistentPlatform = persistentPlatform.booleanValue();
  }

  /**
   * Path to the XML file containing a description of the administered objects to
   * create and bind.
   */
  private String adminFileXML = "joramAdmin.xml";
 
  /**
   * Returns the path of XML the file containing a description of the administered
   * objects to create and bind at starting.
   */
  public String getAdminFileXML() {
    return adminFileXML;
  }

  /**
   * Sets the path of the XML file containing a description of the administered
   * objects to create and bind at starting.
   */
  public void setAdminFileXML(String adminFileXML) {
    this.adminFileXML = adminFileXML;
  }

  /**
   * Path to the XML file containing a description of the exported administered
   * objects (destination) from the platform.
   */
  private String adminFileExportXML = "joramAdminExport.xml";

  /**
   * Returns the path of XML the file containing a description of the exported
   * administered objects (destination) from the platform.
   */
  public String getAdminFileExportXML() {
    return adminFileExportXML;
  }

  /**
   * Sets the path of the XML file containing a description of the exported
   * administered objects (destination) from the platform.
   */
  public void setAdminFileExportXML(String adminFileExportXML) {
    this.adminFileExportXML = adminFileExportXML;
  }
 
  /**
   * Duration in seconds during which connecting is attempted (connecting
   * might take time if the server is temporarily not reachable); the 0 value
   * is set for connecting only once and aborting if connecting failed.
   */
  public int connectingTimer = 0;

  public Integer getConnectingTimer() {
    return new Integer(connectingTimer);
  }

  public void setConnectingTimer(Integer connectingTimer) {
    this.connectingTimer = connectingTimer.intValue();
  }

  /**
   * Duration in seconds during which a JMS transacted (non XA) session might
   * be pending; above that duration the session is rolled back and closed;
   * the 0 value means "no timer".
   */
  public int txPendingTimer = 0;

  public Integer getTxPendingTimer() {
    return new Integer(txPendingTimer);
  }
 
  public void setTxPendingTimer(Integer txPendingTimer) {
    this.txPendingTimer = txPendingTimer.intValue();
  }

  /**
   * Period in milliseconds between two ping requests sent by the client
   * connection to the server; if the server does not receive any ping
   * request during more than 2 * cnxPendingTimer, the connection is
   * considered as dead and processed as required.
   */
  public int cnxPendingTimer = 0;

  public Integer getCnxPendingTimer() {
    return new Integer(cnxPendingTimer);
  }

  public void setCnxPendingTimer(Integer cnxPendingTimer) {
    this.cnxPendingTimer = cnxPendingTimer.intValue();
  }

  /**
   * The maximum number of messages that can be
   * read at once from a queue.
   *
   * Default value is 2 in order to compensate
   * the former subscription mechanism.
   */
  public int queueMessageReadMax = 2;

  public Integer getQueueMessageReadMax() {
    return new Integer(queueMessageReadMax);
  }

  public void setQueueMessageReadMax(Integer queueMessageReadMax) {
    this.queueMessageReadMax = queueMessageReadMax.intValue();
  }

  /**
   * The maximum number of acknowledgements
   * that can be buffered in
   * Session.DUPS_OK_ACKNOWLEDGE mode when listening to a topic.
   * Default is 0.
   */
  public int topicAckBufferMax = 0;

  public Integer getTopicAckBufferMax() {
    return new Integer(topicAckBufferMax);
  }

  public void setTopicAckBufferMax(Integer topicAckBufferMax) {
    this.topicAckBufferMax = topicAckBufferMax.intValue();
  }

  /**
   * This threshold is the maximum messages
   * number over
   * which the subscription is passivated.
   * Default is Integer.MAX_VALUE.
   */
  public int topicPassivationThreshold = Integer.MAX_VALUE;

  public Integer getTopicPassivationThreshold() {
    return new Integer(topicPassivationThreshold);
  }

  public void setTopicPassivationThreshold(Integer topicPassivationThreshold) {
    this.topicPassivationThreshold = topicPassivationThreshold.intValue();
  }

  /**
   * This threshold is the minimum
   * messages number below which
   * the subscription is activated.
   * Default is 0.
   */
  public int topicActivationThreshold = 0;

  public Integer getTopicActivationThreshold() {
    return new Integer(topicActivationThreshold);
  }

  public void setTopicActivationThreshold(Integer topicActivationThreshold) {
    this.topicActivationThreshold = topicActivationThreshold.intValue();
  }

  /**
   * Determines whether the produced messages are asynchronously
   * sent or not (without or with acknowledgement)
   * Default is false (with ack).
   */
  public boolean asyncSend = false;

  public Boolean getAsyncSend() {
    return new Boolean(asyncSend);
  }

  public void setAsyncSend(Boolean asyncSend) {
    this.asyncSend = asyncSend.booleanValue();
  }

  /**
   * Determines whether client threads
   * which are using the same connection
   * are synchronized in order to group
   * together the requests they send.
   * Default is false.
   */
  public boolean multiThreadSync = false;

  public Boolean getMultiThreadSync() {
    return new Boolean(multiThreadSync);
  }

  public void setMultiThreadSync(Boolean multiThreadSync) {
    this.multiThreadSync = multiThreadSync.booleanValue();
  }

  /**
   * The maximum time the threads hang if 'multiThreadSync' is true.
   * Either they wake up (wait time out) or they are notified (by the
   * first woken up thread).
   * <p>
   * Default is 1 ms.
   */
  public int multiThreadSyncDelay = 1;

  public Integer getMultiThreadSyncDelay() {
    return new Integer(multiThreadSyncDelay);
  }

  public void setMultiThreadSyncDelay(Integer multiThreadSyncDelay) {
    this.multiThreadSyncDelay = multiThreadSyncDelay.intValue();
  }

  /**
   * Determine whether durable subscription must be deleted or not
   * at close time of the InboundConsumer.
   * <p>
   * Default is false.
   */
  public boolean deleteDurableSubscription  = false;

  /**
   * Returns the deleteDurableSubscription attribute.
   *
   * @return the DeleteDurableSubscription
   *
   * @see #deleteDurableSubscription
   */
  public Boolean  getDeleteDurableSubscription() {
    return new Boolean(deleteDurableSubscription);
  }

  /**
   * Set the deleteDurableSubscription attribute.
   *
   * @param flg to set deleteDurableSubscription
   *
   * @see #deleteDurableSubscription
   */
  public void setDeleteDurableSubscription(Boolean flg) {
    this.deleteDurableSubscription = flg.booleanValue();
  }

  public JMXServer jmxServer;
 
  public void setJmxServer(MBeanServer jmxServer) {
    this.jmxServer = new JMXServer(jmxServer);
  }

  /** Name of the root in the MBean tree */
  private static String jmxRootName = "joramClient";

  /** Names of the bound objects. */
  private static Vector boundNames = new Vector();

  /** <code>WorkManager</code> instance provided by the application server. */
  private transient WorkManager workManager;

  public void setWorkManager(WorkManager workManager) {
    this.workManager = workManager;
  }

  /**
   * Table holding the adapter's <code>InboundConsumer</code> instances,
   * for inbound messaging.
   * <p>
   * <b>Key:</b> <code>ActivationSpec</code> instance<br>
   * <b>Value:</b> <code>InboundConsumer</code> instance
   */
  private transient Hashtable consumers = new Hashtable();

  /**
   * Vector holding the <code>ManagedConnectionImpl</code> instances for
   * managed outbound messaging.
   */
  private transient Vector producers = new Vector();

  /**
   * Table holding the adapter's <code>XAConnection</code> instances used for
   * recovering the XA resources.
   * <p>
   * <b>Key:</b> user name<br>
   * <b>Value:</b> <code>XAConnection</code> instance
   */
  private transient Hashtable connections;

  /**
   * Constructs a <code>JoramAdapter</code> instance.
   */
  public JoramAdapter() {
    if (logger.isLoggable(BasicLevel.INFO))
      logger.log(BasicLevel.INFO, "JORAM adapter instantiated.");

    java.util.ArrayList array = MBeanServerFactory.findMBeanServer(null);
    if (!array.isEmpty()) {
      setJmxServer((MBeanServer) array.get(0));
    }
  }

  /**
   * Constructs a <code>JoramAdapter</code> instance.
   */
  public JoramAdapter(MBeanServer jmxServer) {
    if (logger.isLoggable(BasicLevel.INFO))
      logger.log(BasicLevel.INFO, "JORAM adapter instantiated.");
    setJmxServer(jmxServer);
  }

  /**
   * Initializes the adapter; starts, if needed, a collocated JORAM server,
   * and if needed again, administers it.
   *
   * @exception ResourceAdapterInternalException  If the adapter could not be
   *                                              initialized.
   */
  public synchronized void start(BootstrapContext ctx) throws ResourceAdapterInternalException {
    setWorkManager(ctx.getWorkManager());
    start();
  }
   
  public synchronized void start() throws ResourceAdapterInternalException {
    if (started)
      throw new ResourceAdapterInternalException("Adapter already started.");
    if (stopped)
      throw new ResourceAdapterInternalException("Adapter has been stopped.");

    if (workManager == null) {
      throw new ResourceAdapterInternalException("WorkManager has not been set.");
    }

    // set HA mode if needed
    AdminModule.setHa(isHa);

    if (logger.isLoggable(BasicLevel.INFO))
      logger.log(BasicLevel.INFO, "JORAM adapter starting deployment...");

    // Collocated mode: starting the JORAM server.
    if (collocated) {
      if (logger.isLoggable(BasicLevel.INFO))
        logger.log(BasicLevel.INFO, " - Collocated JORAM server is starting...");

      // TODO (AF): Setting system properties forbids the launching of multiples
      // servers in an OSGi platform.
      if (persistentPlatform) {
        System.setProperty("Transaction", "fr.dyade.aaa.util.NTransaction");
        System.setProperty("NTNoLockFile", "true");
      } else {
        System.setProperty("Transaction", "fr.dyade.aaa.util.NullTransaction");
        System.setProperty("NbMaxAgents", "" + Integer.MAX_VALUE);
      }

      if (platformConfigDir != null) {
        System.setProperty(AgentServer.CFG_DIR_PROPERTY, platformConfigDir);
        System.setProperty(Debug.DEBUG_DIR_PROPERTY, platformConfigDir);
      }

      try {
        AgentServer.init(serverId, serverName, null, clusterId);
        AgentServer.start();
        if (logger.isLoggable(BasicLevel.INFO))
          logger.log(BasicLevel.INFO, "JoramAdapter - Collocated JORAM server has successfully started.");
      } catch (Exception exc) {
        AgentServer.stop();
        AgentServer.reset(true);

        throw new ResourceAdapterInternalException("Could not start collocated JORAM instance: " + exc);
      }
    }

    // Starting an admin session...
    try {
      adminConnect();
      serverId = (short) AdminModule.getLocalServerId();
    } catch (Exception exc) {
      if (logger.isLoggable(BasicLevel.WARN))
        logger.log(BasicLevel.WARN, " - JORAM server not administerable: " + exc);
    }

    // Execute the XML script of configuration.
    try {
      if (logger.isLoggable(BasicLevel.INFO))
        logger.log(BasicLevel.INFO, "  - Reading the provided admin file: " + adminFileXML);
      AdminModule.executeXMLAdmin(platformConfigDir, adminFileXML);
    } catch (FileNotFoundException exc) {
      if (logger.isLoggable(BasicLevel.INFO))
        logger.log(BasicLevel.INFO, "JoramAdapter - problem during XML configuration: " + adminFileExportXML);
    } catch (Exception exc) {
      if (logger.isLoggable(BasicLevel.ERROR))
        logger.log(BasicLevel.ERROR, "JoramAdapter - problem during XML configuration: " + adminFileExportXML, exc);
    }

    // Execute the XML script corresponding to the export of the configuration.
    try {
      if (logger.isLoggable(BasicLevel.INFO))
        logger.log(BasicLevel.INFO, "  - Reading the provided admin file: " + adminFileExportXML);
      AdminModule.executeXMLAdmin(platformConfigDir, adminFileExportXML);
    } catch (FileNotFoundException exc) {
      if (logger.isLoggable(BasicLevel.INFO))
        logger.log(BasicLevel.INFO, "JoramAdapter - problem during XML configuration: " + adminFileExportXML);
    } catch (Exception exc) {
      if (logger.isLoggable(BasicLevel.ERROR))
        logger.log(BasicLevel.ERROR, "JoramAdapter - problem during XML configuration: " + adminFileExportXML, exc);
    }

    if (logger.isLoggable(BasicLevel.INFO))
      logger.log(BasicLevel.INFO, "Server port is " + serverPort);

    started = true;

    if (logger.isLoggable(BasicLevel.INFO))
      logger.log(BasicLevel.INFO, "JORAM adapter " + ConnectionMetaData.providerVersion + " successfully deployed.");
  }

  /**
   * Initiates an admin session.
   *
   * @exception AdminException  If the admin session could not be started.
   */
  void adminConnect() throws AdminException {
    try {
      org.objectweb.joram.client.jms.ConnectionFactory cf;

      if (isHa) {
        if (collocated) {
          if (logger.isLoggable(BasicLevel.DEBUG))
            logger.log(BasicLevel.DEBUG, "haURL = " + haURL);
          if (haURL != null) {
            cf = HATcpConnectionFactory.create(haURL);
          } else {
            cf = HALocalConnectionFactory.create();
          }
        } else {
          String urlHa = "hajoram://" + hostName + ":" + serverPort;
          cf = HATcpConnectionFactory.create(urlHa);
        }
      } else {
        if (collocated)
          cf = LocalConnectionFactory.create();
        else
          cf = TcpConnectionFactory.create(hostName, serverPort);
      }

      if (connectingTimer == 0)
        cf.getParameters().connectingTimer = 60;
      else
        cf.getParameters().connectingTimer = connectingTimer;

      AdminModule.connect(cf, rootName, rootPasswd, identityClass);
      if (!isActive)
        adminDurationState = System.currentTimeMillis();
      isActive = true;
     
      // Registering MBeans...
      try {
        jmxServer.registerMBean(this, MXWrapper.objectName(jmxRootName, "type=JoramAdapter"));
      } catch (Exception e) {
        if (logger.isLoggable(BasicLevel.WARN))
          logger.log(BasicLevel.WARN, "  - Could not register JoramAdapterMBean", e);
      }
    } catch (ConnectException exc) {
      if (isActive)
        adminDurationState = System.currentTimeMillis();
      isActive = false;
      throw new AdminException("Admin connection can't be established: " + exc.getMessage());
    }
  }

  void adminDisconnect() {
    // Finishing the admin session.
    AdminModule.disconnect();
    if (isActive)
      adminDurationState = System.currentTimeMillis();
    isActive = false;
  }
 
  /**
   * Notifies the adapter to terminate the connections it manages, and if
   * needed, to shutdown the collocated JORAM server.
   */
  public synchronized void stop() {
    if (logger.isLoggable(BasicLevel.INFO))
      logger.log(BasicLevel.INFO, "JORAM adapter stopping...");

    if (! started || stopped)
      return;

    // Unbinds the bound objects...
    while (! boundNames.isEmpty())
      unbind((String) boundNames.remove(0));

    // Finishing the admin session.
    adminDisconnect();

    try {
      jmxServer.unregisterMBean(MXWrapper.objectName(jmxRootName, "type=JoramAdapter"));
    } catch (Exception e) {
      if (logger.isLoggable(BasicLevel.WARN))
        logger.log(BasicLevel.WARN, "unregisterMBean", e);
    }

    // Closing the outbound connections, if any.
    while (! producers.isEmpty()) {
      try {
        ((ManagedConnectionImpl) producers.remove(0)).destroy();
      } catch (Exception exc) {}
    }

    // Closing the inbound connections, if any.
    for (Enumeration keys = consumers.keys(); keys.hasMoreElements();)
      ((InboundConsumer) consumers.get(keys.nextElement())).close();

    // Browsing the recovery connections, if any.
    if (connections != null) {
      for (Enumeration keys = connections.keys(); keys.hasMoreElements();) {
        try {
          ((XAConnection) connections.get(keys.nextElement())).close();
        } catch (Exception exc) {}
      }
    }

    // If JORAM server is collocated, stopping it.
    if (collocated) {
      try {
        AgentServer.stop();
      } catch (Exception exc) {
        if (logger.isLoggable(BasicLevel.WARN))
          logger.log(BasicLevel.WARN, "Error during AgentServer stopping", exc);

      }
    }

    stopped = true;

    if (logger.isLoggable(BasicLevel.INFO))
      logger.log(BasicLevel.INFO, "JORAM adapter successfully stopped.");
  }

  /**
   * Notifies the adapter to setup asynchronous message delivery for an
   * application server endoint.
   *
   * @exception IllegalStateException  If the adapter is either not started,
   *                                   or stopped.
   * @exception NotSupportedException  If the provided activation parameters
   *                                   are invalid.
   * @exception CommException          If the JORAM server is not reachable.
   * @exception SecurityException      If connecting is not allowed.
   * @exception ResourceException      Generic exception.
   */
  public void endpointActivation(MessageEndpointFactory endpointFactory,
                                 ActivationSpec spec) throws ResourceException {
    if (logger.isLoggable(BasicLevel.DEBUG))
      logger.log(BasicLevel.DEBUG,
                 this + " endpointActivation(" + endpointFactory + ", " + spec + ")");

    if (! started)
      throw new IllegalStateException("Non started resource adapter.");
    if (stopped)
      throw new IllegalStateException("Stopped resource adapter.");

    if (! (spec instanceof ActivationSpecImpl))
      throw new ResourceException("Provided ActivationSpec instance is not a JORAM activation spec.");
    ActivationSpecImpl specImpl = (ActivationSpecImpl) spec;

    if (! specImpl.getResourceAdapter().equals(this))
      throw new ResourceException("Supplied ActivationSpec instance associated to an other ResourceAdapter.");

    if (logger.isLoggable(BasicLevel.DEBUG))
      logger.log(BasicLevel.DEBUG, "Activating Endpoint on JORAM adapter.");

    boolean durable =
      specImpl.getSubscriptionDurability() != null
      && specImpl.getSubscriptionDurability().equalsIgnoreCase("Durable");

    boolean transacted = false;
    try {
      Class listenerClass = Class.forName("javax.jms.MessageListener");
      Class[] parameters = { Class.forName("javax.jms.Message") };
      Method meth = listenerClass.getMethod("onMessage", parameters);
      transacted = endpointFactory.isDeliveryTransacted(meth);
    } catch (Exception exc) {
      throw new ResourceException("Could not determine transactional context: " + exc);
    }

    int maxWorks = 10;
    try {
      maxWorks = Integer.parseInt(specImpl.getMaxNumberOfWorks());
    } catch (Exception exc) {
      throw new ResourceException("Invalid max number of works instances number: " + exc);
    }

    int maxMessages = 10;
    try {
      maxMessages = Integer.parseInt(specImpl.getMaxMessages());
    } catch (Exception exc) {
      throw new ResourceException("Invalid max messages number: " + exc);
    }

    int ackMode;
    try {
      if (ActivationSpecImpl.AUTO_ACKNOWLEDGE.equals(specImpl.getAcknowledgeMode())) {
        ackMode = Session.AUTO_ACKNOWLEDGE;
      } else if (ActivationSpecImpl.DUPS_OK_ACKNOWLEDGE.equals(specImpl.getAcknowledgeMode())) {
        ackMode = Session.DUPS_OK_ACKNOWLEDGE;
      } else {
        ackMode = Session.AUTO_ACKNOWLEDGE;
      }
    }  catch (Exception exc) {
      throw new ResourceException("Invalid acknowledge mode: " + exc);
    }

    String destType = specImpl.getDestinationType();
    String destName = specImpl.getDestination();

    try {
      Destination dest;
     
      try {
        Context ctx = new InitialContext();
        dest = (Destination) ctx.lookup(destName);
      } catch (javax.naming.NamingException exc) {
        String shortName = removePrefix(destName);
        if ("javax.jms.Queue".equals(destType))
          dest = AdminModule.createQueue(serverId,
                                         shortName,
                                         "org.objectweb.joram.mom.dest.Queue",
                                         null);
        else if ("javax.jms.Topic".equals(destType))
          dest = AdminModule.createTopic(serverId,
                                         shortName,
                                         "org.objectweb.joram.mom.dest.Topic",
                                         null);
        else
          throw new NotSupportedException("Invalid destination type provided as activation parameter: " + destType);
       
        dest.setFreeReading();
        dest.setFreeWriting();

        if (logger.isLoggable(BasicLevel.INFO))
          logger.log(BasicLevel.INFO,
                     "  - Destination [" + shortName + "] has been created.");

        bind(destName, dest);
      }

      if ("javax.jms.Queue".equals(destType)) {
        if (! (dest instanceof javax.jms.Queue))
          throw new NotSupportedException("Existing destination " + destName  + " does not provide correct type.");
      } else if ("javax.jms.Topic".equals(destType)) {
        if (! (dest instanceof javax.jms.Topic))
          throw new NotSupportedException("Existing destination " + destName  + " does not provide correct type.");
      } else
        throw new NotSupportedException("Invalid destination type provided as activation parameter: " + destType);

      String userName = specImpl.getUserName();
      String password = specImpl.getPassword();
      String identityClass = specImpl.getIdentityClass();

      createUser(userName, password, identityClass);

      ConnectionFactory cf = null;

      if (isHa) {
        if (collocated) {
          if (haURL != null) {
            cf = HATcpConnectionFactory.create(haURL);
          } else {
            cf = HALocalConnectionFactory.create();
          }
        } else {
          cf = HATcpConnectionFactory.create("hajoram://" + hostName + ':' + serverPort);
        }
      }  else {
        if (collocated)
          cf = LocalConnectionFactory.create();
        else
          cf = TcpConnectionFactory.create(hostName, serverPort);
      }

      cf.getParameters().connectingTimer = connectingTimer;
      cf.getParameters().cnxPendingTimer = cnxPendingTimer;
      cf.getParameters().txPendingTimer = txPendingTimer;

      if (queueMessageReadMax > 0) {
        cf.getParameters().queueMessageReadMax = queueMessageReadMax;
      }

      if (topicAckBufferMax > 0) {
        cf.getParameters().topicAckBufferMax = topicAckBufferMax;
      }

      if (topicPassivationThreshold > 0) {
        cf.getParameters().topicPassivationThreshold = topicPassivationThreshold;
      }

      if (topicActivationThreshold > 0) {
        cf.getParameters().topicActivationThreshold = topicActivationThreshold;
      }

      // set identity class for this connectionFactory.
      cf.setIdentityClassName(identityClass);

      XAConnection cnx = cf.createXAConnection(userName, password);
     
      // set Exception listener
      cnx.setExceptionListener(this);
     
      if (logger.isLoggable(BasicLevel.DEBUG))
        logger.log(BasicLevel.DEBUG, this + " endpointActivation cnx = " + cnx);

      // Creating and registering a consumer instance for this endpoint.
      InboundConsumer consumer =
        new InboundConsumer(workManager,
                            endpointFactory,
                            cnx,
                            dest,
                            specImpl.getMessageSelector(),
                            durable,
                            specImpl.getSubscriptionName(),
                            transacted,
                            maxWorks,
                            maxMessages,
                            ackMode,
                            deleteDurableSubscription);

      consumers.put(specImpl, consumer);
    } catch (javax.jms.JMSSecurityException exc) {
      throw new SecurityException("Invalid user identification: " + exc);
    } catch (javax.jms.JMSException exc) {
      throw new CommException("Could not connect to the JORAM server: " + exc);
    } catch (ConnectException exc) {
      throw new ResourceException("Problem when handling the JORAM destinations: " + exc);
    } catch (AdminException exc) {
      throw new ResourceException("Problem when handling the JORAM destinations: " + exc);
    }
  }

  public void onException(JMSException exception) {
    if (logger.isLoggable(BasicLevel.DEBUG))
      logger.log(BasicLevel.DEBUG, "JoramAdapter: onException " + exception);
    while (true) {
      try {
        if (logger.isLoggable(BasicLevel.WARN))
          logger.log(BasicLevel.WARN, "JoramAdapter: try to reconnect...");
        reconnect();
        if (logger.isLoggable(BasicLevel.WARN))
          logger.log(BasicLevel.WARN, "JoramAdapter: reconnected.");
        break;
      } catch (Exception e) {
        continue;
      }
    }
  }
 
  public synchronized void reconnect() throws Exception {
    if (logger.isLoggable(BasicLevel.DEBUG))
      logger.log(BasicLevel.DEBUG, "JoramAdapter: reconnect()");
    boolean connected = false;
    if (!started || stopped)
      return;

    try {
      AdminModule.getConfiguration();
      connected = true;
    } catch (Exception e1) {
      try {
        adminDisconnect();
      } catch (Exception e) {
        if (logger.isLoggable(BasicLevel.DEBUG))
          logger.log(BasicLevel.DEBUG, "JoramAdapter: reconnect " + e);
      }
      try {
        adminConnect();
      } catch (AdminException e) {
        if (logger.isLoggable(BasicLevel.DEBUG))
          logger.log(BasicLevel.DEBUG, "JoramAdapter: reconnect " + e);
        throw e;
      }
    }
   
    if (connected)
      return;
   
    // consumers
    Hashtable copyConsumers = (Hashtable) consumers.clone();
   
    Set keys = copyConsumers.entrySet();
    Iterator it = keys.iterator();
    while (it.hasNext()) {
      Map.Entry entry = (Map.Entry) it.next();
     
      MessageEndpointFactory endpointFactory = ((InboundConsumer)entry.getValue()).endpointFactory;
      ActivationSpec spec = (ActivationSpec) entry.getKey();
      try {
        endpointDeactivation(endpointFactory, spec);
        endpointActivation(endpointFactory, spec);
      } catch (ResourceException e) {
        if (logger.isLoggable(BasicLevel.INFO))
          logger.log(BasicLevel.INFO, "JoramAdapter: reconnect spec = " + spec, e);
      }
    }
   
    // producers
    it = ((Vector) producers.clone()).iterator();
    while (it.hasNext()) {
      ManagedConnectionImpl mci = (ManagedConnectionImpl) it.next();
      mci.reconnect();
    }
  }
 
  /**
   * Notifies the adapter to deactivate message delivery for a given endpoint.
   */
  public void endpointDeactivation(MessageEndpointFactory endpointFactory,
                                   ActivationSpec spec) {
    if (logger.isLoggable(BasicLevel.DEBUG))
      logger.log(BasicLevel.DEBUG,
                 this + " endpointDeactivation(" + endpointFactory + ", " + spec + ")");
    if (! started || stopped)
      return;

    if (logger.isLoggable(BasicLevel.DEBUG))
      logger.log(BasicLevel.DEBUG,
      "Deactivating Endpoint on JORAM adapter.");

    InboundConsumer consumer = (InboundConsumer) consumers.remove(spec);
    if (consumer != null) {
      consumer.close();
    }
  }

  /**
   * Returns XA resources given an array of ActivationSpec instances.
   *
   * @exception IllegalStateException  If the adapter is either not started,
   *                                   or stopped.
   * @exception NotSupportedException  If provided activation parameters
   *                                   are invalid.
   * @exception CommException          If the JORAM server is not reachable.
   * @exception SecurityException      If connecting is not allowed.
   * @exception ResourceException      Generic exception.
   */
  public XAResource[] getXAResources(ActivationSpec[] specs) throws ResourceException {
    if (logger.isLoggable(BasicLevel.DEBUG))
      logger.log(BasicLevel.DEBUG,
                 this + " getXAResources(" + specs + ")");

    if (! started)
      throw new IllegalStateException("Non started resource adapter.");
    if (stopped)
      throw new IllegalStateException("Stopped resource adapter.");

    ActivationSpecImpl specImpl;
    String userName;
    ConnectionFactory cf = null;
    XAConnection connection;
    Vector resources = new Vector();

    if (connections == null)
      connections = new Hashtable();

    try {
      for (int i = 0; i < specs.length; i++) {
        if (! (specs[i] instanceof ActivationSpecImpl))
          throw new ResourceException("Provided ActivationSpec instance is not a JORAM activation spec.");

        specImpl = (ActivationSpecImpl) specs[i];

        if (! specImpl.getResourceAdapter().equals(this))
          throw new ResourceException("Supplied ActivationSpec instance associated to an other ResourceAdapter.");

        userName = specImpl.getUserName();

        // The connection does not already exist: creating it.
        if (! connections.containsKey(userName)) {
          String password = specImpl.getPassword();
          String identityClass = specImpl.getIdentityClass();

          if (isHa) {
            if (collocated) {
              if (logger.isLoggable(BasicLevel.DEBUG))
                logger.log(BasicLevel.DEBUG, "haURL = " + haURL);
              if (haURL != null) {
                cf = HATcpConnectionFactory.create(haURL);
              } else {
                cf = HALocalConnectionFactory.create();
              }
            } else {
              String urlHa = "hajoram://" + hostName + ":" + serverPort;
              cf = HATcpConnectionFactory.create(urlHa);
            }
          }  else {
            if (collocated)
              cf = LocalConnectionFactory.create();
            else
              cf = TcpConnectionFactory.create(hostName, serverPort);
          }

          cf.getParameters().connectingTimer = connectingTimer;
          cf.getParameters().cnxPendingTimer = cnxPendingTimer;
          cf.getParameters().txPendingTimer = txPendingTimer;

          // set identity class for this connectionFactory.
          cf.setIdentityClassName(identityClass);

          connection = cf.createXAConnection(userName, password);

          connections.put(userName, connection);

          resources.add(connection.createXASession().getXAResource());
        }
        if (logger.isLoggable(BasicLevel.DEBUG))
          logger.log(BasicLevel.DEBUG,
                     this + " getXAResources resources = " + resources);
      }
    } catch (javax.jms.JMSSecurityException exc) {
      throw new SecurityException("Invalid user identification: " + exc);
    } catch (javax.jms.JMSException exc) {
      throw new CommException("Could not connect to the JORAM server: " + exc);
    }

    return (XAResource[]) resources.toArray(new XAResource[resources.size()]);
  }

  // TODO (AF): Is it really needed?
  /** @deprecated */
  public void exit() {
    adminDisconnect();
  }

  /** Returns a code depending on the adapter properties. */
  public int hashCode() {
    return (collocated + " " + hostName + " " + serverPort).hashCode();
  }

  /** Compares adapters according to their properties. */
  public boolean equals(Object o) {
    if (! (o instanceof JoramAdapter))
      return false;

    JoramAdapter other = (JoramAdapter) o;

    boolean res =
      collocated == other.collocated
      && hostName.equals(other.hostName)
      && serverPort == other.serverPort;

    if (logger.isLoggable(BasicLevel.DEBUG))
      logger.log(BasicLevel.DEBUG,
                 this + " equals = " + res);
    return res;
  }

  /** Adds a given managed connection to the list of producers. */
  void addProducer(ManagedConnectionImpl managedCx) {
    producers.add(managedCx);
  }

  /** Removes a given managed connection from the list of producers. */
  void removeProducer(ManagedConnectionImpl managedCx) {
    producers.remove(managedCx);
  }

  // Implementation of MBean's interfaces

  /**
    * return the activity of the Joram administration connection.
    * @return true if connection is active.
    */
  public boolean isActive() {
    return isActive;
  }
 
  /**
   * get duration of admin connection before change state.
   * @return the duration of admin change connection state.
   */
  public long getAdminDurationBeforeChangeState() {
    return adminDurationState;
  }
 
  /**
   * get duration of admin connection before change state.
   * @return the duration of admin connection before change state.
   */
  public String getAdminDurationBeforeChangeStateDate() {
    return new Date(adminDurationState).toString();
  }
 
  /**
   * Gets the JMS API version.
   *
   * @return The JMS API version.
   */
  public String getJMSVersion() {
    return ConnectionMetaData.jmsVersion;
  }
 
  /**
   * Get the provider name: Joram.
   *
   * @return The provider name: Joram.
   */
  public String getJMSProviderName() {
    return ConnectionMetaData.providerName;
  }
 
  /**
   * Gets the Joram's implementation version.
   *
   * @return The Joram's implementation version.
   */
  public String getProviderVersion() {
    return ConnectionMetaData.providerVersion;
  }


  /**
   * Gets timeout before abort a request.
   *
   * @return timeout before abort a request.
   * @throws ConnectException
   *
   * @see AdminModule#getTimeOutToAbortRequest()
   */
  public long getTimeOutToAbortRequest() throws ConnectException {
    return AdminModule.getTimeOutToAbortRequest();
  }

  /**
   * Sets timeout before abort a request.
   *
   * @param timeOut timeout before abort a request.
   * @throws ConnectException
   *
   * @see AdminModule#setTimeOutToAbortRequest(long)
   */
  public void setTimeOutToAbortRequest(long timeOut) throws ConnectException {
    AdminModule.setTimeOutToAbortRequest(timeOut);
  }
  /**
   * Returns the unique identifier of the default dead message queue for the local
   * server, null if not set.
   *
   * @return The unique identifier of the dead message queue of the local server or null
   *         if none exists.
   * @exception ConnectException  If the connection fails.
   * @exception AdminException  Never thrown.
   *
   * @see AdminModule#getDefaultDMQId()
   */
  public String getDefaultDMQId() throws ConnectException, AdminException {
    return AdminModule.getDefaultDMQId();
  }
 
  /**
   * Returns the unique identifier of the default dead message queue for a given
   * server, null if not set.
   * <p>
   * The request fails if the target server does not belong to the platform.
   *
   * @param serverId Unique identifier of the server.
   * @return The unique identifier of the dead message queue of the given server or null
   *         if none exists.
   *
   * @exception ConnectException  If the connection fails.
   * @exception AdminException  If the request fails.
   *
   * @see AdminModule#getDefaultDMQId()
   */
  public String getDefaultDMQId(short serverId) throws ConnectException, AdminException {
    return AdminModule.getDefaultDMQId(serverId);
  }

  /**
   * Unset the default dead message queue for the local server.
   *
   * @throws ConnectException
   * @throws AdminException
   */
  public void resetDefaultDMQ() throws ConnectException, AdminException {
    AdminModule.setDefaultDMQ(null);
  }

  /**
   * Unset the default dead message queue for the given server.
   *
   * @param serverId Unique identifier of the given server.
   * @throws ConnectException
   * @throws AdminException
   */
  public void resetDefaultDMQ(short serverId) throws ConnectException, AdminException {
    AdminModule.setDefaultDMQ(serverId, null);
  }

 
  /**
   * Returns the default threshold of the Joram server.
   *
   * @return the default threshold of the Joram server.
   * @see AdminModule#getDefaultThreshold()
   */
    public int getDefaultThreshold() throws ConnectException, AdminException {
    return AdminModule.getDefaultThreshold();
  }

  /**
   * Returns the default threshold of the given Joram server.
   *
   * @param serverId  Unique identifier of the given Joram server.
   * @return the default threshold of the given Joram server.
   * @see AdminModule#getDefaultThreshold(int)
   */
  public int getDefaultThreshold(short serverId) throws ConnectException, AdminException {
    return AdminModule.getDefaultThreshold(serverId);
  }

  /**
   * Sets the default threshold of the Joram server.
   *
   * @param threshold the default threshold of the Joram server.
   * @see AdminModule#setDefaultThreshold(int)
   */
  public void setDefaultThreshold(int threshold) throws ConnectException, AdminException {
    AdminModule.setDefaultThreshold(threshold);
  }

  /**
   * Sets the default threshold of the given Joram server.
   *
   * @param serverId  Unique identifier of the given Joram server.
   * @param threshold the default threshold of the given Joram server.
   * @see AdminModule#setDefaultThreshold(int, int)
   */
  public void setDefaultThreshold(short serverId, int threshold) throws ConnectException, AdminException {
    AdminModule.setDefaultThreshold(serverId, threshold);
  }

  /**
   * Returns the list of all destinations that exist on the local server.
   * This method creates and registers MBeans for all the destinations of
   * the selected servers.
   *
   * @return  An array containing the object name of all destinations defined
   *          on the given server or null if none exists.
   *
   * @exception ConnectException  If the connection is closed or broken.
   * @exception AdminException    Never thrown.
   *
   * @see #getDestinations(short)
   */
  public String[] getDestinations() throws ConnectException, AdminException {
    return getDestinations((short) AdminModule.getLocalServerId());
  }

  /**
   * Returns the list of all destinations that exist on the given server.
   * This method creates and registers MBeans for all the destinations of
   * the selected servers.
   * <p>
   * The request fails if the target server does not belong to the platform.
   *
   * @return  An array containing the object name of all destinations defined
   *          on the given server or null if none exists.
   *
   * @exception ConnectException  If the connection is closed or broken.
   * @exception AdminException    Never thrown.
   */
  public String[] getDestinations(short serverId) throws ConnectException, AdminException {
    Destination[] destinations = AdminModule.getDestinations(serverId);
    String[] names = new String[destinations.length];
   
    for (int i=0; i<destinations.length; i++) {
      names[i] = destinations[i].registerMBean(jmxRootName);
    }
    return names;
  }

  /**
   * Creates or retrieves a queue destination on the underlying JORAM server,
   * (re)binds the corresponding <code>Queue</code> instance.
   *
   * @param name       The name of the queue.
   *
   * @exception AdminException   If the creation fails.
   * @exception ConnectException if the connection is closed or broken
   *
   * @see #createQueue(short, String, String, Properties)
   */
  public String createQueue(String name) throws AdminException, ConnectException {
    return createQueue(serverId, name, Destination.QUEUE, null);
  }

  /**
   * Creates or retrieves a queue destination on the underlying JORAM server,
   * (re)binds the corresponding <code>Queue</code> instance.
   *
   * @param serverId   The identifier of the server where deploying the queue.
   * @param name       The name of the queue.
   *
   * @exception AdminException   If the creation fails.
   * @exception ConnectException if the connection is closed or broken
   *
   * @see #createQueue(short, String, String, Properties)
   */
  public String createQueue(short serverId, String name) throws AdminException, ConnectException {
    return createQueue(serverId, name, Destination.QUEUE, null);
  }

  /**
   * First tries to retrieve a queue destination on the underlying JORAM server first
   * using JNDI then the Joram's internal name service. Finally, if the destination does
   * not exist it is created. Anyway at the end of this method the destination is bound
   * in the JNDI repository.
   *
   * @param serverId   The identifier of the server where deploying the queue.
   * @param name       The name of the queue.
   * @param className  The queue class name.
   * @param prop       The queue properties.
   *
   * @exception AdminException   If the creation fails.
   * @exception ConnectException if the connection is closed or broken
   */
  public String createQueue(short serverId,
                            String name,
                            String className,
                            Properties prop) throws AdminException, ConnectException {
    Queue queue = null;

    try {
      Context ctx = new InitialContext();
      queue = (Queue) ctx.lookup(name);
    } catch (javax.naming.NamingException exc) {
      String shortName = removePrefix(name);
      queue = (Queue) AdminModule.createQueue(serverId, shortName, className, prop);
      queue.setFreeReading();
      queue.setFreeWriting();

      if (logger.isLoggable(BasicLevel.INFO))
        logger.log(BasicLevel.INFO,
                   "  - Queue [" + shortName + "] has been created.");

      bind(name, queue);
    }

    return queue.registerMBean(jmxRootName);
  }

  /**
   * Creates or retrieves a topic destination on the underlying JORAM server,
   * (re)binds the corresponding <code>Topic</code> instance.
   *
   * @param name       The name of the topic.
   *
   * @exception AdminException   If the creation fails.
   * @exception ConnectException if the connection is closed or broken
   *
   * @see #createTopic(short, String, String, Properties)
   */
  public String createTopic(String name) throws AdminException, ConnectException {
    return createTopic(serverId, name, Destination.TOPIC, null);
  }

  /**
   * Creates or retrieves a topic destination on the underlying JORAM server,
   * (re)binds the corresponding <code>Topic</code> instance.
   *
   * @param serverId   The identifier of the server where deploying the topic.
   * @param name       The name of the topic.
   *
   * @exception AdminException   If the creation fails.
   * @exception ConnectException if the connection is closed or broken
   *
   * @see #createTopic(short, String, String, Properties)
   */
  public String createTopic(short serverId, String name) throws AdminException, ConnectException {
    return createTopic(serverId, name, Destination.TOPIC, null);
  }

  /**
   * Creates or retrieves a topic destination on the underlying JORAM server,
   * (re)binds the corresponding <code>Topic</code> instance.
   *
   * @param serverId   The identifier of the server where deploying the topic.
   * @param name       The name of the topic.
   * @param className  The topic class name.
   * @param prop       The topic properties.
   *
   * @exception AdminException   If the creation fails.
   * @exception ConnectException if the connection is closed or broken
   */
  public String createTopic(short serverId,
                            String name,
                            String className,
                            Properties prop) throws AdminException, ConnectException {
    Topic topic = null;

    try {
      Context ctx = new InitialContext();
      topic = (Topic) ctx.lookup(name);
    } catch (javax.naming.NamingException exc) {
      String shortName = removePrefix(name);
      topic = (Topic) AdminModule.createTopic(serverId, shortName, className, prop);
      topic.setFreeReading();
      topic.setFreeWriting();

      if (logger.isLoggable(BasicLevel.INFO))
        logger.log(BasicLevel.INFO,
                   "  - Topic [" + shortName + "] has been created.");

      bind(name, topic);
    }

    return topic.registerMBean(jmxRootName);
  }

  /**
   * Remove a destination specified by its JNDI name on the underlying
   * JORAM platform.
   *
   * @param name       The JNDI name of the destination.
   */
  public void removeDestination(String name) throws AdminException {
    try {
      Context ctx = new InitialContext();
      Destination dest = (Destination) ctx.lookup(name);
      ctx.close();

      dest.delete();
      unbind(name);
    } catch (Exception exc) {
      logger.log(BasicLevel.WARN,
                 "removeDestination failed: " + name, exc);
      throw new AdminException("removeDestination(" + name + ") failed.");
    }
  }

  /**
   * Returns the list of all users that exist on the local server.
   * This method creates and registers MBeans for all the users of
   * the selected servers.
   *
   * @return  An array containing the object name of all users defined
   *          on the given server or null if none exists.
   *
   * @exception ConnectException  If the connection fails.
   * @exception AdminException    Never thrown.
   *
   * @see #getUsers(short)
   */
  public String[] getUsers() throws ConnectException, AdminException {
    return getUsers((short) AdminModule.getLocalServerId());
  }

  /**
   * Returns the list of all users that exist on a given server.
   * This method creates and registers MBeans for all the users of
   * the selected servers.
   * <p>
   * The request fails if the target server does not belong to the platform.
   *
   * @param serverId  Unique identifier of the given server.
   * @return  An array containing the object name of all users defined
   *          on the given server or null if none exists.
   *
   * @exception ConnectException  If the connection fails.
   * @exception AdminException    If the request fails.
   */
  public String[] getUsers(short serverId) throws ConnectException, AdminException {
    User[] users = AdminModule.getUsers(serverId);
    String[] names = new String[users.length];
   
    for (int i=0; i<users.length; i++) {
      names[i] = users[i].registerMBean(jmxRootName);
    }
    return names;
  }

  /**
   * Creates or retrieves a user on the underlying JORAM server.
   *
   * @param name      The login name of the user.
   * @param password  The password of the user.
   * @return The object name of created user.
   *
   * @exception AdminException    If the creation fails.
   * @exception ConnectException  If the connection fails.
   *
   * @see #createUser(String, String, short, String)
   */
  public String createUser(String name,
                           String password) throws AdminException, ConnectException {
    return createUser(name, password, (short) AdminModule.getLocalServerId(), SimpleIdentity.class.getName());
  }

  /**
   * Creates or retrieves a user on the underlying JORAM server.
   *
   * @param name          The login name of the user.
   * @param password      The password of the user.
   * @param identityClass The identity class used for authentication.
   * @return The object name of created user.
   *
   * @exception AdminException    If the creation fails.
   * @exception ConnectException  If the connection fails.
   *
   * @see #createUser(String, String, short, String)
   */
  public String createUser(String name,
                           String password,
                           String identityClass) throws AdminException, ConnectException {
    return createUser(name, password, (short) AdminModule.getLocalServerId(), identityClass);
  }

  /**
   * Creates or retrieves a user on the given JORAM server.
   *
   * @param name      The login name of the user.
   * @param password  The password of the user.
   * @param serverId  The unique identifier of the Joram server.
   * @return The object name of created user.
   *
   * @exception AdminException    If the creation fails.
   * @exception ConnectException  If the connection fails.
   *
   * @see #createUser(String, String, short, String)
   */
  public String createUser(String name,
                           String password,
                           short serverId) throws AdminException, ConnectException {
    return createUser(name, password, serverId, SimpleIdentity.class.getName());
  }

  /**
   * Creates or retrieves a user on the underlying JORAM server.
   *
   * @param name          The login name of the user.
   * @param password      The password of the user.
   * @param serverId      The unique identifier of the Joram server.
   * @param identityClass The identity class used for authentication.
   * @return The object name of created user.
   *
   * @exception AdminException    If the creation fails.
   * @exception ConnectException  If the connection fails.
   */
  public String createUser(String name,
                         String password,
                         short serverId,
                         String identityClass) throws AdminException, ConnectException {
    User user = AdminModule.createUser(name, password, serverId, identityClass);
    return user.registerMBean(jmxRootName);
  }

  /**
   * Creates a non managed connection factory and binds it to JNDI.
   *
   * @param name Name of created connection factory.
   */
  public void createCF(String name) {
    ManagedConnectionFactoryImpl mcf = new ManagedConnectionFactoryImpl();

    try {
      mcf.setResourceAdapter(this);
      mcf.setCollocated(new Boolean(false));

      Object factory = mcf.createConnectionFactory();
      bind(name, factory);
     
      if (logger.isLoggable(BasicLevel.INFO))
        logger.log(BasicLevel.INFO,
                   "  - ConnectionFactory [" + name + "] has been created and bound.");
    } catch (Exception exc) {}
  }

  /**
   * Creates a non managed PTP connection factory and binds it to JNDI.
   *
   * @param name Name of created connection factory.
   */
  public void createQueueCF(String name) {
    ManagedConnectionFactoryImpl mcf = new ManagedQueueConnectionFactoryImpl();

    try {
      mcf.setResourceAdapter(this);
      mcf.setCollocated(new Boolean(false));

      Object factory = mcf.createConnectionFactory();
      bind(name, factory);
      if (logger.isLoggable(BasicLevel.INFO))
        logger.log(BasicLevel.INFO,
                   "  - QueueConnectionFactory [" + name
                   + "] has been created and bound.");
    } catch (Exception exc) {}
  }

  /**
   * Creates a non managed PubSub connection factory and binds it to JNDI.
   *
   * @param name Name of created connection factory.
   */
  public void createTopicCF(String name) {
    ManagedConnectionFactoryImpl mcf = new ManagedTopicConnectionFactoryImpl();

    try {
      mcf.setResourceAdapter(this);
      mcf.setCollocated(new Boolean(false));

      Object factory = mcf.createConnectionFactory();
      bind(name, factory);
      if (logger.isLoggable(BasicLevel.INFO))
        logger.log(BasicLevel.INFO,
                   "  - TopicConnectionFactory [" + name
                   + "] has been created and bound.");
    } catch (Exception exc) {}
  }

  /** remove prefix name scn:comp/ */
  private static String removePrefix(String name) {
    String PREFIX_NAME = "scn:comp/";
    try {
      if (name.startsWith(PREFIX_NAME))
        return name.substring(PREFIX_NAME.length());
    } catch (Exception e) {}
    return name;
  }

  /** Binds an object to the JNDI context. */
  void bind(String name, Object obj) {
    try {
      Context ctx = new InitialContext();
      ctx.rebind(name, obj);
      if (! boundNames.contains(name))
        boundNames.add(name);
    } catch (Exception e) {
      if (logger.isLoggable(BasicLevel.WARN))
        logger.log(BasicLevel.WARN,
                   "Binding failed:  bind(" + name +"," + obj +")", e);
    }
  }

  /** Unbinds an object from the JNDI context. */
  void unbind(String name) {
    try {
      Context ctx = new InitialContext();
      ctx.unbind(name);
      boundNames.remove(name);
    } catch (Exception exc) {}
  }

  /**
   * Executes the XML configuration file.
   *
   * @param path the path for the joramAdmin file
   * @throws AdminException if an error occurs
   */
  public void executeXMLAdmin(String path) throws Exception {
    AdminModule.executeXMLAdmin(path);
  }

  /**
   * Export the repository content to an XML file with default filename.
   * - only the destinations objects are retrieved in this version
   * - xml script format of the admin objects (joramAdmin.xml)
   *
   * @param exportDir       target directory where the export file will be put
   * @throws AdminException if an error occurs
   */
  public void exportRepositoryToFile(String exportDir) throws AdminException {
    AdminModule.exportRepositoryToFile(exportDir, adminFileExportXML);
  }

  /**
   * Export the repository content to an XML file
   * - only the destinations objects are retrieved in this version
   * - xml script format of the admin objects (joramAdmin.xml)
   *
   * @param exportDir       target directory where the export file will be put
   * @param exportFilename  filename of the export file
   * @throws AdminException if an error occurs
   */
  public void exportRepositoryToFile(String exportDir,
                                     String exportFilename) throws AdminException {
    AdminModule.exportRepositoryToFile(exportDir, exportFilename);
  }

  /**
   * Returns the list of the platform's servers' identifiers.
   *
   * @return an array containing the list of the platform's servers' identifiers.
   * @throws AdminException If the request fails.
   * @throws ConnectException If the connection fails.
   */
  public Short[] getServersIds() throws ConnectException, AdminException {
    // TODO (AF): next to 5.2, directly use  AdminModule.getServersIds()
    int[] sids = AdminModule.getWrapper().getServersIds();
    Short serversIds[] = new Short[sids.length];
    for (int i=0; i<sids.length; i++)
      serversIds[i] = new Short((short) sids[i]);
    return serversIds;
  }

  /**
   * Returns the list of the platform's servers' names.
   *
   * @return An array containing the list of server's names.
   * @exception ConnectException  If the connection fails.
   * @exception AdminException  Never thrown.
   */
  public final String[] getServersNames() throws ConnectException, AdminException {
    // TODO (AF): next to 5.2, directly use  AdminModule.getServersIds()
    return AdminModule.getWrapper().getServersNames(null);
  }
 
  /**
   * Returns the current servers configuration (a3servers.xml).
   *
   * @return The current servers configuration.
   * @exception ConnectException  If the connection fails.
   * @exception AdminException  If the request fails.
   */
  public final String getConfiguration() throws ConnectException, AdminException {
    return AdminModule.getConfiguration();
  }
}
TOP

Related Classes of org.objectweb.joram.client.connector.JoramAdapter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.