Package com.sun.messaging.jmq.jmsserver.service.imq

Source Code of com.sun.messaging.jmq.jmsserver.service.imq.QueueBrowserInfo

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2000-2010 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License.  You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/

/*
* @(#)IMQDirectService.java  1.57 06/29/07
*/

package com.sun.messaging.jmq.jmsserver.service.imq;

import java.io.*;
import java.util.*;
import java.security.AccessControlException;
import javax.transaction.xa.Xid;

import com.sun.messaging.jmq.util.JMQXid;
import com.sun.messaging.jmq.util.GoodbyeReason;
import com.sun.messaging.jmq.util.ServiceState;
import com.sun.messaging.jmq.util.ServiceType;
import com.sun.messaging.jmq.util.UniqueID;
import com.sun.messaging.jmq.util.UID;
import com.sun.messaging.jmq.util.DestType;
import com.sun.messaging.jmq.util.log.Logger;
import com.sun.messaging.jmq.jmsserver.service.*;
import com.sun.messaging.jmq.jmsserver.util.*;
import com.sun.messaging.jmq.jmsserver.util.pool.*;
import com.sun.messaging.jmq.jmsserver.core.Session;
import com.sun.messaging.jmq.jmsserver.core.SessionUID;
import com.sun.messaging.jmq.jmsserver.core.ConsumerUID;
import com.sun.messaging.jmq.jmsserver.core.ProducerUID;
import com.sun.messaging.jmq.jmsserver.auth.AuthCacheData;
import com.sun.messaging.jmq.jmsserver.auth.AccessController;
import com.sun.messaging.jmq.jmsserver.data.PacketRouter;
import com.sun.messaging.jmq.jmsserver.data.PacketRouter;
import com.sun.messaging.jmq.jmsserver.data.TransactionUID;
import com.sun.messaging.jmq.jmsserver.data.AutoRollbackType;
import com.sun.messaging.jmq.jmsserver.data.handlers.AckHandler;
import com.sun.messaging.jmq.jmsserver.data.protocol.Protocol;
import com.sun.messaging.jmq.jmsserver.core.PacketReference;
import com.sun.messaging.jmq.util.lists.*;
import com.sun.messaging.jmq.util.selector.Selector;
import com.sun.messaging.jmq.util.selector.SelectorFormatException;
import com.sun.messaging.jmq.jmsserver.net.*;
import com.sun.messaging.jmq.io.Packet;
import com.sun.messaging.jmq.io.Status;
import com.sun.messaging.jmq.io.PacketType;
import com.sun.messaging.jmq.io.SysMessageID;
import com.sun.messaging.jmq.jmsserver.resources.*;
import com.sun.messaging.jmq.jmsserver.config.*;
import com.sun.messaging.jmq.jmsserver.Globals;
import com.sun.messaging.jmq.jmsserver.management.agent.Agent;
import com.sun.messaging.jmq.jmsservice.*;

public class IMQDirectService extends IMQService implements JMSService
{

    private static boolean DEBUG = false;

    private boolean acEnabled = false;

    Map  localConnectionList = Collections.synchronizedMap(new HashMap());
    Map    queueBrowseList = Collections.synchronizedMap(new HashMap());
    Protocol  protocol;



    protected ThreadPool pool = null;


    /**
     * the list of connections which this service knows about
     * XXX make this accessible from IMQService ??
     */
    private ConnectionManager connectionList = Globals.getConnectionManager();

    private AuthCacheData authCacheData = new AuthCacheData();
    protected Thread listenThread = null;
    HashMap serviceprops = null;
   
    public IMQDirectService(String name, int type, int min, int max, boolean acc)
    {
      super(name, type);
      protocol = Globals.getProtocol();

        acEnabled = acc;

        // create a thread pool for the threading off of the forwarding
        // task
        OperationRunnableFactory runfac =new OperationRunnableFactory(true /* blocking */);
        pool = new ThreadPool(name,min,max,runfac);
    }


    // XXX - this implemenetation assumes that we have 1 distinct
    // listen thread per/service
    // revisit  (may not always be true)

    public synchronized  void startService(boolean startPaused) {
        if (isServiceRunning() || listenThread != null) {
            /*
             * this error should never happen in normal operation
             * if its does, we will need to add an error message
             * to the resource bundle
             */
            logger.log(Logger.DEBUG,
                       BrokerResources.E_INTERNAL_BROKER_ERROR,
                       "unable to start service, already started.");
            return;
        }
        setState(ServiceState.STARTED);
        {
            String args[] = { getName(),
                              "",
                              String.valueOf(getMinThreadpool()),
                              String.valueOf(getMaxThreadpool()) };
            logger.log(Logger.INFO, BrokerResources.I_SERVICE_START, args);
            try {
            logger.log(Logger.INFO, BrokerResources.I_SERVICE_USER_REPOSITORY,
                       AccessController.getInstance(
                       getName(), getServiceType()).getUserRepository(),
                       getName());
            } catch (BrokerException e) {
            logger.log(Logger.WARNING,
                       BrokerResources.W_SERVICE_USER_REPOSITORY,
                       getName(), e.getMessage());
            }
        }
    
        if (startPaused) {
            setServiceRunning(false);
            setState(ServiceState.PAUSED);
      /*
       * CHECK: This used to be if'd by WORKAROUND_HTTP
       */
                try {
                    Globals.getPortMapper().updateServicePort(name, 0);
                } catch (Exception ex) {
                    logger.logStack(Logger.WARNING,
                          BrokerResources.E_INTERNAL_BROKER_ERROR,
                          "starting paused service " + this, ex);
                }
        } else {
            setServiceRunning(true);
            setState(ServiceState.RUNNING);
        }
        notify();
    }

    public void stopService(boolean all) {
        synchronized (this) {

            if (isShuttingDown()) {
                // we have already been called
                return;
            }

            String strings[] = { getName(), "" };
            if (all) {
                logger.log(Logger.INFO,
                           BrokerResources.I_SERVICE_STOP,
                           strings);
            } else if (!isShuttingDown()) {
                logger.log(Logger.INFO,
                           BrokerResources.I_SERVICE_SHUTTINGDOWN,
                           strings);
            }
          
      setShuttingDown(true);
        }

        if (this.getServiceType() == ServiceType.NORMAL) {
            List cons = connectionList.getConnectionList(this);
            Connection con = null;
            for (int i = cons.size()-1; i >= 0; i--) {
                con = (Connection)cons.get(i);
                con.stopConnection();
            }
        }

        synchronized (this) {
            setState(ServiceState.SHUTTINGDOWN);
            this.notify();
        }

        if (!all) {
            return;
        }

        // set operation state to EXITING
        if (this.getServiceType() == ServiceType.NORMAL) {
            List cons = connectionList.getConnectionList(this);
            Connection con = null;
            for (int i = cons.size()-1; i >= 0; i--) {
                con = (Connection)cons.get(i);
                con.destroyConnection(true, GoodbyeReason.SHUTDOWN_BKR,
                    Globals.getBrokerResources().getKString(
                        BrokerResources.M_SERVICE_SHUTDOWN));
            }
        }

        synchronized (this) {
            setState(ServiceState.STOPPED);
            this.notify();
        }

        if (DEBUG) {
            logger.log(Logger.DEBUG,
                "Destroying Service {0}", getName());
        }
    }

    public void pauseService(boolean all) {

        if (!isServiceRunning()) {
            logger.log(Logger.DEBUG,
                    BrokerResources.E_INTERNAL_BROKER_ERROR,
                    "unable to pause service "
                    + name + ", already paused.");
            return;
       

        String strings[] = { getName(), "" };
        logger.log(Logger.DEBUG, BrokerResources.I_SERVICE_PAUSE, strings);

        try {
            stopNewConnections();
        } catch (Exception ex) {
            logger.logStack(Logger.WARNING,
                      BrokerResources.E_INTERNAL_BROKER_ERROR,
                      "pausing service " + this, ex);
        }
        setState(ServiceState.PAUSED);

        setServiceRunning(false);
    }

    public void resumeService() {
        if (isServiceRunning()) {
             logger.log(Logger.DEBUG,
                    BrokerResources.E_INTERNAL_BROKER_ERROR,
                    "unable to resume service "
                    + name + ", already running.");
           return;
        }
        String strings[] = { getName(), "" };
        logger.log(Logger.DEBUG, BrokerResources.I_SERVICE_RESUME, strings);
        try {
            startNewConnections();
        } catch (Exception ex) {
            logger.logStack(Logger.WARNING,
                      BrokerResources.E_INTERNAL_BROKER_ERROR,
                      "pausing service " + this, ex);
        }
        setServiceRunning(true);

        synchronized (this) {
            setState(ServiceState.RUNNING);
            this.notify();
        }
       
    }

    public void updateService(int port, int min, int max)
        throws IOException, PropertyUpdateException, BrokerException
    {
        Globals.getPortMapper().updateServicePort(name, 0);
        Globals.getPortMapper().removeService(name);
        Globals.getPortMapper().addService(name, "none",
          Globals.getConfig().getProperty(
          IMQDirectServiceFactory.SERVICE_PREFIX +
          name + ".servicetype"),
          0, getServiceProperties());
    }

    public AuthCacheData getAuthCacheData() {
        return authCacheData;    
   

    public IMQConnection createDirectConnection(String username, String password)
    throws BrokerException {
  IMQDirectConnection con = null;
  /*
  System.err.println("#### CREATE DIRECT CXN: username: "
    + username
    + ", passwd: "
    + password);
  */

  con = new IMQDirectConnection(this);
  connectionList.addConnection(con);
  localConnectionList.put(con.getConnectionUID(), con);

  try  {
      con.authenticate(username, password);
      /*
      System.err.println("#### CREATE DIRECT CXN: AUTH SUCCESSFULL");
      System.err.println("#### DIRECT CXN authenticated name: " + con.getAuthenticatedName());
      */
  } catch(Exception e)  {
      e.printStackTrace();
      String errStr = "Authentication failed for username "
      + username
      + " in service "
      + getName()
      + ": "
      + e;
      logger.log(Logger.WARNING, errStr);
      logger.log(Logger.WARNING, BrokerResources.W_LOGIN_FAILED, e);
      connectionList.removeConnection(con.getConnectionUID(),
             true, GoodbyeReason.CON_FATAL_ERROR, errStr);
      localConnectionList.remove(con.getConnectionUID());

      throw new SecurityException(errStr);
  }

  Agent agent = Globals.getAgent();
  if (agent != null)  {
      agent.registerConnection(con.getConnectionUID().longValue());
      agent.notifyConnectionOpen(con.getConnectionUID().longValue());
  }

  /*
  System.err.println("#### CREATE DIRECT CXN: returning: " + con);
  System.err.println("#### CREATE DIRECT CXN: service from cxn info: " + con.getConnectionInfo().service);
  */

  return (con);
    }

    public void removeConnection(ConnectionUID uid, int reason, String str) {
    /*
    System.err.println(">>>>>>>>> IMQDirectConnection: REMOVE CONNECTION: " + uid);
    */
         connectionList.removeConnection(uid,
             true, reason, str);
   localConnectionList.remove(uid);
    }

    public boolean isDirect() {
        return (true);
    }

    /*
     * BEGIN Interface JMSService
     */

    /**
     *  Return an Identifier for the JMSService.<br>
     *  The identification string returned should enable a user to identify the
     *  specific broker instance that this JMSService is communicating with
     *  from a log message that contains this Identifier string.<br>
     *  for example -- {@literal <hostname>:<primary_port>:<servicename>}
     *
     *  @return The JMSServiceID string that identifies the broker address and
     *          servicename that is being used.
     */
    public String getJMSServiceID()  {
  return (getName());
    }

    /**
     *  Create a connection with the service.
     *
     *  @param  username    The identity with which to establish the connection
     *  @param  password    The password for the identity
     *  @param  ctx         The JMSServiceBootStrapContext to use for broker
     *                      thread resources etc.
     *
     *  @return the JMSServiceReply of the request to create the connection
     *
     *  @see JMSServiceReply#getJMQVersion
     *  @see JMSServiceReply#getJMQConnectionID
     *  @see JMSServiceReply#getJMQHA
     *  @see JMSServiceReply#getJMQClusterID
     *  @see JMSServiceReply#getJMQMaxMsgBytes
     *
     *  @throws JMSServiceException If the Status returned for the
     *          createConnection method is not {@link JMSServiceReply.Status#OK}
     */
    public JMSServiceReply createConnection(String username, String password,
                        JMSServiceBootStrapContext ctx)
          throws JMSServiceException  {
  JMSServiceReply reply;
  HashMap props = new HashMap();
        IMQConnection cxn = null;

  try  {
            cxn = createDirectConnection(username, password);
  } catch (BrokerException be)  {
      String errStr = "Failed to create direct connection for user: "
      + username;
       
            logger.logStack(Logger.ERROR, errStr, be);
      props.put("JMQStatus", JMSServiceReply.Status.ERROR);
      throw new JMSServiceException(errStr, be, props);
  }

  props.put("JMQStatus", JMSServiceReply.Status.OK);
  props.put("JMQConnectionID", cxn.getConnectionUID().longValue());
  reply = new JMSServiceReply(props, null);

  return (reply);
    }

    /**
     *  Destroy a connection.
     *
     *  @param connectionId The Id of the connection to destroy
     *
     *  @return The JMSServiceReply of the request to destroy the connection
     *
     *  @throws JMSServiceException If the Status returned for the
     *          destroyConnection method is not
     *          {@link JMSServiceReply.Status#OK}
     */
    public JMSServiceReply destroyConnection(long connectionId) throws JMSServiceException {
    IMQConnection cxn;
    HashMap props = new HashMap();
    JMSServiceReply reply;

    if (getState() == ServiceState.STOPPED) {
      // too late to do anything
    } else {

      cxn = checkConnectionId(connectionId, "destroyConnection");

      /*
       * Remove reference to connection in local list
       * XXX: TBD - Should really call removeConnection() here
       */
      localConnectionList.remove(cxn.getConnectionUID());

      cxn.destroyConnection(false /* no reply */, GoodbyeReason.CLIENT_CLOSED, Globals.getBrokerResources()
          .getKString(BrokerResources.M_CLIENT_SHUTDOWN));

    }

    props.put("JMQStatus", JMSServiceReply.Status.OK);
    reply = new JMSServiceReply(props, null);
    return (reply);
  }

    /**
     *  Generate a set of Unique IDs.<br>
     *  Each Unique ID generated has the following properties:
     *    <UL>
     *       <LI>It will stay unique for a very long time (years)</LI>
     *       <LI>It will be unique across all other IDs gneerated in the Broker
     *           (ConnectionID, ConsumerID, TransactionID</LI>
     *       <LI>It will be unique acrosss all brokers in the cluster</LI>
     *    </UL>
     *
     *  @param  connectionId The Id of the connection
     *  @param  quantity The number of Unique IDs to generate
     *
     *  @return An array of size 'quantity' of long Unique IDs
     */
    public long[] generateUID(long connectionId, int quantity)
        throws JMSServiceException  {
  IMQConnection  cxn = null;
  HashMap props = new HashMap();
  long  ids[];

        cxn = checkConnectionId(connectionId, "generateUID");

  if (quantity < 0)  {
      String errStr = "generateUID: quantity is less than 0: "
      + quantity;

            logger.log(Logger.ERROR, errStr);

      props.put("JMQStatus", JMSServiceReply.Status.ERROR);
      throw new JMSServiceException(errStr, props);
  }

  if (quantity == 0)  {
      return (null);
  }

  ids = new long [ quantity ];
  short prefix = UID.getPrefix();
  for (int i = 0; i < quantity; i++) {
      ids[i] = UniqueID.generateID(prefix);
  }

  return (ids);
    }

    /**
     *  Generate a Unique ID<br>
     *  The Unique ID generated has the following properties:
     *    <UL>
     *       <LI>It will stay unique for a very long time (years)</LI>
     *       <LI>It will be unique across all other IDs gneerated in the Broker
     *           (ConnectionID, ConsumerID, TransactionID</LI>
     *       <LI>It will be unique acrosss all brokers in the cluster</LI>
     *    </UL>
     *
     *  @param  connectionId The Id of the connection
     *
     *  @return The Unique ID
     */
    public long generateUID(long connectionId) throws JMSServiceException  {
  long oneId[] = generateUID(connectionId, 1);

  return (oneId[0]);
    }

    /**
     *  Set the clientId for a connection.
     *
     *  @param connectionId The Id of the connection to set the clientId on
     *  @param clientId The clientId to be set
     *  @param shareable If <code>true</code> then the clientId can be shared
     *                   with other connections.
     *                   If <code>false</code>, it cannot be shared.
     *  @param nameSpace The scope for clientId sharing.<p>
     *                   The server must ensure that all clientId requests
     *                   within a single namespace are unique.
     *
     *  @return The JMSServiceReply of the request to set the clientId on the
     *          connection.
     *
     *  @throws JMSServiceException if the Status returned for the setClientId
     *          method is not {@link JMSServiceReply.Status#OK}
     *
     *  @see JMSServiceReply.Status#BAD_REQUEST
     *  @see JMSServiceReply.Status#CONFLICT
     *  @see JMSServiceReply.Status#ERROR
     */
    public JMSServiceReply setClientId(long connectionId, String clientId,
                    boolean shareable, String nameSpace)
        throws JMSServiceException  {
  IMQConnection cxn = null;
  JMSServiceReply reply;
  HashMap props = new HashMap();

        cxn = checkConnectionId(connectionId, "setClientId");

  try  {
      protocol.setClientID(cxn, clientId, nameSpace, shareable);
  } catch(BrokerException be)  {
      String errStr = "setClientId: set client ID failed. Connection ID: "
      + connectionId
      + ", Client ID: "
      + clientId
      + ", Shareable: "
      + shareable
      + ", nameSpace: "
      + nameSpace;

            logger.logStack(Logger.ERROR, errStr, be);

      props.put("JMQStatus", getErrorReplyStatus(be));
      throw new JMSServiceException(errStr, be, props);
  }

  props.put("JMQStatus", JMSServiceReply.Status.OK);
  reply = new JMSServiceReply(props, null);
  return (reply);
    }
   
    /**
     *  Unset the clientId for a connection.
     *
     *  @param connectionId The Id of the connection whose clientId is to be unset
     *
     *  @return The JMSServiceReply of the request to unset the clientId on the
     *          connection.
     *
     *  @throws JMSServiceException if the Status returned for the unsetClientId
     *          method is not {@link JMSServiceReply.Status#OK}
     *
     *  @see JMSServiceReply.Status#BAD_REQUEST
     *  @see JMSServiceReply.Status#CONFLICT
     *  @see JMSServiceReply.Status#ERROR
     *
     */
    public JMSServiceReply unsetClientId(long connectionId)
      throws JMSServiceException  {
  JMSServiceReply reply;
  HashMap props = new HashMap();
  IMQConnection cxn;

        cxn = checkConnectionId(connectionId, "unsetClientId");

  try  {
      /*
       * Passing null clientId means unset it.
       */
      protocol.setClientID(cxn, null, null, false);
  } catch(BrokerException be)  {
      String errStr = "unsetClientId: unset client ID failed. Connection ID: "
      + connectionId;

            logger.logStack(Logger.ERROR, errStr, be);
      props.put("JMQStatus", JMSServiceReply.Status.ERROR);
      throw new JMSServiceException(errStr, be, props);
  }

  props.put("JMQStatus", JMSServiceReply.Status.OK);
  reply = new JMSServiceReply(props, null);

  return (reply);
    }

    /**
     *  Start messge delivery for a connection.<p>
     *  Message delivery is threaded per session with all the consumers for a
     *  single session  being called using the same thread.
     *
     *  @param connectionId The Id of the connection on which to start delivery
     *
     *  @return The JMSServiceReply of the request to start the connection.
     *
     *  @throws JMSServiceException if the Status returned for the
     *          startConnection method is not {@link JMSServiceReply.Status#OK}
     *
     *  @see JMSServiceReply.Status#ERROR
     *
     */
    public JMSServiceReply startConnection(long connectionId)
                throws JMSServiceException  {
  JMSServiceReply reply;
  HashMap props;
  IMQConnection cxn;

        cxn = checkConnectionId(connectionId, "startConnection");
  protocol.resumeConnection(cxn);

  /*
   * TBD Verify!
         */
        SessionListener.startConnection(cxn);

  props = new HashMap();
  props.put("JMQStatus", JMSServiceReply.Status.OK);
  reply = new JMSServiceReply(props, null);

  return (reply);
    }

    /**
     *  Stop message delivery for a connection.
     *
     *  @param connectionId The Id of the connection on which to stop delivery
     *
     *  @return The JMSServiceReply of the request to stop the connection.
     *
     *  @throws JMSServiceException if the Status returned for the
     *          stopConnection method is not {@link JMSServiceReply.Status#OK}
     *
     *  @see JMSServiceReply.Status#ERROR
     *
     */
    public JMSServiceReply stopConnection(long connectionId)
            throws JMSServiceException  {
  JMSServiceReply reply;
  HashMap props;
  IMQConnection cxn;

        cxn = checkConnectionId(connectionId, "stopConnection");

  protocol.pauseConnection(cxn);

  /*
   * TBD Verify!
         */
        SessionListener.stopConnection(cxn);

  props = new HashMap();
  props.put("JMQStatus", JMSServiceReply.Status.OK);
  reply = new JMSServiceReply(props, null);

  return (reply);
    }


    /**
     *  Create a session within a connection.
     *
     *  @param connectionId The Id of the connection in which the session is to
     *                      be created
     *  @param ackMode The acknowledgement mode of the session to be created
     *
     *  @return The JMSServiceReply of the request to create a session. The Id
     *          of the session is obtained from the JMSServiceReply
     *
     *  @throws JMSServiceException if the Status returned for the
     *          createSession method is not {@link JMSServiceReply.Status#OK}
     *
     *  @see JMSServiceReply.Status#ERROR
     *  @see JMSServiceReply#getJMQSessionID
     */

    public JMSServiceReply createSession(long connectionId, SessionAckMode ackMode)
        throws JMSServiceException  {
  JMSServiceReply reply;
  HashMap props = new HashMap();
  IMQConnection cxn;
  long sessionID = 0;

        cxn = checkConnectionId(connectionId, "createSession");

  try  {
      int brokerAckMode;

      brokerAckMode = convertToBrokerAckMode(ackMode);

      Session s = protocol.createSession(brokerAckMode, cxn);
        new SessionListener(this, s); // create a thread
      sessionID = s.getSessionUID().longValue();
  } catch(BrokerException be)  {
      String errStr = "createSession: create session failed. Connection ID: "
      + connectionId
      + ", acknowledge mode: "
      + ackMode;

            logger.logStack(Logger.ERROR, errStr, be);
      props.put("JMQStatus", getErrorReplyStatus(be));
      throw new JMSServiceException(errStr, be, props);
  }

  props.put("JMQStatus", JMSServiceReply.Status.OK);
  props.put("JMQSessionID", sessionID);
  reply = new JMSServiceReply(props, null);

  return (reply);
    }
   
    /**
     *  Destroy a session.
     *
     *  @param connectionId The Id of the connection
     *  @param sessionId The Id of the session to be destroyed
     *
     *  @return The JMSServiceReply of the request to destroy the session
     *
     *  @throws JMSServiceException If the Status returned for the
     *          destroySession method is not
     *          {@link JMSServiceReply.Status#OK}
     *
     */
    public JMSServiceReply destroySession(long connectionId, long sessionId)
        throws JMSServiceException  {
  JMSServiceReply reply;
  HashMap props = new HashMap();
  IMQConnection cxn;
  SessionUID sUID;

        cxn = checkConnectionId(connectionId, "destroySession");

  sUID = new SessionUID(sessionId);

  try  {
      protocol.destroySession(sUID, cxn);

        // let the session listener go
       SessionListener.getListener(sUID).destroy();
  } catch(BrokerException be)  {
      String errStr = "destroySession: destroy session failed. Connection ID: "
      + connectionId
      + ", Session ID: "
      + sessionId;

            logger.logStack(Logger.ERROR, errStr, be);
      props.put("JMQStatus", JMSServiceReply.Status.ERROR);
      throw new JMSServiceException(errStr, be, props);
  }

  props.put("JMQStatus", JMSServiceReply.Status.OK);
  reply = new JMSServiceReply(props, null);

  return (reply);
    }

    /**
     *  Start messge delivery for a session.<p>
     *
     *  @param  connectionId The Id of the connection
     *  @param  sessionId The Id of the session on which to start delivery
     *
     *  @return The JMSServiceReply of the request to start the session.
     *
     *  @throws JMSServiceException if the Status returned for the
     *          startSession method is not {@link JMSServiceReply.Status#OK}
     *
     *  @see JMSServiceReply.Status#ERROR
     *
     */
    public JMSServiceReply startSession(long connectionId, long sessionId)
                throws JMSServiceException  {
  JMSServiceReply reply;
  HashMap props = new HashMap();
  SessionUID sUID;
  IMQConnection cxn;

        cxn = checkConnectionId(connectionId, "startSession");
  sUID = new SessionUID(sessionId);

  try  {
    // CR 6935676
      //protocol.resumeSession(sUID);
      /*
       * TBD Verify!
             */
            SessionListener.getListener(sUID).startSession();
  } catch(Exception e)  {
      String errStr = "startSession: Start of session failed. Session ID: "
                + sessionId;

            logger.logStack(Logger.ERROR, errStr, e);
      props.put("JMQStatus", JMSServiceReply.Status.ERROR);
      throw new JMSServiceException(errStr, e, props);
  }

  props.put("JMQStatus", JMSServiceReply.Status.OK);
  reply = new JMSServiceReply(props, null);

  return (reply);
    }

    /**
     *  Stop message delivery for a session.
     *
     *  @param  connectionId The Id of the connection
     *  @param  sessionId The Id of the session on which to stop delivery
     *
     *  @return The JMSServiceReply of the request to stop the session
     *
     *  @throws JMSServiceException if the Status returned for the
     *          stopSession method is not {@link JMSServiceReply.Status#OK}
     *
     *  @see JMSServiceReply.Status#ERROR
     *
     */
    public JMSServiceReply stopSession(long connectionId, long sessionId)
          throws JMSServiceException  {
  JMSServiceReply reply;
  HashMap props = new HashMap();
  SessionUID sUID;
  IMQConnection cxn;

        cxn = checkConnectionId(connectionId, "stopSession");
  sUID = new SessionUID(sessionId);

  try {
    // CR 6935676
      //protocol.pauseSession(sUID);
      /*
       * TBD Verify!
             */
            SessionListener.getListener(sUID).stopSession();
  } catch(Exception e)  {
      String errStr = "stopSession: Stop of session failed. Session ID: "
            + sessionId;

            logger.logStack(Logger.ERROR, errStr, e);
      props.put("JMQStatus", JMSServiceReply.Status.ERROR);
      throw new JMSServiceException(errStr, e, props);
  }

  props.put("JMQStatus", JMSServiceReply.Status.OK);
  reply = new JMSServiceReply(props, null);

  return (reply);
    }

    /**
     *  Verify the existence / auto-createability of a physical destination.<p>
     *  If the destination exists the Status returned is OK.<br>
     *  If the destination does not exist but can be auto-created the Status
     *  returned is NOT_FOUND along with the JMQCanCreate property is set to
     *  true.<br>
     *  If the destination does not exist and cannot be auto-created the Status
     *  returned is NOT_FOUND along with JMQCanCreate property set to false.
     * 
     *  @param  connectionId The Id of the connection
     *  @param  dest The Destination object that defines the physical destination
     *
     *  @return The JMSServiceReply of the request to verify the destination
     *
     *  @throws JMSServiceException if the Status returned for the
     *          verifyDestination method is not either
     *          {@link JMSServiceReply.Status#OK} or
     *          {@link JMSServiceReply.Status#NOT_FOUND}
     *
     *  @see JMSServiceReply#getJMQCanCreate
     *  @see JMSServiceReply#getJMQDestType
     *
     *  @see JMSServiceReply.Status#NOT_FOUND
     *  @see JMSServiceReply.Status#FORBIDDEN
     *  @see JMSServiceReply.Status#BAD_REQUEST
     *  @see JMSServiceReply.Status#ERROR
     */
    public JMSServiceReply verifyDestination(long connectionId,
            Destination dest) throws JMSServiceException  {
  JMSServiceReply reply;
  HashMap props = new HashMap();
  IMQConnection cxn;
  HashMap resultProps = null;

        cxn = checkConnectionId(connectionId, "verifyDestination");

  try  {
      resultProps = protocol.verifyDestination(dest.getName(),
      (dest.getType() == Destination.Type.QUEUE) ?
          DestType.DEST_TYPE_QUEUE : DestType.DEST_TYPE_TOPIC,
       null /* selector param not needed ? */);
  } catch(Exception e)  {
      String errStr = "verifyDestination: verify of destination failed. Destination name: "
      + dest.getName()
      + ", type: "
      + dest.getType();

            logger.logStack(Logger.ERROR, errStr, e);
      props.put("JMQStatus", JMSServiceReply.Status.ERROR);
      throw new JMSServiceException(errStr, e, props);
  }

  if (resultProps != null)  {
      Integer status = (Integer)resultProps.get("JMQStatus");

      if (status != null)  {
          if (status.intValue()
      == com.sun.messaging.jmq.io.Status.OK)  {
              props.put("JMQStatus", JMSServiceReply.Status.OK);
          } else if (status.intValue()
      == com.sun.messaging.jmq.io.Status.NOT_FOUND)  {
              Boolean canCreate = (Boolean)resultProps.get("JMQCanCreate");

              props.put("JMQStatus", JMSServiceReply.Status.NOT_FOUND);
        if (canCreate != null)  {
                  props.put("JMQCanCreate", canCreate);
        }
          }
      }
  }

  props.put("JMQDestination", dest.getName());
  props.put("JMQDestType", dest.getType());

  reply = new JMSServiceReply(props, null);

  return (reply);
    }

    /**
     *  Create a physical destination.
     *
     *  @param connectionId The Id of the connection
     *  @param dest The Destination object that defines the physical destination
     *              to be created.
     *              <p>If the physical destination does not exist, it will be
     *              automatically created if the configuration allows. [DEFAULT]
     *
     *  @return The JMSServiceReply of the request to create the destination
     *
     *  @throws JMSServiceException if the Status returned for the
     *          createDestination method is not {@link JMSServiceReply.Status#OK}
     *
     *  @see JMSServiceReply#getJMQDestType
     *  @see JMSServiceReply.Status#ERROR
     */
    public JMSServiceReply createDestination(long connectionId,
            Destination dest) throws JMSServiceException  {
  JMSServiceReply reply;
  HashMap props = new HashMap();
  IMQConnection cxn;

        cxn = checkConnectionId(connectionId, "createDestination");

  int internalDestType;
  if (dest.getType() == Destination.Type.QUEUE)  {
      internalDestType = DestType.DEST_TYPE_QUEUE;
  } else  {
      internalDestType = DestType.DEST_TYPE_TOPIC;
  }

  if (dest.getLife() == Destination.Life.TEMPORARY)  {
      internalDestType |= DestType.DEST_TEMP;
  }

        if (cxn.isAdminConnection()) {
      /*
       * Copied from
       * com.sun.messaging.jmq.jmsserver.data.handlers.DestinationHandler
       *
       * Not sure why DestType.DEST_AUTO is included here.
       */
            internalDestType |= DestType.DEST_ADMIN | DestType.DEST_LOCAL
                                | DestType.DEST_AUTO;
        }

  String errStr = "createDestination: Destination creation failed. Destination name: "
      + dest.getName()
      + ", type: "
      + dest.getType()
      + ", lifespan: "
      + dest.getLife();
  try  {
            com.sun.messaging.jmq.jmsserver.core.Destination d =null;

      d = protocol.createDestination(dest.getName(), internalDestType, cxn, acEnabled);
  } catch(BrokerException be)  {
            logger.logStack(Logger.ERROR, errStr, be);

      int status = be.getStatusCode();
      if (status == Status.CONFLICT)  {
          props.put("JMQStatus", JMSServiceReply.Status.CONFLICT);
      } else if (status == Status.FORBIDDEN)  {
          props.put("JMQStatus", JMSServiceReply.Status.FORBIDDEN);
      } else  {
          props.put("JMQStatus", JMSServiceReply.Status.ERROR);
      }

      throw new JMSServiceException(errStr, be, props);
  } catch (IOException ioe)  {
            logger.logStack(Logger.ERROR, errStr, ioe);

      props.put("JMQStatus", JMSServiceReply.Status.ERROR);
      throw new JMSServiceException(errStr, ioe, props);
  } catch (AccessControlException ace)  {
            logger.logStack(Logger.ERROR, errStr, ace);

      props.put("JMQStatus", JMSServiceReply.Status.FORBIDDEN);
      throw new JMSServiceException(errStr, ace, props);
  }

  props.put("JMQStatus", JMSServiceReply.Status.OK);
  props.put("JMQDestination", dest.getName());
  props.put("JMQDestType", dest.getType());
  reply = new JMSServiceReply(props, null);

  return (reply);
    }

    /**
     *  Destroy a physical destination.
     *
     *  @param connectionId The Id of the connection
     *  @param dest The Destination object that identifies the physical
     *              destination to be destroyed
     *
     *  @return The JMSServiceReply of the request to destroy the destination
     *
     *  @throws JMSServiceException if the Status returned for the
     *          destroyDestination method is not
     *          {@link JMSServiceReply.Status#OK}
     *
     *  @see JMSServiceReply.Status#ERROR
     *
     */
    public JMSServiceReply destroyDestination(long connectionId,
            Destination dest) throws JMSServiceException  {
  JMSServiceReply reply;
  HashMap props = new HashMap();
  IMQConnection cxn;

        cxn = checkConnectionId(connectionId, "destroyDestination");

  try  {
            com.sun.messaging.jmq.jmsserver.core.Destination d =null;

            com.sun.messaging.jmq.jmsserver.core.DestinationUID rmuid =
    com.sun.messaging.jmq.jmsserver.core.DestinationUID.getUID(
      dest.getName(),
            (dest.getType() == Destination.Type.QUEUE));

            assert com.sun.messaging.jmq.jmsserver.core.Destination.getDestination(rmuid)
      != null;

            com.sun.messaging.jmq.jmsserver.core.Destination.removeDestination(
        rmuid, true,
                    Globals.getBrokerResources().getString(
                    BrokerResources.M_CLIENT_REQUEST, cxn.getConnectionUID()));
  } catch(Exception e)  {
      String errStr = "destroyDestination: Destination destroy failed. Destination name: "
      + dest.getName()
      + ", type: "
      + dest.getType()
      + ", lifespan: "
      + dest.getLife();

            logger.logStack(Logger.ERROR, errStr, e);
      props.put("JMQStatus", getErrorReplyStatus(e));
      throw new JMSServiceException(errStr, e, props);
  }

  props.put("JMQStatus", JMSServiceReply.Status.OK);
  reply = new JMSServiceReply(props, null);

  return (reply);
    }

    /**
     *  Add a producer.
     *
     *  @param connectionId The Id of the connection
     *  @param sessionId The Id of the session in which to add the producer
     *  @param dest The Destination on which to add a producer
     *
     *  @return The JMSServiceReply of the request to add a producer
     *
     *  @throws JMSServiceException if the Status returned for the
     *          addProducer method is not {@link JMSServiceReply.Status#OK}
     *
     *  @see JMSServiceReply.Status#getJMQProducerID
     *
     *  @see JMSServiceReply.Status#FORBIDDEN
     *  @see JMSServiceReply.Status#NOT_FOUND
     *  @see JMSServiceReply.Status#CONFLICT
     *  @see JMSServiceReply.Status#ERROR
     *
     */
    public JMSServiceReply addProducer(long connectionId, long sessionId,
            Destination dest) throws JMSServiceException  {

  JMSServiceReply reply;
  Session session;
  HashMap props = new HashMap();
  IMQConnection cxn;
  com.sun.messaging.jmq.jmsserver.core.Destination d;
  com.sun.messaging.jmq.jmsserver.core.Producer prd = null;
  long producerID = 0;

        cxn = checkConnectionId(connectionId, "addProducer");
        session = checkSessionId(sessionId, "addProducer");

  try  {
            d = com.sun.messaging.jmq.jmsserver.core.Destination.getDestination(dest.getName(),
           (dest.getType() == Destination.Type.QUEUE));

            prd = protocol.addProducer(d, cxn, new Object().toString(), acEnabled);
      producerID = prd.getProducerUID().longValue();
  } catch(Exception e)  {
      String errStr = "addProducer: Add producer failed. Connection ID: "
      + connectionId
      + ", session ID: "
      + sessionId;

            logger.logStack(Logger.ERROR, errStr, e);
      props.put("JMQStatus", getErrorReplyStatus(e));
      throw new JMSServiceException(errStr, e, props);
  }

  props.put("JMQStatus", JMSServiceReply.Status.OK);
  props.put("JMQProducerID", producerID);
  reply = new JMSServiceReply(props, null);

  return (reply);
    }

    /**
     *  Delete a producer.
     *
     *  @param  connectionId The Id of the connection in which to delete the
     *          producer
     *  @param  sessionId The Id of the session in which to delete the producer
     *  @param  producerId The Id of the producer to delete
     *
     *  @return The JMSServiceReply of the request to delete a producer
     *
     *  @throws JMSServiceException if the Status returned for the
     *          deleteProducer method is not {@link JMSServiceReply.Status#OK}
     *
     *  @see JMSServiceReply.Status#FORBIDDEN
     *  @see JMSServiceReply.Status#NOT_FOUND
     *  @see JMSServiceReply.Status#ERROR
     *
     */
    public JMSServiceReply deleteProducer(long connectionId, long sessionId,
            long producerId) throws JMSServiceException  {

  JMSServiceReply reply;
  HashMap props = new HashMap();
  IMQConnection cxn;

        cxn = checkConnectionId(connectionId, "deleteProducer");

  try  {
            protocol.removeProducer(new ProducerUID(producerId),
      cxn, new Object().toString());
  } catch(Exception e)  {
      String errStr = "deleteProducer: Delete producer failed. Connection ID: "
      + connectionId
      + ", session ID: "
      + sessionId
      + ", producer ID: "
      + producerId;

            logger.logStack(Logger.ERROR, errStr, e);
      props.put("JMQStatus", getErrorReplyStatus(e));
      throw new JMSServiceException(errStr, e, props);
  }

  props.put("JMQStatus", JMSServiceReply.Status.OK);
  reply = new JMSServiceReply(props, null);

  return (reply);
    }

    /**
     *  Add a consumer.<p> The initial state of the consumer must be the
     *  <u>sync</u> state.
     *
     *  @param  connectionId The Id of the connection in which to add the
     *          consumer
     *  @param  sessionId The Id of the session in which to add the consumer.
     *          The acknowledgement mode of the consumer will be that of the
     *          session
     *  @param  dest The Destination from which the consumer will receive
     *          messages
     *  @param  selector The selector which will be used to filter messages
     *  @param  durableName If non-null, and dest is a Topic, this consumer is
     *          a durable subscription and this parameter will be the name
     *          assigned to the durable subscription. A non-null, empty
     *          durableName is an error.
     *  @param  clientId The clientId to use when this is a durable subscription
     *          with a non-null durableName. This clientId must match the one
     *          that has been set on the connection previously.
     *  @param  noLocal If {@code true}, consumer does not wnat to receive
     *          messages produced on the same connection<br>
     *          If {@code false}, consumer wants to receive messages produced
     *          on the same connection as well.
     *  @param  shared If {@code true}, and dest is a Topic, this is a
     *          shared consumer and messages will be shared with other
     *          consumers in the same group that have the same
     *          clientId+DurableName for Shared Durable Subscriptions<p>
     *          OR<p>
     *          clientId+TopicName+Selector for Shared Non-Durable Sunscriptions
     *
     *  @return The JMSServiceReply of the request to add a consumer
     *
     *  @throws JMSServiceException if the Status returned for the
     *          addConsumer method is not {@link JMSServiceReply.Status#OK}
     *
     *  @see JMSService#setConsumerAsync
     *
     *  @see JMSServiceReply.Status#getJMQConsumerID
     *
     *  @see JMSServiceReply.Status#FORBIDDEN
     *  @see JMSServiceReply.Status#BAD_REQUEST
     *  @see JMSServiceReply.Status#NOT_FOUND
     *  @see JMSServiceReply.Status#NOT_ALLOWED
     *  @see JMSServiceReply.Status#PRECONDITION_FAILED
     *  @see JMSServiceReply.Status#CONFLICT
     *  @see JMSServiceReply.Status#ERROR
     *
     */
    public JMSServiceReply addConsumer(long connectionId, long sessionId,
            Destination dest, String selector, String durableName,
            String clientId, boolean noLocal, boolean shared)
                                    throws JMSServiceException  {
  JMSServiceReply reply;
  IMQConnection cxn;
  HashMap props = new HashMap();
  com.sun.messaging.jmq.jmsserver.core.Destination d;
  Session session;
  com.sun.messaging.jmq.jmsserver.core.Consumer con;
  int size = 1000;
  long consumerID = 0;

        cxn = checkConnectionId(connectionId, "addConsumer");
        session = checkSessionId(sessionId, "addConsumer");

  try  {
            d = com.sun.messaging.jmq.jmsserver.core.Destination.getDestination(dest.getName(),
           (dest.getType() == Destination.Type.QUEUE));

      /*
       * size (prefetch size) is not needed here since the broker is going to
       * call the client method with the messages, not simply dump packets
       * till a particular size is reached.
       */
            boolean useFlowControl=false;
            con = protocol.createConsumer(d, cxn,
                        session, selector, clientId,
                        durableName, noLocal, size,
                        shared, new Object().toString(), acEnabled, useFlowControl);
      consumerID = con.getConsumerUID().longValue();
  } catch(Exception e)  {
      String errStr = "addConsumer: Add consumer failed. Connection ID: "
      + connectionId
      + ", session ID: "
      + sessionId;

            logger.logStack(Logger.ERROR, errStr, e);
      if (e instanceof SelectorFormatException)  {
          props.put("JMQStatus", JMSServiceReply.Status.BAD_REQUEST);
      } else  {
          props.put("JMQStatus", getErrorReplyStatus(e));
      }
      throw new JMSServiceException(errStr, e, props);
  }

  props.put("JMQStatus", JMSServiceReply.Status.OK);
  props.put("JMQConsumerID", consumerID);
  reply = new JMSServiceReply(props, null);

  return (reply);
    }

    /**
     *  Delete a consumer.<p>
     *  If this operation is deleting a consumer that is a durable subscription,
     *  then the durableName <b>and</b> the clientId must be non-null. In
     *  addition, the clientId must match the clientId that is currently set
     *  on the connection identified by  connectionId.
     *
     *  @param  connectionId The Id of the connection
     *  @param  sessionId The Id of the session
     *  @param  consumerId The Id of the consumer to delete
     *  @param  durableName The name of the durable subscription to remove
     *          if the consumer is unsubscribing.
     *  @param  clientId The clientId of the connection
     *
     *  @return The JMSServiceReply of the request to delete a consumer
     *
     *  @throws JMSServiceException if the Status returned for the
     *          deleteConsumer method is not {@link JMSServiceReply.Status#OK}
     *
     *  @see JMSServiceReply.Status#FORBIDDEN
     *  @see JMSServiceReply.Status#NOT_FOUND
     *  @see JMSServiceReply.Status#PRECONDITION_FAILED
     *  @see JMSServiceReply.Status#CONFLICT
     *  @see JMSServiceReply.Status#ERROR
     *
     */
    public JMSServiceReply deleteConsumer(long connectionId, long sessionId,
            long consumerId, String durableName, String clientId)
      throws JMSServiceException  {
  JMSServiceReply reply;
  IMQConnection cxn;
  Session session;
  HashMap props = new HashMap();
  com.sun.messaging.jmq.jmsserver.core.Consumer con;

        cxn = checkConnectionId(connectionId, "deleteConsumer");
        session = checkSessionId(sessionId, "deleteConsumer");

  try  {
      if (durableName == null)  {
          ConsumerUID conUID = new ConsumerUID(consumerId);
                protocol.destroyConsumer(conUID, session, cxn);
      } else  {
                protocol.unsubscribe(durableName, clientId);
      }
  } catch(Exception e)  {
      String errStr = "deleteConsumer: Delete consumer failed. Connection ID: "
      + connectionId
      + ", session ID: "
      + sessionId
      + ", consumer ID: "
      + consumerId
      + ", durable name: "
      + durableName
      + ", client ID: "
      + clientId;

            logger.logStack(Logger.ERROR, errStr, e);
      props.put("JMQStatus", getErrorReplyStatus(e));
      throw new JMSServiceException(errStr, e, props);
  }

  props.put("JMQStatus", JMSServiceReply.Status.OK);
  reply = new JMSServiceReply(props, null);

  return (reply);
    }

    /**
     *  Configure a consumer for async or sync message consumption.<p>
     *  This method is used to enable and disable async delivery of messages
     *  from the broker to the client.
     *
     *  @param  connectionId The Id of the connection
     *  @param  sessionId The Id of the session
     *  @param  consumerId The Id of the consumer for which the async state is
     *          being set.
     *  @param  consumer The Consumer object that is to be used to deliver the
     *          message.<br>
     *          If <b>non-null</b>, the consumer is being set
     *          into the <u>async</u> state and the server must start delivering
     *          messagesto the {@code Consumer.deliver()} method when the
     *          connectionId and sessionId have been started via the
     *          {@code startConnection} and {@code startSession} methods.<br>
     *          If <b>null</b>, the consumer is being set into the <u>sync</u>
     *          state and the delivery of messages must stop.<br>
     *          The session must first be stopped, before changing a
     *          consumer from the async state to the sync state. However, the
     *          connection and session are not required to be stopped when
     *          a consumer is changed from the sync state, which is the default
     *          for {@code addConsumer()}, to the async state.
     *
     *  @throws JMSServiceException if the Status returned for the
     *          setConsumerAsync method is not {@link JMSServiceReply.Status#OK}
     *
     *  @see JMSService#startConnection
     *  @see JMSService#startSession
     *  @see JMSService#stopSession
     *  @see Consumer#deliver
     *
     *  @see JMSServiceReply.Status#NOT_FOUND
     *  @see JMSServiceReply.Status#CONFLICT
     *  @see JMSServiceReply.Status#ERROR
     *
     */
    public JMSServiceReply setConsumerAsync(long connectionId, long sessionId,
            long consumerId, Consumer consumer)
                        throws JMSServiceException  {
  JMSServiceReply reply;
  IMQConnection cxn;
  HashMap props = new HashMap();
  com.sun.messaging.jmq.jmsserver.core.Destination d;
  Session session;
  com.sun.messaging.jmq.jmsserver.core.Consumer con;
  int size = -1;

        cxn = checkConnectionId(connectionId, "setConsumerAsync");
        session = checkSessionId(sessionId, "setConsumerAsync");

  try  {
      ConsumerUID conUID = new ConsumerUID(consumerId);
      con = com.sun.messaging.jmq.jmsserver.core.Consumer.getConsumer(conUID);

            // register it as an asychronous listener
            SessionListener slistener = SessionListener.getListener(session.getSessionUID());
            slistener.setAsyncListener(con, consumer);
  } catch(Exception e)  {
      String errStr = "setConsumerAsync: Set Async consumer failed. Connection ID: "
      + connectionId
      + ", session ID: "
      + sessionId
      + ", consumer ID: "
      + consumerId;

            logger.logStack(Logger.ERROR, errStr, e);
      props.put("JMQStatus", JMSServiceReply.Status.ERROR);
      throw new JMSServiceException(errStr, e, props);
  }

  props.put("JMQStatus", JMSServiceReply.Status.OK);
  props.put("JMQConsumerID", consumerId);
  reply = new JMSServiceReply(props, null);

  return (reply);
    }


    /**
     *  Start a transaction.
     *
     *  @param connectionId The Id of the connection
     *  @param sessionId If non-zero, this is the Id of the session in which the
     *                   transaction is being created. This parameter is zero
     *                   for XA transactions
     *  @param xid If non-null, an XA transaction is being started
     *  @param flags If xId is non-null, then flags is one of:<p>
     <UL>
     <LI>XAResource.TMNOFLAGS = start a brand new transaction</LI>
     <LI>XAResource.TMRESUNE = resume a previously suspended transaction</LI>
     </UL>
     @param  rollback The type of transaction rollback behavior to use
     *  @param  timeout The transaction timeout to use. The timeout is the
     *          maximum time in seconds that the transaction will be allowed to
     *          be in an un-prepared state.
     *
     *  @return The JMSServiceReply of the request to start a transaction
     *
     *  @throws JMSServiceException if the Status returned for the
     *          startTransaction method is not {@link JMSServiceReply.Status#OK}
     *
     *
     */
    public JMSServiceReply startTransaction(long connectionId, long sessionId, Xid xid,
                        int flags, JMSService.TransactionAutoRollback rollback,
      long timeout) throws JMSServiceException  {
  JMSServiceReply reply;
  HashMap props = new HashMap();
  IMQConnection cxn;
  TransactionUID txnUID = null;
  JMQXid jmqXid = null;
  Integer xaFlags = null;
  boolean isXA = false;
  AutoRollbackType type = null;

        cxn = checkConnectionId(connectionId, "startTransaction");

  if (xid != null)  {
      isXA = true;
      jmqXid = new JMQXid(xid);
      xaFlags = new Integer(flags);
  }

  try  {
      txnUID = protocol.startTransaction(jmqXid, xaFlags, type, timeout, cxn);
  } catch(BrokerException be)  {
      String errStr = "startTransaction: start transaction failed. Connection ID: "
      + connectionId
      + ", session ID: "
      + sessionId
      + ", XID: "
      + xid;

            logger.logStack(Logger.ERROR, errStr, be);
      props.put("JMQStatus", getErrorReplyStatus(be));
      throw new JMSServiceException(errStr, be, props);
  }

  props.put("JMQStatus", JMSServiceReply.Status.OK);
  props.put("JMQTransactionID", txnUID.longValue());
  reply = new JMSServiceReply(props, null);

  return (reply);
    }

    /**
     *  End a transaction.
     *
     *  @param  connectionId The Id of the connection
     *  @param  transactionId If non-zero, the transaction being ended is
     *          identified by this broker-generated id
     *  @param  xid If transactionId is zero, then xid contains the Xid of the
     *          XA transaction being ended
     *  @param  flags If this is an XA transaction, then flags is one of:
     *  <UL>
     <LI>XAResource.TMSUSPEND: If suspending a transaction</LI>
     <LI>XAResource.TMFAIL:    If failing a transaction</LI>
     <LI>XAResource.TMSUCCESS: If ending a transaction</LI>
     </UL>
    
     *  @return The JMSServiceReply of the request to end a transaction
     *
     *  @throws JMSServiceException if the Status returned for the
     *          endTransaction method is not {@link JMSServiceReply.Status#OK}
     *
     *  @see JMSServiceReply.Status#getJMQTransactionID
     *
     *  @see JMSServiceReply.Status#BAD_REQUEST
     *  @see JMSServiceReply.Status#NOT_FOUND
     *  @see JMSServiceReply.Status#PRECONDITION_FAILED
     *  @see JMSServiceReply.Status#TIMEOUT
     *  @see JMSServiceReply.Status#ERROR
     *
     */
    public JMSServiceReply endTransaction(long connectionId, long transactionId,
            Xid xid, int flags) throws JMSServiceException  {
  JMSServiceReply reply;
  HashMap props = new HashMap();
  IMQConnection cxn;
  TransactionUID txnUID = null;
  JMQXid jmqXid = null;
  Integer xaFlags = null;
  long tid = 0;

        cxn = checkConnectionId(connectionId, "endTransaction");

  txnUID = new TransactionUID(transactionId);

  if (xid != null)  {
      jmqXid = new JMQXid(xid);
      xaFlags = new Integer(flags);
  }

  try  {
      protocol.endTransaction(txnUID, jmqXid, xaFlags);
  } catch(BrokerException be)  {
      String errStr = "endTransaction: end transaction failed. Connection ID: "
      + connectionId
      + ", Transaction ID: "
      + transactionId
      + ", XID: "
      + xid;

            logger.logStack(Logger.ERROR, errStr, be);
      props.put("JMQStatus", getErrorReplyStatus(be));
      throw new JMSServiceException(errStr, be, props);
  }

  props.put("JMQStatus", JMSServiceReply.Status.OK);
  props.put("JMQTransactionID", txnUID.longValue());
  reply = new JMSServiceReply(props, null);

  return (reply);
    }

    /**
     *  Pepare a transaction.
     *
     *  @param  connectionId The Id of the connection
     *  @param  transactionId If non-zero, the transaction being prepared is
     *          identified by this broker-generated id
     *  @param  xid If transactionId is zero, then xid contains the Xid of the
     *          XA transaction being prepared
     * 
     *  @return The JMSServiceReply of the request to prepare a transaction
     *
     *  @throws JMSServiceException if the Status returned for the
     *          prepareTransaction method is not
     *          {@link JMSServiceReply.Status#OK}
     *
     *  @see JMSServiceReply.Status#getJMQTransactionID
     *
     *  @see JMSServiceReply.Status#BAD_REQUEST
     *  @see JMSServiceReply.Status#NOT_FOUND
     *  @see JMSServiceReply.Status#PRECONDITION_FAILED
     *  @see JMSServiceReply.Status#TIMEOUT
     *  @see JMSServiceReply.Status#ERROR
     *
     */
    public JMSServiceReply prepareTransaction(long connectionId,
            long transactionId, Xid xid) throws JMSServiceException  {
  JMSServiceReply reply;
  HashMap props = new HashMap();
  IMQConnection cxn;
  TransactionUID txnUID = null;
  JMQXid jmqXid = null;
  Integer xaFlags = null;

        cxn = checkConnectionId(connectionId, "prepareTransaction");

  /*
   * If transactionId is 0, extract it from XID
   */
  if (transactionId == 0)  {
      jmqXid = new JMQXid(xid);
      /*
      xaFlags = new Integer(flags);
      */
      txnUID = Globals.getTransactionList().xidToUID(jmqXid);
  } else  {
      txnUID = new TransactionUID(transactionId);
  }

  try  {
      protocol.prepareTransaction(txnUID, xaFlags);
  } catch(BrokerException be)  {
      String errStr = "prepareTransaction: prepare transaction failed. Connection ID: "
          + connectionId
          + ", Transaction ID: "
          + transactionId
          + ", XID: "
          + xid;

            logger.logStack(Logger.ERROR, errStr, be);
      props.put("JMQStatus", getErrorReplyStatus(be));
      throw new JMSServiceException(errStr, be, props);
  }

  props.put("JMQStatus", JMSServiceReply.Status.OK);
  props.put("JMQTransactionID", txnUID.longValue());
  reply = new JMSServiceReply(props, null);

  return (reply);
    }

    /**
     *  Commit a transaction.
     *
     *  @param  connectionId The Id of the connection
     *  @param  transactionId If non-zero, the transaction being committed is
     *          identified by this broker-generated id
     *  @param  xid If transactionId is zero, then xid contains the Xid of the
     *          XA transaction being committed
     *  @param  flags If this is an XA transaction, then flags is one of:
     *  <UL>
     <LI>XAResource.TMONEPHASE:One phase commit. The transaction need not be
     *                            in the PREPARED state</LI>
     <LI>XAResource.TMNOFLAGS: Two phase commit. The transaction must be in
     *                            the PREPARED state</LI>
     </UL>
    
     *  @return The JMSServiceReply of the request to commit a transaction
     *
     *  @throws JMSServiceException if the Status returned for the
     *          commitTransaction method is not
     *          {@link JMSServiceReply.Status#OK}
     *
     *  @see JMSServiceReply.Status#getJMQTransactionID
     *
     *  @see JMSServiceReply.Status#BAD_REQUEST
     *  @see JMSServiceReply.Status#NOT_FOUND
     *  @see JMSServiceReply.Status#PRECONDITION_FAILED
     *  @see JMSServiceReply.Status#TIMEOUT
     *  @see JMSServiceReply.Status#ERROR
     *
     */
    public JMSServiceReply commitTransaction(long connectionId,
            long transactionId, Xid xid, int flags)
        throws JMSServiceException  {
  JMSServiceReply reply;
  HashMap props = new HashMap();
  IMQConnection cxn;
  TransactionUID txnUID = null;
  JMQXid jmqXid = null;
  Integer xaFlags;
  long tid = 0;

        cxn = checkConnectionId(connectionId, "commitTransaction");

  txnUID = new TransactionUID(transactionId);
        if (xid != null)
      jmqXid = new JMQXid(xid);

  xaFlags = new Integer(flags);

  try  {
      protocol.commitTransaction(txnUID, jmqXid, xaFlags, cxn);
  } catch(BrokerException be)  {
      String errStr = "CommitTransaction: commit failed. Connection ID: "
      + connectionId
      + ", Transaction ID: "
      + transactionId;

            logger.logStack(Logger.ERROR, errStr, be);
      props.put("JMQStatus", getErrorReplyStatus(be));
      throw new JMSServiceException(errStr, be, props);
  }

  props.put("JMQStatus", JMSServiceReply.Status.OK);
  props.put("JMQTransactionID", txnUID.longValue());
  reply = new JMSServiceReply(props, null);

  return (reply);
    }

    /**
     *  Rollback a transaction.
     *
     *  @param  connectionId The Id of the connection
     *  @param  transactionId If non-zero, the transaction being rolledback is
     *          identified by this broker-generated id
     *  @param  xid If transactionId is zero, then xid contains the Xid of the
     *          XA transaction being rolledback
     *  @param  redeliver If <code>true</code>, then the broker must redeliver
     *          the messages that were rolledback by this operation.
     *  @param  setRedelivered If true <b><u>and</u></b> <code>redeliver</code>
     *          is <code>true</code> then the broker must set the
     *          REDELIVERED flag on messages it redelivers.
     * 
     *  @return The JMSServiceReply of the request to rollback a transaction
     *
     *  @throws JMSServiceException if the Status returned for the
     *          rollbackTransaction method is not
     *          {@link JMSServiceReply.Status#OK}
     *
     *  @see JMSServiceReply.Status#getJMQTransactionID
     *
     *  @see JMSServiceReply.Status#BAD_REQUEST
     *  @see JMSServiceReply.Status#NOT_FOUND
     *  @see JMSServiceReply.Status#PRECONDITION_FAILED
     *  @see JMSServiceReply.Status#TIMEOUT
     *  @see JMSServiceReply.Status#ERROR
     *
     */
    public JMSServiceReply rollbackTransaction(long connectionId,
            long transactionId, Xid xid, boolean redeliver,
            boolean setRedelivered) throws JMSServiceException  {
  JMSServiceReply reply;
  HashMap props = new HashMap();
  IMQConnection cxn;
  TransactionUID txnUID = null;
  JMQXid jmqXid = null;
  Integer xaFlags = null;

        cxn = checkConnectionId(connectionId, "rollbackTransaction");

  txnUID = new TransactionUID(transactionId);

  if (xid != null)  {
      jmqXid = new JMQXid(xid);
      /*
      xaFlags = new Integer(flags);
      */
  }

  try  {
      protocol.rollbackTransaction(txnUID, jmqXid, xaFlags, cxn, redeliver, setRedelivered);
  } catch(BrokerException be)  {
      String errStr = "rollbackTransaction: rollback transaction failed. Connection ID: "
      + connectionId
      + ", Transaction ID: "
      + transactionId
      + ", XID: "
      + xid;

            logger.logStack(Logger.ERROR, errStr, be);
      props.put("JMQStatus", getErrorReplyStatus(be));
      throw new JMSServiceException(errStr, be, props);
  }

  props.put("JMQStatus", JMSServiceReply.Status.OK);
  props.put("JMQTransactionID", txnUID.longValue());
  reply = new JMSServiceReply(props, null);

  return (reply);
    }

    /**
     *  Recover XA transactions from the broker.
     *
     *  @param connectionId The Id of the connection
     *  @param flags Controls the cursor positioning for the scanning of Xids
     *               returned.
     *               flags is set by the transaction manager and passed in
     *               directly through the XAResource interface.
     *               flags can be one of:<p>
     *
     *<p>
     <UL>
     <LI>{@link javax.transaction.xa.XAResource#TMNOFLAGS XAResource.TMNOFLAGS}: Used when neither of the following two flags are used</LI>
     <LI>{@link javax.transaction.xa.XAResource#TMSTARTRSCAN XAResource.TMSTARTRSCAN}: Starts a recovery scan</LI>
     <LI>{@link javax.transaction.xa.XAResource#TMENDRSCAN XAResource.TMENDRSCAN}:  Ends a recovery scan</LI>
     </UL>
     *
     *  @see javax.transaction.xa.XAResource#recover javax.transaction.xa.XAResource.recover()
     */
    public Xid[] recoverXATransactions(long connectionId, int flags)
          throws JMSServiceException  {
  IMQConnection cxn;
  JMQXid jmqXids[] = null;

        cxn = checkConnectionId(connectionId, "recoverXATransactions");

  try  {
      jmqXids = protocol.recoverTransaction(null);
  } catch(Exception e)  {
      HashMap props = new HashMap();
      String errStr = "recoverXATransactions: recover XA transactions failed. Connection ID: "
      + connectionId;

            logger.logStack(Logger.ERROR, errStr, e);
      props.put("JMQStatus", getErrorReplyStatus(e));
      throw new JMSServiceException(errStr, e, props);
  }

  return (jmqXids);
    }

    /**
     *  Recover a transaction from the broker.
     *
     *  @param connectionId The Id of the connection
     *  @param transactionId The id of the transaction to recover
     *
     *  @return The transactionId is returned if the transaction is in the
     *          PREPARED state. If the transaction is not found or not in the
     *          PREPARED state a zero (0L) is returned.
     */
    public long recoverTransaction(long connectionId, long transactionId)
          throws JMSServiceException  {
  IMQConnection cxn;
        TransactionUID txnUID = null;
  JMQXid jmqXids[];
  long tid = 0;

        cxn = checkConnectionId(connectionId, "recoverTransaction");
  txnUID = new TransactionUID(transactionId);

  try  {
      jmqXids = protocol.recoverTransaction(txnUID);

      if (jmqXids.length > 0)  {
          return(transactionId);
      }
  } catch(Exception e)  {
      String errStr = "recoverTransaction: recover transaction failed. Connection ID:"
      + connectionId
      + ", Transaction ID: "
      + transactionId;

            logger.logStack(Logger.ERROR, errStr, e);

      HashMap props = new HashMap();
      props.put("JMQStatus", getErrorReplyStatus(e));
      throw new JMSServiceException(errStr, e, props);
  }

  return ((long)0);
    }

    /**
     *  Send a message to the broker.
     *
     *  @param  connectionId The Id of the connection
     *  @param  message The Message to be sent
     *
     *  @throws JMSServiceException if the Status returned for the
     *          sendMessage method is not {@link JMSServiceReply.Status#OK}
     *
     */
    public JMSServiceReply sendMessage(long connectionId, JMSPacket message)
        throws JMSServiceException  {
  JMSServiceReply reply;
  HashMap props = new HashMap();
  IMQConnection cxn;

        cxn = checkConnectionId(connectionId, "sendMessage");

  /*
   * TBD: The packets used here are not compatible. Should sendMessage() have
   * individual params (eg msg body) to pass to processMessage() instead of
   * Packet ?
   *
   * Trying Packet.fill()...
   */
  try  {
      Packet p = new Packet();
      p.fill(message.getPacket());
      protocol.processMessage(cxn, p);
  } catch(Exception e)  {
      String errStr = "sendMessage: Sending message failed. Connection ID: "
      + connectionId;

            logger.logStack(Logger.ERROR, errStr, e);
      props.put("JMQStatus", JMSServiceReply.Status.ERROR);
      throw new JMSServiceException(errStr, e, props);
  }

  props.put("JMQStatus", JMSServiceReply.Status.OK);
  reply = new JMSServiceReply(props, null);

  return (reply);
    }

    /**
     *  Fetch a message from the broker.
     *
     *  @param  connectionId The Id of the connection
     *  @param  sessionId The Id of the session
     *  @param  consumerId The Id of the consumer for which to fetch the message
     *  @param  timeout The maximum time to wait (in milliseconds) for a message
     *          to be available before returning.<br>
     *          Note that the method must return immediately if there is a
     *          message available for this consumerId at the time the call is
     *          made.<br>
     <UL>
     <LI>    When timeout is positive, the call must wait for a maximum of
     *          the specificied number of milliseconds before returning.
     *          If a message is available before the timeout expires, the method
     *          returns with the message as soon as it is available.
     *  </LI>
     <LI>    When timeout is 0, the call must block until a message is
     *          available to return or until the session is stopped.
     *  </LI>
     <LI>    When the timeout is negative (less than 0), the call must
     *          return immediately, with a message if one is available or
     *          with a null, if a message is not available immediately.
     *  </LI>
     </UL>
     @param  acknowledge If this is set to {@code true} then it implies that
     *          the caller is asking for the message to be <b>acknowledged</b>
     *          before the method returns. If this operation is part of a
     *          transaction, the {@code transactionId} parameter will be
     *          non-zero.
     *  @param  transactionId If non-zero, this is the transactionId in which
     *          to acknowledge the message being returned if the
     *          {@code acknowledge} parameter is set to {@code true}.
     *
     *  @return The JMSPacket which contains the message being returned.
     *
     *  @throws JMSServiceException if broker encounters an error.
     *          {@link JMSServiceReply.Status} contains the reason for the
     *          error.
     */
    public JMSPacket fetchMessage(long connectionId, long sessionId,
                    long consumerId, long timeout, boolean acknowledge,
                    long transactionId)
                        throws JMSServiceException  {
        JMSPacket msg = null;
  IMQConnection cxn;
  Session session;

        cxn = checkConnectionId(connectionId, "fetchMessage");
        session = checkSessionId(sessionId, "fetchMessage");

  SessionListener slistener = SessionListener.getListener(session.getSessionUID());
        ConsumerUID conUID;

  try  {
          conUID = new ConsumerUID(consumerId);
            msg = slistener.getNextConsumerPacket(conUID, timeout);
            if ((msg != null) && acknowledge) {
              TransactionUID txnUID = null;

            if (transactionId != 0)  {
                  txnUID = new TransactionUID(transactionId);
            }
                SysMessageID ids[] = new SysMessageID[1];
                ids[0] = ((Packet)msg).getSysMessageID();
                ConsumerUID cids[] = new ConsumerUID[1];
                cids[0] = conUID;
                Globals.getProtocol().acknowledge(cxn, txnUID, false, AckHandler.ACKNOWLEDGE_REQUEST, null, null, 0, ids, cids);
            }
  } catch(Exception e)  {
      HashMap props = new HashMap();
      String errStr = "fetchMessage: Fetch Message failed. Connection ID: "
      + connectionId
      + ", session ID: "
      + sessionId
      + ", consumer ID: "
      + consumerId;

            logger.logStack(Logger.ERROR, errStr, e);
      props.put("JMQStatus", JMSServiceReply.Status.ERROR);
      throw new JMSServiceException(errStr, e, props);
  }


  return (msg);
    }

    /**
     *  Acknowledge a message to the broker.
     *
     *  @param  connectionId The Id of the connection
     *  @param  sessionId The Id of the session
     *  @param  consumerId The Id of the consumer for which to acknowledge
     *          the message
     *
     *  @param  sysMessageID The SysMessageID of the message to be acknowledged
     *
     *  @param  transactionId If non-zero, this is the transactionId in which
     *          to acknowledge the message.
     *
     *  @param  ackType The MessageAckType for this message acknowledgement
     *
     *  @return The JMSServiceReply which contains status and information
     *          about the acknowledge request.
     *
     *  @throws JMSServiceException If the Status returned for the
     *          acknowledgeMessage method is not
     *          {@link JMSServiceReply.Status#OK}.<br>
     *          {@link JMSServiceException#getJMSServiceReply} should be used
     *          to obtain the broker reply in case of an exception.<br>
     *          The reason for the exception can be obtained from
     *          {@link JMSServiceReply.Status}
     *
     */
    public JMSServiceReply acknowledgeMessage(long connectionId, long sessionId,
            long consumerId, SysMessageID sysMessageID, long transactionId,
            MessageAckType ackType) throws JMSServiceException  {
  boolean validate = false;
        TransactionUID txnUID = null;
        int brokerAckType;
        int deliverCnt = -1;
  SysMessageID ids[] = null;
  ConsumerUID cids[] = null;
        Throwable deadThr = null;
  String deadComment = null;
  JMSServiceReply reply;
  HashMap props = new HashMap();
  IMQConnection cxn;

        cxn = checkConnectionId(connectionId, "acknowledgeMessage");

  if (transactionId != 0)  {
      txnUID = new TransactionUID(transactionId);
  }

  brokerAckType = convertToBrokerAckType(ackType);

  ids = new SysMessageID [ 1 ];
  ids[0] = sysMessageID;

  cids = new ConsumerUID [ 1 ];
  cids[0] = new ConsumerUID(consumerId);

  try  {
          /*
       * TBD:
            * validate - should the acks just be validated (normally false)
            * deadThr - exception associated with a dead message (should be null
            *                 if ackType != DEAD)
            * deadComment - the explaination why a message was marked dead (should be null
            *               if ackType != DEAD)
            * deliverCnt - number of times a dead message was delivered (should be 0
            *               if ackType != DEAD)
            */
            protocol.acknowledge(cxn, txnUID, validate, brokerAckType,
          deadThr, deadComment, deliverCnt, ids, cids);
  } catch(Exception e)  {
      String errStr =
      "acknowledgeMessage: Sending Acknowledgement failed. Connection ID: "
      + connectionId;

            logger.logStack(Logger.ERROR, errStr, e);
      props.put("JMQStatus", getErrorReplyStatus(e));
      throw new JMSServiceException(errStr, e, props);
  }

  props.put("JMQStatus", JMSServiceReply.Status.OK);
  reply = new JMSServiceReply(props, null);

  return (reply);
    }


    /**
     *  Send a message acknowledgement to the broker.
     *  All messages acknowledged by the method must be of the same
     *  MessageAckType
     *
     *  @param  connectionId The Id of the connection
     *  @param  ackType The type of the acknowledgement
     *  @param  acks The acknowledgements
     *
     *  @throws JMSServiceException if the Status returned for the
     *          sendAcknowledgement method is not
     *          {@link JMSServiceReply.Status#OK}
     *
     */
    public JMSServiceReply sendAcknowledgement(long connectionId,
                MessageAckType ackType, JMSPacket acks)
      throws JMSServiceException  {

  boolean validate = false;
  long transactionId = -1;
        TransactionUID txnUID = null;
        int brokerAckType;
        int deliverCnt = -1;
  SysMessageID ids[] = null;
  ConsumerUID cids[] = null;
        Throwable deadThr = null;
  String deadComment = null;
  JMSServiceReply reply;
  HashMap props = new HashMap();
  IMQConnection cxn;

        cxn = checkConnectionId(connectionId, "sendAcknowledgement");

  if (transactionId != -1)  {
      txnUID = new TransactionUID(transactionId);
  }

  brokerAckType = convertToBrokerAckType(ackType);

  try  {
          /*
       * TBD:
            * txnUID - transaction id associated with the acknowledgement (or null
       * if no transaction)
            * validate - should the acks just be validated (normally false)
            * deadThr - exception associated with a dead message (should be null
            *                 if ackType != DEAD)
            * deadComment - the explaination why a message was marked dead (should be null
            *               if ackType != DEAD)
            * deliverCnt - number of times a dead message was delivered (should be 0
            *               if ackType != DEAD)
            * ids - array of message ids to process
            * cids - array of consumerIDs associated with a message, should directly
            *            correspond to the same index in ids
            */
            protocol.acknowledge(cxn, txnUID, validate, brokerAckType,
          deadThr, deadComment, deliverCnt, ids, cids);
  } catch(Exception e)  {
      String errStr =
      "sendAcknowledgement: Sending Acknowledgement failed. Connection ID: "
      + connectionId;

            logger.logStack(Logger.ERROR, errStr, e);
      props.put("JMQStatus", getErrorReplyStatus(e));
      throw new JMSServiceException(errStr, e, props);
  }

  props.put("JMQStatus", JMSServiceReply.Status.OK);
  reply = new JMSServiceReply(props, null);

  return (reply);
    }

    public JMSServiceReply addBrowser(long connectionId, long sessionId,
            Destination dest, String selector)
                                    throws JMSServiceException  {
  JMSServiceReply reply;
  IMQConnection cxn;
  HashMap props = new HashMap();
  ConsumerUID uid;
  Session session;

        cxn = checkConnectionId(connectionId, "addBrowser");
        session = checkSessionId(sessionId, "addBrowser");

  try  {
      Selector sel = Selector.compile(selector);
  } catch(SelectorFormatException sfe)  {
      String errStr = "addBrowser: Add browser failed. Connection ID: "
      + connectionId
      + ", session ID: "
      + sessionId
      + ", destination: "
      + dest
      + ", selector: "
      + selector;

            logger.logStack(Logger.ERROR, errStr, sfe);
      props.put("JMQStatus", JMSServiceReply.Status.BAD_REQUEST);
      throw new JMSServiceException(errStr, sfe, props);
  }

  uid = new ConsumerUID();
  queueBrowseList.put(uid, new QueueBrowserInfo(dest, selector));

  props.put("JMQStatus", JMSServiceReply.Status.OK);
  props.put("JMQConsumerID", uid.longValue());
  reply = new JMSServiceReply(props, null);

  return (reply);
    }

    public JMSServiceReply deleteBrowser(long connectionId, long sessionId,
            long consumerId)
                                    throws JMSServiceException  {
  JMSServiceReply reply;
  IMQConnection cxn;
  HashMap props = new HashMap();
  ConsumerUID uid;
  Session session;

        cxn = checkConnectionId(connectionId, "deleteBrowser");
        session = checkSessionId(sessionId, "deleteBrowser");

  uid = new ConsumerUID(consumerId);

  if (queueBrowseList.containsKey(uid))  {
      queueBrowseList.remove(uid);
  } else  {
      String errStr = "deleteBrowser: consumer ID not found. Connection ID:"
      + connectionId
      + ", Session ID: "
      + sessionId
      + ", Consumer ID: "
      + consumerId;

            logger.log(Logger.ERROR, errStr);

      props.put("JMQStatus", JMSServiceReply.Status.NOT_FOUND);
      throw new JMSServiceException(errStr, props);
  }

  props.put("JMQStatus", JMSServiceReply.Status.OK);
  props.put("JMQConsumerID", uid.longValue());
  reply = new JMSServiceReply(props, null);

  return (reply);
    }

    public JMSPacket[] browseMessages(long connectionId, long sessionId,
            long consumerId) throws JMSServiceException  {
  JMSServiceReply reply;
  IMQConnection cxn;
  HashMap props = new HashMap();
  ConsumerUID uid;
  Session session;
  JMSPacket[] msgs = null;

        cxn = checkConnectionId(connectionId, "browseMessages");
        session = checkSessionId(sessionId, "browseMessages");

  uid = new ConsumerUID(consumerId);

  if (queueBrowseList.containsKey(uid))  {
      QueueBrowserInfo qbi = (QueueBrowserInfo)queueBrowseList.get(uid);

      try  {
          Destination dest = qbi.dest;
          String selector = qbi.selector;
          com.sun.messaging.jmq.jmsserver.core.Destination d;
                d = com.sun.messaging.jmq.jmsserver.core.Destination.getDestination(dest.getName(),
           (dest.getType() == Destination.Type.QUEUE));

    if (d == null)  {
              String errStr = "browseMessages: destination not found. Connection ID:"
      + connectionId
      + ", Session ID: "
      + sessionId
      + ", Consumer ID: "
      + consumerId
      + "destination: "
      + dest.toString();

                    logger.log(Logger.ERROR, errStr);

              props.put("JMQStatus", JMSServiceReply.Status.NOT_FOUND);
              throw new JMSServiceException(errStr, props);
    }

    ArrayList msgIds = protocol.browseQueue(d, selector, cxn, acEnabled);

    if (msgIds != null)  {
        int numMsgs = msgIds.size();

        if (numMsgs == 0)  {
      return (null);
        }

        msgs = new JMSPacket[ numMsgs ];

        for (int i = 0; i < numMsgs; ++i)  {
      PacketReference pr = d.get((SysMessageID)msgIds.get(i));
      msgs[i] = pr.getPacket();
        }
    }
      } catch (Exception e)  {
          String errStr = "browseMessages: Browse queue failed. Connection ID: "
      + connectionId
      + ", session ID: "
      + sessionId
      + ", consumer ID: "
      + consumerId;

                logger.logStack(Logger.ERROR, errStr, e);
          if (e instanceof SelectorFormatException)  {
              props.put("JMQStatus", JMSServiceReply.Status.BAD_REQUEST);
          } else  {
              props.put("JMQStatus", getErrorReplyStatus(e));
          }
          throw new JMSServiceException(errStr, e, props);
      }
  } else  {
      String errStr = "browseMessages: consumer ID not found. Connection ID:"
      + connectionId
      + ", Session ID: "
      + sessionId
      + ", Consumer ID: "
      + consumerId;

            logger.log(Logger.ERROR, errStr);

      props.put("JMQStatus", JMSServiceReply.Status.NOT_FOUND);
      throw new JMSServiceException(errStr, props);
  }

  return (msgs);
    }

    /**
     *  Redeliver messages for a Session.<p>
     *  All the messages that are specified by the parameters will be
     *  redelivered by the broker.
     *
     *  @param  connectionId The Id of the connection in which the messages were
     *          received
     *  @param  sessionId The Id of the session in which the messages were
     *          received
     *  @param  SysMessageID[] The array of SysMessageID objects for the
     *          messages that were received and are to be redelivered
     *  @param  consumerIds[] The array of consumerId longs for the messages
     *          that were received and are to be redelivered
     *  @param  transactionId The Id of the transaction in which the messages
     *          were received
     *  @param  setRedelivered Indicates whether to set the Redelivered flag
     *          when redelivering the messages.<br>
     *          If <code>true</code> then the Redelivered flag must be set for
     *          the messages when they are redelivered.<br>
     *          If <code>false</code>, then the Redelivered flag must not be
     *          set for the messages when they are redelivered.
     *
     *  @throws JMSServiceException If broker encounters an error.<br>
     *          {@link JMSServiceException#getJMSServiceReply} should be used
     *          to obtain the broker reply in case of an exception.<br>
     *          The reason for the exception can be obtained from
     *          {@link JMSServiceReply.Status}
     */
    public JMSServiceReply redeliverMessages(long connectionId, long sessionId,
            SysMessageID[] messageIDs, Long[] consumerIds, long transactionId,
            boolean setRedelivered) throws JMSServiceException  {
  JMSServiceReply reply;
  IMQConnection cxn;
  HashMap props = new HashMap();
  ConsumerUID conUIDs[] = null;
        TransactionUID txnUID = null;
  Session session;

        cxn = checkConnectionId(connectionId, "redeliverMessages");
        session = checkSessionId(sessionId, "redeliverMessages");

  if (consumerIds != null)  {
      conUIDs = new ConsumerUID [ consumerIds.length ];
      for (int i = 0; i < consumerIds.length; ++i)  {
          conUIDs[i] = new ConsumerUID(consumerIds[i]);
      }
  }

  if (transactionId != -1)  {
      txnUID = new TransactionUID(transactionId);
  }

  try  {
      protocol.redeliver(conUIDs, messageIDs, cxn, txnUID, true);
  } catch(Exception e)  {
      String errStr =
      "redeliverMessages: Redeliver failed. Connection ID: "
      + connectionId
      + ", session ID: "
      + sessionId
      + ", transaction ID: "
      + transactionId;

            logger.logStack(Logger.ERROR, errStr, e);
      props.put("JMQStatus", getErrorReplyStatus(e));
      throw new JMSServiceException(errStr, e, props);
  }

  props.put("JMQStatus", JMSServiceReply.Status.OK);
  reply = new JMSServiceReply(props, null);

  return (reply);
    }


    /*
     * END Interface JMSService
     */

    /*
     * Convenience method to check connection ID.
     * If the connection ID is valid, the corresponding
     * IMQConnection object will be returned. If not, a
     * JMSServiceException will be thrown.
     */
    IMQConnection checkConnectionId(long connectionId,
      String methodName) throws JMSServiceException  {
  ConnectionManager cm = Globals.getConnectionManager();
  IMQConnection  cxn;
 
  cxn = (IMQConnection)cm.getConnection(new ConnectionUID(connectionId));

  if (cxn == null)  {
            String errStr = methodName
      + ": connection ID not found: "
      + connectionId;

            logger.log(Logger.ERROR, errStr);
      HashMap props = new HashMap();
      props.put("JMQStatus", JMSServiceReply.Status.ERROR);
      throw new JMSServiceException(errStr, props);
  }

  return (cxn);
    }

    /*
     * Convenience method to check session ID.
     * If the session ID is valid, the corresponding
     * Session object will be returned. If not, a
     * JMSServiceException will be thrown.
     */
    private Session checkSessionId(long sessionId,
      String methodName) throws JMSServiceException  {
        Session ses = Session.getSession(new SessionUID(sessionId));

  if (ses == null)  {
      String errStr = methodName
      + ": session ID not found: "
      + sessionId;

            logger.log(Logger.ERROR, errStr);
      HashMap props = new HashMap();
      props.put("JMQStatus", JMSServiceReply.Status.ERROR);
      throw new JMSServiceException(errStr, props);
  }

  return (ses);
    }

    private int convertToBrokerAckMode(SessionAckMode ackMode)  {
  switch (ackMode)  {
  case AUTO_ACKNOWLEDGE:
      return
    (com.sun.messaging.jmq.jmsserver.core.Session.AUTO_ACKNOWLEDGE);
  case CLIENT_ACKNOWLEDGE:
      return
    (com.sun.messaging.jmq.jmsserver.core.Session.CLIENT_ACKNOWLEDGE);
  case DUPS_OK_ACKNOWLEDGE:
      return
    (com.sun.messaging.jmq.jmsserver.core.Session.DUPS_OK_ACKNOWLEDGE);
  case NO_ACKNOWLEDGE:
      return
    (com.sun.messaging.jmq.jmsserver.core.Session.NO_ACK_ACKNOWLEDGE);
  case UNSPECIFIED:
      return
    (com.sun.messaging.jmq.jmsserver.core.Session.NONE);
  }

  return (com.sun.messaging.jmq.jmsserver.core.Session.NONE);
    }

    private int convertToBrokerAckType(MessageAckType ackType)  {
  switch (ackType)  {
  case ACKNOWLEDGE:
      return (AckHandler.ACKNOWLEDGE_REQUEST);
  case UNDELIVERABLE:
      return (AckHandler.UNDELIVERABLE_REQUEST);
  case DEAD:
      return (AckHandler.DEAD_REQUEST);
  }

  return (AckHandler.ACKNOWLEDGE_REQUEST);
    }

    /*
     * Returns the equivalent JMSServiceReply.Status from the passed Exception.
     * Only really handles the case where the exception is a BrokerException. If
     * the are cases where a status code is dependent on some other type of exception
     * e.g. SelectorFormatException it needs to be handled outside this method.
     */
    private JMSServiceReply.Status getErrorReplyStatus(Exception e)  {
  JMSServiceReply.Status retStatus = JMSServiceReply.Status.ERROR;

  if (e instanceof BrokerException)  {
      BrokerException be = (BrokerException)e;
      int status = be.getStatusCode();

      switch (status)  {
      case Status.FORBIDDEN:
    retStatus = JMSServiceReply.Status.FORBIDDEN;
                break;
      case Status.CONFLICT:
    retStatus = JMSServiceReply.Status.CONFLICT;
                break;
      case Status.BAD_REQUEST:
    retStatus = JMSServiceReply.Status.BAD_REQUEST;
                break;
      case Status.NOT_FOUND:
    retStatus = JMSServiceReply.Status.NOT_FOUND;
                break;
      case Status.NOT_ALLOWED:
    retStatus = JMSServiceReply.Status.NOT_ALLOWED;
                break;
      case Status.PRECONDITION_FAILED:
    retStatus = JMSServiceReply.Status.PRECONDITION_FAILED;
                break;
      case Status.NOT_MODIFIED:
    retStatus = JMSServiceReply.Status.NOT_MODIFIED;
                break;
      case Status.NOT_IMPLEMENTED:
    retStatus = JMSServiceReply.Status.NOT_IMPLEMENTED;
                break;
      case Status.TIMEOUT:
    retStatus = JMSServiceReply.Status.TIMEOUT;
                break;
      /*
      case Status.GONE:
    retStatus = JMSServiceReply.Status.GONE;
      */
      }
  }

  return (retStatus);
    }

    private void startAllConnections()  {
        Iterator itr = localConnectionList.values().iterator();
        while (itr.hasNext()) {
            IMQConnection cxn = (IMQConnection)itr.next();
      SessionListener.startConnection(cxn);
        }
    }

    private void stopAllConnections()  {
        Iterator itr = localConnectionList.values().iterator();
        while (itr.hasNext()) {
            IMQConnection cxn = (IMQConnection)itr.next();
      SessionListener.stopConnection(cxn);
        }
    }
}

    /**
     * Thread that watches a session for events
     */
    class SessionListener implements com.sun.messaging.jmq.util.lists.EventListener, Runnable
    {
        /**
         * IMQDirectService
         */

        IMQDirectService parent;

        /**
         * listener is alive
         */
        boolean valid = false;

  /**
   * session is stopped ?
   */
        boolean stopped = true;

        /**
         * session associated with this listener
         */
        Session session = null;

        /**
         * is this a sync or async consumer
         */
        boolean sync = true;

  /**
   * was a Session event listener registered ?
   */
  boolean sessionEvListenerRegistered = false;

        /**
         * has a thread been started
         */
        boolean started = false;

        /**
         * maps sessionUID-&lt;SessionListener
         */
        static HashMap listeners = new HashMap();

        /**
         * maps consumerUID to Consumer object
         * NOTE: this is NOT the core.Consumer object
         */
        HashMap consumers = new HashMap();

        /**
         * lock used for notification
         */
        Object sessionLock = new Object();


        /**
         * ListenerObject used for the eventListener on Session
         */
        Object sessionEL = null;

        /**
         * return a SessionListener by session
         */
        public static SessionListener getListener(SessionUID uid)
        {
            synchronized (listeners) {
                return (SessionListener)listeners.get(uid);
            }
        }

        /**
         * create a session listener
         */
        public SessionListener(IMQDirectService svc, Session s) {
            this.parent = svc;
            this.session = s;
            synchronized(listeners) {
                listeners.put(s.getSessionUID(), this);
            }
        }

        /**
         * Synchronous method to retrieve a packet
         */
        public Packet getNextConsumerPacket(ConsumerUID cuid)  {
            return getNextConsumerPacket(cuid, 0);
  }

        /**
         * Synchronous method to retrieve a packet
         */
        public Packet getNextConsumerPacket(ConsumerUID cuid, long timeout)
        {

            // we are either async or sync
            // if this is called from something that registered a message
            // listener, something went wrong. Throw an exception
            if (!sync) throw new RuntimeException("Cannot invoke SessionListener.getNextConsumerPacket() when in asynchronous receiving mode");

            //see if we are busy
            // if we aren't wait

           
            com.sun.messaging.jmq.jmsserver.core.Consumer c = (
                com.sun.messaging.jmq.jmsserver.core.Consumer)
                com.sun.messaging.jmq.jmsserver.core.Consumer.getConsumer(cuid);

            sync = true;

      /*
       * If timeout is < 0, this is for receiveNoWait().
       * If the consumer is not busy() return null right away.
       */
      if (timeout < 0)  {
    if (stopped || !c.isBusy())  {
        return (null);
    }
      }


                // add an event listener to wake us up when the consumer is busy
                Object lock = c.addEventListener(this,EventType.BUSY_STATE_CHANGED, null);
                while (!c.isBusy() || stopped) {
                    try {
                        // wait until the consumer is not busy
                        synchronized (c.getConsumerUID()) {
                            synchronized(sessionLock) {
                                if (stopped) {
                                    if (timeout > 0) {
                                        long locktime = System.currentTimeMillis();
                                        try {
                                            sessionLock.wait(timeout);
                                        } catch (Exception ex) {}
                                        // adjust the timeout by the wait time
                                        long now = System.currentTimeMillis();
                                        timeout -= now - locktime;
                                        if (timeout <= 0) return null;
                                    } else if (timeout == 0)  {
                                        try {
                                            sessionLock.wait(timeout);
                                        } catch (Exception ex) {}
            }

            // Is this needed ?
                                    if (stopped) return null;
                                   
                                }
                            }
                               
                            // we cant check isBusy in the lock because
                            // we can deadlock
                            // instead look in the cuidNotify table
                            if (cuidNotify.remove(c.getConsumerUID()))
                                continue;
          /*
           * Just in case between the (timeout < 0) check above and the while loop,
           * the consumer became not busy, we want to return if it is a noWait case.
           */
                            if (timeout < 0)  {
                                c.removeEventListener(lock);
                                return (null);
                            }
                            c.getConsumerUID().wait(timeout);
                        }
                        if (stopped) return null;

            /*
             * wait() returned but this could be due to a timeout and not
             * from notify()
             *
             * We check the busy state and also if a non zero timeout was
       * specified. If it is indeed a timeout, return null.
             */
      if (!c.isBusy() && (timeout > 0))  {

                            // remove the event listener since we arent sure if we will care
                            c.removeEventListener(lock);
          return (null);
      }
                    } catch (Exception ex) {}
                // remove the event listener since we arent sure if we will care
                c.removeEventListener(lock);
            }
            if (stopped) return null;
            synchronized (c.getConsumerUID()) {
                cuidNotify.remove(c.getConsumerUID());
            }

            // now get the packet
            Packet p = new Packet();
            if (session.fillNextPacket(p, cuid))
                return p;

            // this should only happen if something went strange like we
            // have two threads processing @ the same time
            // but just try it again
            return getNextConsumerPacket(cuid, timeout); // recurse

        }

        /**
         * Set this up as an AsyncListener
         */
        public void setAsyncListener(com.sun.messaging.jmq.jmsserver.core.Consumer brokerC,
                    Consumer target)
        {
            ConsumerUID cuid;

      /*
       * Target passed in may be null
       * This is to indicate that the consumer has unregistered itself as an async
       * consumer - may go into sync mode.
       *
       */
      if (target == null)  {
    // XXX Need to stop delivery of msgs - TBD
    //

                // we are no longer asynchronous
                sync = true;

    // Remove Consumer from table
    //
                cuid = brokerC.getConsumerUID();
                consumers.remove(cuid);

    return;
      }

            // we arent synchronous
            sync = false;

            // put the Consumer into a table so we can retrieve it when
            // a message is received
            cuid = brokerC.getConsumerUID();
            consumers.put(cuid, target);

            // set up a listener to wake up when the Session is Busy
      if (!sessionEvListenerRegistered)  {
                sessionEL = session.addEventListener(this, EventType.BUSY_STATE_CHANGED, null);
          sessionEvListenerRegistered = true;
      }

            // ok - start the parsing thread
            if (!started) {
                Thread thr = new Thread(this, "Session" + session.getSessionUID());
                thr.start();
                started = true;
            }
        }

        /**
         * Thread run method
         */
        public void run() {
            process();
        }


        // set when a notification is about to occur
        boolean sessionLockNotify = false;

        // set when a consumer notificationis about to occur
        HashSet cuidNotify = new HashSet();


        /**
         * method which handles delivering messages
         */
        public void process() {
           if (sync) {
               // we shouldn't be here
               // there doesnt need to be an external thread
               throw new RuntimeException("Cannot invoke SessionListener.process() when in synchronous receiving mode");
           }
     valid = true;
           while (valid ) {
                   // if we are not busy, wait for the eventListener to wake us up
                while (valid && (!session.isBusy() || stopped)) {
                   // get the lock
                   synchronized(sessionLock) {
                       // we cant check isBusy in the loop so
                       // instead check the sessionLockNotify flag
                       if (sessionLockNotify) {
                           sessionLockNotify = false;
                           continue;
                       }
                       try {
                           sessionLock.wait();
                       } catch (Exception ex) {
                           Globals.getLogger().log(Logger.DEBUGHIGH,"Exception in sessionlock wait",
                                     ex);
                       }
                   }
                }
                synchronized(sessionLock) {
                    // we dont care if we are about to notify
                    sessionLockNotify = false;
                }
                if (session.isBusy() && !stopped) {
                       // cool, we have something to do
                       Packet p = new Packet();

                       // retrieve the next packet and its ConsumerUID
                       ConsumerUID uid = session.fillNextPacket(p);

                       if (uid == null) {
                           // weird, something went wrong, try again
                           continue;
                       }

                       // Get the consumer object
                       Consumer con = (Consumer)consumers.get(uid);
                       try {
         JMSAck ack = null;

                           // call the deliver method
                           ack = con.deliver(p);

         if (ack != null)  {
             long transactionId = ack.getTransactionId(),
             consumerId = ack.getConsumerId();
             SysMessageID sysMsgId = ack.getSysMessageID();
                         TransactionUID txnUID = null;
                         ConsumerUID conUID = null;

                   if (transactionId != 0)  {
                             txnUID = new TransactionUID(transactionId);
                   }

                   if (consumerId != 0)  {
                             conUID = new ConsumerUID(consumerId);
                   }

                               IMQConnection cxn = parent.checkConnectionId(ack.getConnectionId(), "Listener Thread");

                               SysMessageID ids[] = new SysMessageID[1];
                               //ids[0] = sysMsgId;
                               //ids[0] = ((Packet)p).getSysMessageID();
                               ids[0] = sysMsgId;
                               ConsumerUID cids[] = new ConsumerUID[1];
                               cids[0] = conUID;
                               Globals.getProtocol().acknowledge(cxn, txnUID, false, AckHandler.ACKNOWLEDGE_REQUEST, null, null, 0, ids, cids);
         }
                       } catch (Exception ex) {
                           // I have no idea what the exception might mean so just
                           // log it and go on
                           Globals.getLogger().log(Logger.ERROR,"Can not deliver message to " + con);
                       }
                   }
                  
           }
        }

        /**
         * This method is called when a thread puts a message on a
         * consumer or session. Its used to wake up the waiting thread
         * which might be in the process() [asynchronous] method or in the
         * getNextConsumerPacket()[synchronous].
         */
        public void eventOccured(EventType type,  Reason r,
            Object target, Object oldval, Object newval,
            Object userdata) {

            if (type != EventType.BUSY_STATE_CHANGED) {
                return; // should never occur   
            }

            // deal with consumers (the synchronous case)
            if (target instanceof com.sun.messaging.jmq.jmsserver.core.Consumer)
            {
                // notify on the ConsumerUID
                com.sun.messaging.jmq.jmsserver.core.Consumer cc =
                       (com.sun.messaging.jmq.jmsserver.core.Consumer) target;
                ConsumerUID cuid = cc.getConsumerUID();
                if (cc.isBusy()) {
                    synchronized (cuid) {
                        // we cant check isBusy in here - we can deadlock
                        // so instead look in the cuidNotify hashtable

                        cuidNotify.add(cuid);
                        //ok, we want to wake up the thread currently in
                        // getNextConsumerPacket.
                        // it is waiting on the ConsumerUID
                        // so do a notify on ConsumerUID
                            cuid.notifyAll();
                    }
                }
                return;
            }

            // deal with sessions (the async case)
            Session s = (Session)target;

            // this wakes up the process thread which is blocked on SessionLock
            synchronized (sessionLock) {
                sessionLockNotify = true;
                sessionLock.notify();
            }
        }

  /*
   * Start all sessions for the specified connection
   */
        public static void startConnection(IMQConnection cxn) {
      if (cxn == null)  {
    return;
      }

      List sessions = cxn.getSessions();

      if (sessions == null)  {
    return;
      }

      Iterator itr = sessions.iterator();
      while (itr.hasNext()) {
    SessionUID sUID = (SessionUID)itr.next();
                SessionListener sl = getListener(sUID);

    sl.startSession();
      }
  }

  /*
   * Stop all sessions for the specified connection
   */
        public static void stopConnection(IMQConnection cxn) {
      if (cxn == null)  {
    return;
      }

      List sessions = cxn.getSessions();

      if (sessions == null)  {
    return;
      }

      Iterator itr = sessions.iterator();
      while (itr.hasNext()) {
    SessionUID sUID = (SessionUID)itr.next();
                SessionListener sl = getListener(sUID);
    sl.stopSession();
      }
  }

  /*
   * Start this session - set stopped flag to false and wake up waiting thread
   */
        public void startSession() {
      stopped = false;
             // wake up the thread (if waiting())
             synchronized (sessionLock) {
                 sessionLock.notify();
             }
  }

  /*
   * Stop this session - set stopped flag to true
   */
        public void stopSession() {
      stopped = true;
             synchronized (sessionLock) {
                 sessionLock.notify();
             }
  }

        public void destroy() {

             // set the shutdown flag
             valid = false;
             // wake up the thread (if waiting())
             synchronized (sessionLock) {
                 sessionLock.notify();
             }

             // remove any even listener
             session.removeEventListener(sessionEL);

             // clean up listeners table
             synchronized(listeners) {
                 listeners.remove(session.getSessionUID());
             }
             // clean up the consumers table
             consumers = null;
        }
    }

class QueueBrowserInfo  {
    Destination dest;
    String selector;

    public QueueBrowserInfo(Destination dest, String selector) {
  this.dest = dest;
  this.selector = selector;
    }
}
TOP

Related Classes of com.sun.messaging.jmq.jmsserver.service.imq.QueueBrowserInfo

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.