/*
 *  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 *  Copyright 2000-2009 Sun Microsystems, Inc. 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.html
 *  or mq/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 mq/legal/LICENSE.txt.  Sun designates
 *  this particular file as subject to the "Classpath" exception as provided by
 *  Sun in the GPL Version 2 section of the License file that accompanied this
 *  code.  If applicable, add the following below the License Header, with the
 *  fields enclosed by brackets [] replaced by your own identifying information:
 *  "Portions Copyrighted [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. 
 *
 *  ActivationSpec.java
 *
 *  @(#)ActivationSpec.java	1.31 04/09/08
 */

package com.sun.messaging.jms.ra;

import javax.resource.*;
import javax.resource.spi.*;

import java.util.logging.Logger;

import com.sun.messaging.jmq.DestinationName;

/**
 *  Encapsulates the configuration of a MessageEndpoint.
 *  An Application Server configures an instance of this class and uses it
 *  to activate message inflow to a message listener in the application server.
 */

public class ActivationSpec
implements javax.resource.spi.ActivationSpec,
           javax.resource.spi.ResourceAdapterAssociation,
           java.io.Serializable
{

    /** String constants used to map standard values to JMS equivalents */
    private static transient final String AUTOACKNOWLEDGE = "Auto-acknowledge";
    private static transient final String DUPSOKACKNOWLEDGE = "Dups-ok-acknowledge";
    private static transient final String NOACKNOWLEDGE = "No-acknowledge";
    private static transient final String DURABLE = "Durable";
    private static transient final String NONDURABLE = "NonDurable";
    private static transient final String QUEUE = "javax.jms.Queue";
    private static transient final String TOPIC = "javax.jms.Topic";

    /* Loggers */
    private static transient final String _className =
            "com.sun.messaging.jms.ra.ActivationSpec";
    protected static transient final String _lgrNameInboundMessage =
            "javax.resourceadapter.mqjmsra.inbound.message";
    protected static transient final Logger _loggerIM =
            Logger.getLogger(_lgrNameInboundMessage);
    protected static transient final String _lgrMIDPrefix = "MQJMSRA_AS";
    protected static transient final String _lgrMID_EET = _lgrMIDPrefix + "1001: ";
    protected static transient final String _lgrMID_INF = _lgrMIDPrefix + "1101: ";
    protected static transient final String _lgrMID_WRN = _lgrMIDPrefix + "2001: ";
    protected static transient final String _lgrMID_ERR = _lgrMIDPrefix + "3001: ";
    protected static transient final String _lgrMID_EXC = _lgrMIDPrefix + "4001: ";

    /** The resource adapter instance that this instance is bound to */
    private com.sun.messaging.jms.ra.ResourceAdapter ra = null;

    /* ActivationSpec attributes recommended for JMS RAs */
    /** The type of the destination for the MessageEndpoint consumer */
    private String destinationType = TOPIC;

    /** The name of the destination for the MessageEndpoint consumer */
    private String destination = null;

    /** The message selector for the MessageEndpoint consumer */
    private String messageSelector = null;

    /** The acknowledgement mode for the MessageEndpoitn consumer */
    private String acknowledgeMode = AUTOACKNOWLEDGE;

    /** The subscription durability of the MessageEndpoint consumer */
    private String subscriptionDurability = NONDURABLE;

    /** The clientId of the MessageEndpoint consumer */
    private String clientId = null;

    /** The subscription name of the MessageEndpoint consumer */
    private String subscriptionName = null;


    /* ActivationSpec attributes for the GlassFish(tm) MQ JMS Resource Adapter */

    /** The ConnectionFactory JNDI Name to be used */
    private String connectionFactoryJNDIName;

    /** The Maximum endpoint pool size that will be used */
    private int endpointPoolMaxSize = 15;

    /** The Steady endpoint pool size that will be used */
    private int endpointPoolSteadySize = 10;

    /** The endpoint pool re-size count that will be used */
    private int endpointPoolResizeCount = 1;

    /** The endpoint pool re-size timeout in seconds that will be used */
    private int endpointPoolResizeTimeout = 5;

    /** The Maximum # of endpoint delivery attempts for endpoints that throw an Exception */
    private int endpointExceptionRedeliveryAttempts = 6;

    /** The interval for endpoint delivery attempts for endpoints that throw an Exception */
    private int endpointExceptionRedeliveryInterval = 500;

    /** The flag indicating whether to send undeliverable messages to the DMQ */
    private boolean sendUndeliverableMsgsToDMQ = true;

    /** Indicates whether the endpoint deployment requires a shared client Identifier */
    //private boolean enableSharedClientID = false;

    /** The Message Service Address List to use to connect to GlassFish(tm) MQ */
    private String addressList = null;
    private boolean addressListSet = false;

    /** The custom acknowledgement mode for this MessageEndpoint consumer */
    private String customAcknowledgeMode = null;

    /** The MDB Name to use when grouping MDBs that must share messages */
    private String mdbName = null;

    /** The username that will be used for this endpoint - default is to use the one from the RA */
    private String userName = null;

    /** The password that will be used for this endpoint - default is to use the one from the RA */
    private String password = null;

    /** Force this activation to use RADIRECT mode */
    private boolean enableRADirect = false;
    
    /** Force this activation to use APIDIRECT mode */
    private boolean enableAPIDirect = false;

    /** ContextClassLoader for the onMessage Thread */
    private transient ClassLoader contextClassLoader = null;

    /** The Group Name (Cluster) to use when grouping MDBs that must share messages within a group */
    private String groupName = null;

    /** The Resource Adapter UID to use to ensure that ClientIDs are unique within an RA */
    private String raUID = null;

    /** The flag indicating whether this is being activated in a Clustered Container */
    private boolean inClusteredContainer = false;
    
    /**
     * The property useSharedSubscriptionInClusteredContainer is only used 
     * if this is a clustered container (as determined by inClusteredContainer), 
     * If the property useSharedSubscriptionInClusteredContainer is set  
     * then all subscriptions using this activation will be shared
     * otherwise subscriptions will not be shared
     */
    private boolean useSharedSubscriptionInClusteredContainer = true;

    /** Internal flag indicating whether this is being activated using serial msg delivery */
    /** Default (false) implies concurrent msg delivery */
    private boolean deliverySerial = false;
    
    /** additional connection factory properties, as a comma-separated list of name=value pairs */
    private String options;

    /** ActivationSpec must provide a default constructor */
    public ActivationSpec ()
    {
        _loggerIM.entering(_className, "constructor()");
    }


    // ActivationSpec interface defined methods //

    /** Validates the configuration of this ActivationSpec instance
     *  ActivationSpec instance.
     *
     *  @throws InvalidPropertyException If this activation spec
     *          instance has any invalid property
     */
    public void
    validate()
    throws InvalidPropertyException
    {
        InvalidPropertyException ipe;
        _loggerIM.entering(_className, "validate()", this);
        //Require destinationName to be valid
        if (!DestinationName.isSyntaxValid(destination)) {
            ipe = new InvalidPropertyException(_lgrMID_EXC+"validate:Invalid destination name=" + destination);
            _loggerIM.throwing(_className, "validate()", ipe);
            throw ipe;
        }

        //Require both subscriptionName and clientId to be
        //valid for durable subscriptions
        if (destinationType.equals(TOPIC) &&
            subscriptionDurability.equals(DURABLE)) {
            if ((subscriptionName == null) ||
                ("".equals(subscriptionName)) ||
                (clientId == null) ||
                ("".equals(clientId))) {
                    ipe = new InvalidPropertyException(_lgrMID_EXC+"validate:Both subscriptionName and clientId must be non-null"+
                        "\n\tsubscriptionName="+subscriptionName+"\n\tclientId="+clientId);
                    _loggerIM.throwing(_className, "validate()", ipe);
                    throw ipe;
            }
        }
        //Require valid values of endpoint properties
        if (endpointExceptionRedeliveryInterval < 1) {
            ipe = new InvalidPropertyException(_lgrMID_EXC+"validate:"+
                    "\nendpointExceptionRedeliveryInterval must be greater than 0"+
                    "\nInvalid value="+endpointExceptionRedeliveryInterval);
            _loggerIM.throwing(_className, "validate()", ipe);
            throw ipe;
        }
        if (endpointExceptionRedeliveryAttempts < 0) {
            ipe = new InvalidPropertyException(_lgrMID_EXC+"validate:"+
                    "\nendpointExceptionRedeliveryAttempts must be greater than or equal to 0"+
                    "\nInvalid value="+endpointExceptionRedeliveryAttempts);
            _loggerIM.throwing(_className, "validate()", ipe);
            throw ipe;
        }
        if (endpointPoolResizeTimeout < 1) {
            ipe = new InvalidPropertyException(_lgrMID_EXC+"validate:"+
                    "\nendpointPoolResizeTimeout must be greater than 0"+
                    "\nInvalid value="+endpointPoolResizeTimeout);
            _loggerIM.throwing(_className, "validate()", ipe);
            throw ipe;
        }
        if (endpointPoolResizeCount < 1) {
            ipe = new InvalidPropertyException(_lgrMID_EXC+"validate:"+
                    "\nendpointPoolResizeCount must be greater than 0"+
                    "\nInvalid value="+endpointPoolResizeCount);
            _loggerIM.throwing(_className, "validate()", ipe);
            throw ipe;
        }
        if (endpointPoolMaxSize < 1) {
            ipe = new InvalidPropertyException(_lgrMID_EXC+"validate:"+
                    "\nendpointPoolMaxSize must be greater than 0"+
                    "\nInvalid value="+endpointPoolMaxSize);
            _loggerIM.throwing(_className, "validate()", ipe);
            throw ipe;
        }
        if (endpointPoolSteadySize < 0) {
            ipe = new InvalidPropertyException(_lgrMID_EXC+"validate:"+
                    "\nendpointPoolSteadySize must be greater than or equal to 0"+
                    "\nInvalid value="+endpointPoolSteadySize);
            _loggerIM.throwing(_className, "validate()", ipe);
            throw ipe;
        }
        if (endpointPoolSteadySize > endpointPoolMaxSize) {
            ipe = new InvalidPropertyException(_lgrMID_EXC+"validate:"+
                    "\nendpointPoolSteadySize must be less than or equal to endpointPoolMaxSize"+
                    "\nendpointPoolSteadySize value="+endpointPoolSteadySize+
                    "\nendpointPoolMaxSize value="+endpointPoolSteadySize);
            _loggerIM.throwing(_className, "validate()", ipe);
            throw ipe;
        }
        _loggerIM.exiting(_className, "validate()");
    }

    // ResourceAdapterAssociation interface defined methods //

    /** Sets the Resource Adapter Javabean that is associated with this
     *  ActivationSpec instance.
     *
     *  @param ra The ResourceAdapter Javabean
     */
    public void
    setResourceAdapter(javax.resource.spi.ResourceAdapter ra)
    throws ResourceException
    {
        _loggerIM.entering(_className, "setResourceAdapter()", ra);
        synchronized (this) {
            if (this.ra == null) {
                if (!(ra instanceof com.sun.messaging.jms.ra.ResourceAdapter)) {
                    ResourceException rae = new ResourceException(_lgrMID_EXC+"setResourceAdapter:Incompatible ResourceAdapter class="
                        + ra.getClass());
                    _loggerIM.warning(rae.getMessage());
                    _loggerIM.throwing(_className, "setResourceAdapter()", rae);
                    throw rae;
                }
                this.ra = (com.sun.messaging.jms.ra.ResourceAdapter)ra;
                this.groupName = this.ra.getGroupName();
                this.inClusteredContainer = this.ra.getInClusteredContainer();
                this.raUID = this.ra._getRAUID();
                if (!this.addressListSet) {
                    this.enableRADirect = this.ra._isRADirect();
                    this.enableAPIDirect = this.ra._isAPIDirect();                    
                }
            } else {
                ResourceException rae = new ResourceException(_lgrMID_EXC+"setResourceAdapter:Illegal to re-associate ResourceAdapter");
                _loggerIM.warning(rae.getMessage());
                _loggerIM.throwing(_className, "setResourceAdapter()", rae);
                throw rae;
            }
        }
        _loggerIM.exiting(_className, "setResourceAdapter()");
    }

    /** Gets the Resource Adapter Javabean that is associated with this
     *  ActivationSpec instance.
     *
     *  @return The ResourceAdapter Javabean
     */
    public javax.resource.spi.ResourceAdapter
    getResourceAdapter()
    {
        _loggerIM.entering(_className, "getResourceAdapter()");
        return ra;
    }


    // ActivationSpec Javabean configuration methods //
    // These Methods can throw java.lang.RuntimeException or subclasses //

    /** Sets the type of the destination for the MessageEndpoint consumer
     *
     *  @param destinationType The destination type
     *         valid values are "javax.jms.Queue" and "javax.jms.Topic"
     *
     *  @throws IllegalArgumentException If destinationType is not one of the above
     */
    public void
    setDestinationType(String destinationType)
    {
        _loggerIM.entering(_className, "setDestinationType()", destinationType);
        //Must be javax.jms.Queue or Topic
        if (QUEUE.equals(destinationType) ||
            TOPIC.equals(destinationType)) {

            this.destinationType = destinationType;

        } else {
            IllegalArgumentException iae = new IllegalArgumentException(_lgrMID_EXC+"setDestinationType:Invalid destinationType="+destinationType);
            _loggerIM.warning(iae.getMessage());
            _loggerIM.throwing(_className, "setDestinationType()", iae);
            throw iae;
        }
    }

    /** Gets the type of the destination for the MessageEndpoint consumer
     *
     *  @return The destination type
     *          values are "javax.jms.Queue" or "javax.jms.Topic"
     */
    public String
    getDestinationType()
    {
        return destinationType;
    }

    /** Sets the name of the destination for the MessageEndpoint consumer
     *
     *  @param destination The destination name
     *
     *  @throws IllegalArgumentException If destination is not a valid name
     */
    public void
    setDestination(String destination)
    {
        _loggerIM.entering(_className, "setDestination()", destination);
        //Destination must be valid name according to MQ rule
        if (!DestinationName.isSyntaxValid(destination)) {
            IllegalArgumentException iae = new IllegalArgumentException(_lgrMID_EXC+"setDestination:Invalid destination name="+destination);
            _loggerIM.warning(iae.getMessage());
            _loggerIM.throwing(_className, "setDestination()", iae);
            throw iae;
        }
        this.destination = destination;
    }

    /** Gets the name of the destination for the MessageEndpoint consumer
     *
     *  @return The destination name
     */
    public String
    getDestination()
    {
        _loggerIM.entering(_className, "getDestination()", destination);
        return destination;
    }

    /** Sets the message selector for the MessageEndpoint consumer
     *
     *  @param messageSelector The selector
     */
    public void
    setMessageSelector(String messageSelector)
    {
        _loggerIM.entering(_className, "setMessageSelector()", messageSelector);
        this.messageSelector = messageSelector;
    }

    /** Gets the message selector for the MessageEndpoint consumer
     *
     *  @return The message selector
     */
    public String
    getMessageSelector()
    {
        _loggerIM.entering(_className, "getMessageSelector()", messageSelector);
        return messageSelector;
    }

    /** Sets the acknowledgement mode for the MessageEndpoint consumer
     *
     *  @param acknowledgeMode The acknowledgement mode
     *         valid values are "Auto-acknowledge" and "Dups-ok-acknowledge"
     *         and "No-acknowledge" (Non-Durable/Topic only)
     *
     *  @throws IllegalArgumentException If acknowledgement mode is not valid
     */
    public void
    setAcknowledgeMode(String acknowledgeMode)
    {
        _loggerIM.entering(_className, "setAcknowledgeMode()", acknowledgeMode);
        //Must be Auto-acknowledge or Dups-ok-acknowledge
        if (AUTOACKNOWLEDGE.equals(acknowledgeMode) ||
            DUPSOKACKNOWLEDGE.equals(acknowledgeMode)) {

            this.acknowledgeMode = acknowledgeMode;

        } else {
            IllegalArgumentException iae = new IllegalArgumentException(_lgrMID_EXC+"setAcknowledgeMode:Invalid acknowledgeMode="+acknowledgeMode);
            _loggerIM.warning(iae.getMessage());
            _loggerIM.throwing(_className, "setAcknowledgeMode()", iae);
            throw iae;
        }
    }

    /** Gets the acknowledgement mode for the MessageEndpoint consumer
     *
     *  @return The acknowledgement mode
     *          one of either "Auto-acknowledge" or "Dups-ok-acknowledge" or null
     */
    public String
    getAcknowledgeMode()
    {
        _loggerIM.entering(_className, "getAcknowledgeMode()", acknowledgeMode);
        return acknowledgeMode;
    }

    /** Sets a custom acknowledgement mode for the MessageEndpoint consumer
     *
     *  @param customAcknowledgeMode The customAcknowledgement mode
     *         valid values are "No-acknowledge" (Non-Durable/Topic only)
     *
     *  @throws IllegalArgumentException If customAcknowledgement mode is not valid
     */
    public void
    setCustomAcknowledgeMode(String customAcknowledgeMode)
    {
        _loggerIM.entering(_className, "setCustomAcknowledgeMode()", customAcknowledgeMode);
        //Must be No-acknowledge
        if (NOACKNOWLEDGE.equals(customAcknowledgeMode)) {
            this.customAcknowledgeMode = customAcknowledgeMode;
        } else {
            IllegalArgumentException iae = new IllegalArgumentException(_lgrMID_EXC+"setCustomAcknowledgeMode:Invalid customAcknowledgeMode="+customAcknowledgeMode);
            _loggerIM.warning(iae.getMessage());
            _loggerIM.throwing(_className, "setCustomAcknowledgeMode()", iae);
            throw iae;
        }
    }

    /** Gets the CustomAcknowledgement mode for the MessageEndpoint consumer
     *
     *  @return The CustomAcknowledgement mode
     *          currently only "No-acknowledge" or null
     */
    public String
    getCustomAcknowledgeMode()
    {
        _loggerIM.entering(_className, "getCustomAcknowledgeMode()", customAcknowledgeMode);
        return customAcknowledgeMode;
    }

    /** Sets the subscription durability for the MessageEndpoint consumer
     *
     *  @param subscriptionDurability The durability mode
     *         valid values are "Durable" and "NonDurable"
     *
     *  @throws IllegalArgumentException If subscriptionDurability is not valid
     */
    public void
    setSubscriptionDurability(String subscriptionDurability)
    {
        _loggerIM.entering(_className, "setSubscriptionDurability()", subscriptionDurability);
        //Must be Durable or NonDurable
        if (DURABLE.equals(subscriptionDurability) ||
            NONDURABLE.equals(subscriptionDurability)) {

            this.subscriptionDurability = subscriptionDurability;

        } else {
            IllegalArgumentException iae = new IllegalArgumentException(_lgrMID_EXC+"setSubscriptionDurability:Invalid subscriptionDurability="+subscriptionDurability);
            _loggerIM.warning(iae.getMessage());
            _loggerIM.throwing(_className, "setSubscriptionDurability()", iae);
            throw iae;
        }
    }

    /** Gets the subscription durability for the MessageEndpoint consumer
     *
     *  @return The subscription durability
     *          one of either "Durable" or "NonDurable" or null
     */
    public String
    getSubscriptionDurability()
    {
        _loggerIM.entering(_className, "getSubscriptionDurability()", subscriptionDurability);
        return subscriptionDurability;
    }

    /** Sets the client identifier for the MessageEndpoint consumer
     *
     *  @param clientId The client identifier
     */
    public void
    setClientId(String clientId)
    {
        _loggerIM.entering(_className, "setClientId()", clientId);
        this.clientId = clientId;
    }

    /** Return the client identifier for the MessageEndpoint consumer
     *
     *  @return The client identifier
     */
    public String
    getClientId()
    {
        _loggerIM.entering(_className, "getClientId()", clientId);
        return clientId;
    }

    /** Sets the subscription name for the MessageEndpoint consumer
     *
     *  @param subscriptionName The name of the subscription
     */
    public void
    setSubscriptionName(String subscriptionName)
    {
        _loggerIM.entering(_className, "setSubscriptionName()", subscriptionName);
        this.subscriptionName = subscriptionName; 
    }

    /** Returns the subscription name for the MessageEndpoint consumer
     *
     *  @return The name of the subscription
     */
    public String
    getSubscriptionName()
    {
        _loggerIM.entering(_className, "getSubscriptionName()", subscriptionName);
        return subscriptionName;
    }

    /** Sets the connectionFactoryJNDIName for the MessageEndpoint consumer
     *
     *  @param connectionFactoryJNDIName The connectionFactoryJNDIName
     */
    public void
    _setConnectionFactoryJNDIName(String connectionFactoryJNDIName)
    {
        _loggerIM.entering(_className, "_setConnectionFactoryJNDIName()", connectionFactoryJNDIName);
        this.connectionFactoryJNDIName = connectionFactoryJNDIName; 
    }

    /** Returns the connectionFactoryJNDIName for the MessageEndpoint consumer
     *
     *  @return The connectionFactoryJNDIName
     */
    public String
    _getConnectionFactoryJNDIName()
    {
        _loggerIM.entering(_className, "_getConnectionFactoryJNDIName()", connectionFactoryJNDIName);
        return connectionFactoryJNDIName;
    }

    /** Sets the endpointPoolMaxSize for the MessageEndpoint consumer
     *
     *  @param endpointPoolMaxSize The endpointPoolMaxSize
     */
    public void
    setEndpointPoolMaxSize(int endpointPoolMaxSize)
    {
        _loggerIM.entering(_className, "setEndpointPoolMaxSize()", Integer.toString(endpointPoolMaxSize));
        if (endpointPoolMaxSize < 1) {
            IllegalArgumentException iae = new IllegalArgumentException(_lgrMID_EXC+"setEndpointPoolMaxSize:"+
                    "Value must be greater than 0"+
                    "Invalid value="+endpointPoolMaxSize);
            _loggerIM.warning(iae.getMessage());
            _loggerIM.throwing(_className, "setEndpointPoolMaxSize()", iae);
            throw iae;
        }
        this.endpointPoolMaxSize = endpointPoolMaxSize; 
    }

    /** Returns the endpointPoolMaxSize for the MessageEndpoint consumer
     *
     *  @return The endpointPoolMaxSize
     */
    public int
    getEndpointPoolMaxSize()
    {
        _loggerIM.entering(_className, "getEndpointPoolMaxSize()", Integer.toString(endpointPoolMaxSize));
        return endpointPoolMaxSize;
    }

    /** Sets the endpointPoolSteadySize for the MessageEndpoint consumer
     *
     *  @param endpointPoolSteadySize The endpointPoolSteadySize
     */
    public void
    setEndpointPoolSteadySize(int endpointPoolSteadySize)
    {
        _loggerIM.entering(_className, "setEndpointPoolSteadySize()", Integer.toString(endpointPoolSteadySize));
        if (endpointPoolSteadySize < 0) {
            IllegalArgumentException iae = new IllegalArgumentException(_lgrMID_EXC+"setEndpointPoolSteadySize:"+
                    "Value must be greater than or equal to 0"+
                    "Invalid value="+endpointPoolSteadySize);
            _loggerIM.warning(iae.getMessage());
            _loggerIM.throwing(_className, "setEndpointPoolSteadySize()", iae);
            throw iae;
        }
        this.endpointPoolSteadySize = endpointPoolSteadySize; 
    }

    /** Returns the endpointPoolSteadySize for the MessageEndpoint consumer
     *
     *  @return The endpointPoolSteadySize
     */
    public int
    getEndpointPoolSteadySize()
    {
        _loggerIM.entering(_className, "getEndpointPoolSteadySize()", Integer.toString(endpointPoolSteadySize));
        return endpointPoolSteadySize;
    }

    /** Sets the endpointPoolResizeCount for the MessageEndpoint consumer
     *
     *  @param endpointPoolResizeCount The endpointPoolResizeCount
     */
    public void
    setEndpointPoolResizeCount(int endpointPoolResizeCount)
    {
        _loggerIM.entering(_className, "setEndpointPoolResizeCount()", Integer.toString(endpointPoolResizeCount));
        if (endpointPoolResizeCount < 1) {
            IllegalArgumentException iae = new IllegalArgumentException(_lgrMID_EXC+"setEndpointPoolResizeCount:"+
                    "Value must be greater than 0:"+
                    "Invalid value="+endpointPoolResizeCount);
            _loggerIM.warning(iae.getMessage());
            _loggerIM.throwing(_className, "setEndpointPoolResizeCount()", iae);
            throw iae;
        }
        this.endpointPoolResizeCount = endpointPoolResizeCount; 
    }

    /** Returns the endpointPoolResizeCount for the MessageEndpoint consumer
     *
     *  @return The endpointPoolResizeCount
     */
    public int
    getEndpointPoolResizeCount()
    {
        _loggerIM.entering(_className, "getEndpointPoolResizeCount()", Integer.toString(endpointPoolResizeCount));
        return endpointPoolResizeCount;
    }

    /** Sets the endpointPoolResizeTimeout for the MessageEndpoint consumer
     *
     *  @param endpointPoolResizeTimeout The endpointPoolResizeTimeout
     */
    public void
    setEndpointPoolResizeTimeout(int endpointPoolResizeTimeout)
    {
        _loggerIM.entering(_className, "setEndpointPoolResizeTimeout()", Integer.toString(endpointPoolResizeTimeout));
        if (endpointPoolResizeTimeout < 1) {
            IllegalArgumentException iae = new IllegalArgumentException(_lgrMID_EXC+"setEndpointPoolResizeTimeout:"+
                    "Value must be greater than 0:"+
                    "Invalid value="+endpointPoolResizeTimeout);
            _loggerIM.warning(iae.getMessage());
            _loggerIM.throwing(_className, "setEndpointPoolResizeTimeout()", iae);
            throw iae;
        }
        this.endpointPoolResizeTimeout = endpointPoolResizeTimeout; 
    }

    /** Returns the endpointPoolResizeTimeout for the MessageEndpoint consumer
     *
     *  @return The endpointPoolResizeTimeout
     */
    public int
    getEndpointPoolResizeTimeout()
    {
        _loggerIM.entering(_className, "getEndpointPoolResizeTimeout()", Integer.toString(endpointPoolResizeTimeout));
        return endpointPoolResizeTimeout;
    }

    /** Sets the maximum number of Redelivery attempts
     *  to an Endpoint that throws an Exception.
     *  This enables the RA to stop
     *  endlessly delivering messages to an Endpoint
     *  that repeatedly throws an Exception
     *
     *  @param endpointExceptionRedeliveryAttempts The maximum number of Redelivery attempts
     */
    public void
    setEndpointExceptionRedeliveryAttempts(int endpointExceptionRedeliveryAttempts)
    {
        _loggerIM.entering(_className, "setEndpointExceptionRedeliveryAttempts()", Integer.toString(endpointExceptionRedeliveryAttempts));
        if (endpointExceptionRedeliveryAttempts < 0) {
            IllegalArgumentException iae = new IllegalArgumentException(_lgrMID_EXC+"setEndpointExceptionRedeliveryAttempts:"+
                    "Value must be greater than or equal to 0:"+
                    "Invalid value="+endpointExceptionRedeliveryAttempts);
            _loggerIM.warning(iae.getMessage());
            _loggerIM.throwing(_className, "setEndpointExceptionRedeliveryAttempts()", iae);
            throw iae;
        }
        this.endpointExceptionRedeliveryAttempts = endpointExceptionRedeliveryAttempts; 
    }

    /** Returns the the maximum number of Redelivery attempts
     *  to an Endpoint that throws an Exception.
     *  This enables the RA to stop
     *  endlessly delivering messages to an Endpoint
     *  that repeatedly throws an Exception
     *
     *  @return The maximum number of Redelivery attempts
     *          to an Endpoint.
     */
    public int
    getEndpointExceptionRedeliveryAttempts()
    {
        _loggerIM.entering(_className, "getEndpointExceptionRedeliveryAttempts()", Integer.toString(endpointExceptionRedeliveryAttempts));
        return endpointExceptionRedeliveryAttempts;
    }

    /** Sets the interval for Redelivery attempts
     *  to an Endpoint that throws an Exception.
     *
     *  @param endpointExceptionRedeliveryInterval The maximum number of Redelivery attempts
     */
    public void
    setEndpointExceptionRedeliveryInterval(int endpointExceptionRedeliveryInterval)
    {
        _loggerIM.entering(_className, "setEndpointExceptionRedeliveryInterval()", Integer.toString(endpointExceptionRedeliveryInterval));
        if (endpointExceptionRedeliveryInterval < 1) {
            IllegalArgumentException iae = new IllegalArgumentException(_lgrMID_EXC+"setEndpointExceptionRedeliveryInterval:"+
                    "Value must be greater than 0:"+
                    "Invalid value="+endpointExceptionRedeliveryInterval);
            _loggerIM.warning(iae.getMessage());
            _loggerIM.throwing(_className, "setEndpointExceptionRedeliveryInterval()", iae);
            throw iae;
        }
        this.endpointExceptionRedeliveryInterval = endpointExceptionRedeliveryInterval; 
    }

    /** Returns the interval for Redelivery attempts
     *  to an Endpoint that throws an Exception.
     *
     *  @return The interval for Redelivery attempts
     *          to an Endpoint.
     */
    public int
    getEndpointExceptionRedeliveryInterval()
    {
        _loggerIM.entering(_className, "getEndpointExceptionRedeliveryInterval()", Integer.toString(endpointExceptionRedeliveryInterval));
        return endpointExceptionRedeliveryInterval;
    }

    /** Sets whether to send undeliverable messages to the DMQ
     *
     *  @param sendUndeliverableMsgsToDMQ If true; sends the undeliverable
     *         messages to the DMQ.
     */
    public void
    setSendUndeliverableMsgsToDMQ(boolean sendUndeliverableMsgsToDMQ)
    {
        _loggerIM.entering(_className, "setSendUndeliverableMsgsToDMQ()", Boolean.toString(sendUndeliverableMsgsToDMQ));
        this.sendUndeliverableMsgsToDMQ = sendUndeliverableMsgsToDMQ; 
    }

    /** Returns whether to send undeliverable messages to the DMQ
     *
     *  @return sendUndeliverableMsgsToDM
     *  Whether to send undeliverable messages to the DMQ
     */
    public boolean
    getSendUndeliverableMsgsToDMQ()
    {
        _loggerIM.entering(_className, "getSendUndeliverableMsgsToDMQ()", Boolean.toString(sendUndeliverableMsgsToDMQ));
        return sendUndeliverableMsgsToDMQ;
    }

    /** Sets the ContextClassLoader to be used for the MessageEndpoint consumer
     *
     *  @param contextClassLoader The contextClassLoader
     */
    public void
    setContextClassLoader(ClassLoader contextClassLoader)
    {
        _loggerIM.entering(_className, "setContextClassLoader()", contextClassLoader);
        this.contextClassLoader = contextClassLoader; 
    }

    /** Returns the contextClassLoader used for the MessageEndpoint consumer
     *
     *  @return The contextClassLoader
     */
    public ClassLoader
    getContextClassLoader()
    {
        _loggerIM.entering(_className, "getContextClassLoader()", contextClassLoader);
        return contextClassLoader;
    }

    /** Sets the addressList for the MessageEndpoint consumer
     *
     *  @param addressList The addressList
     */
    public void
    setAddressList(String addressList)
    {
        _loggerIM.entering(_className, "setAddressList()", addressList);
        this.addressList = addressList;
        if ((addressList != null) && !"".equals(addressList)){
            this.enableRADirect = false;
            this.enableAPIDirect = false;            
            this.addressListSet = true;
        }
    }

    /** Returns the addressList for the MessageEndpoint consumer
     *
     *  @return The addressList
     */
    public String
    getAddressList()
    {
        _loggerIM.entering(_className, "getAddressList()", addressList);
        return addressList;
    }

    /** Sets the mdbName for the MessageEndpoint consumer
     *
     *  @param mdbName The MDB name
     */
    public void
    setMdbName(String mdbName)
    {
        _loggerIM.entering(_className, "setMdbName()", mdbName);
        this.mdbName = mdbName; 
    }

    /** Returns the mdbName for the MessageEndpoint consumer
     *
     *  @return The mdbName
     */
    public String
    getMdbName()
    {
        _loggerIM.entering(_className, "getMdbName()", mdbName);
        return mdbName;
    }

    /** Sets the UserName for this Endpoint instance
     *   
     *  @param userName The UserName
     */  
    public void  
    setUserName(String userName)
    {
        _loggerIM.entering(_className, "setUserName()", userName);
        this.userName = userName;
    }

    /** Return the UserName for this Endpoint instance
     *   
     *  @return The UserName
     */  
    public String
    getUserName()
    {
        _loggerIM.entering(_className, "getUserName()", userName);
        if ((userName == null) && (ra != null)) {
            return ra.getUserName();
        } else {
            return userName;
        }
    }

    /** Sets the Password for this Endpoint instance
     *   
     *  @param password The Password
     */  
    public void
    setPassword(String password)
    {
        _loggerIM.entering(_className, "setPassword()");
        this.password = password;
    }
 
    /** Return the Password for this Endpoint instance
     *   
     *  @return The Password
     */ 
    public String
    getPassword()
    {
        _loggerIM.entering(_className, "getPassword()");
        if ((password == null) && (ra != null)) {
            return ra.getPassword();
        } else {
            return password;
        }
    }

    public void setEnableRADirect(boolean value) {
        _loggerIM.entering(_className, "setEnableRADirect()", value);
        this.enableRADirect = value;
    }
    
    public void setEnableAPIDirect(boolean value) {
        _loggerIM.entering(_className, "setEnableAPIDirect()", value);
        this.enableAPIDirect = value;
    }    

    public boolean getEnableRADirect(){
        _loggerIM.entering(_className, "getEnableRADirect()", this.enableRADirect);
        return this.enableRADirect;
    }
    
    public boolean getEnableAPIDirect(){
        _loggerIM.entering(_className, "getEnableAPIDirect()", this.enableAPIDirect);
        return this.enableAPIDirect;
    }    
    
    /**
     * Set additional arbitrary connection factory properties
     * 
     * The properties must be specified as a String containing a comma-separated list of name=value pairs
     * e.g. prop1=value1,prop2=value2
     * If a value contains a = or , you can either 
     * place the whole value between quotes (prop1="val=ue") or 
     * use \ as an escape character (prop1=val\,ue)
     * 
     * This method cannot be used to set properties which are configured internally or which have their own setter methods. These are:
     * imqReconnectEnabled, imqReconnectAttempts, imqReconnectInterval, imqDefaultUsername, 
     * imqDefaultPassword, imqAddressList, imqAddressListIterations
     * 
     * Any values specified for those properties will be ignored
     *
     *
     * @param props connection factory properties as a comma-separated list of name=value pairs
     */
    public void setOptions(String props){
    	options=props;
    }
    
    public String getOptions(){
    	return options;
    }
    
    //////////////////////////////////////////////////////////////////////////////////

    // Methods for RA use
    protected String
    _AddressList()
    {
        if (addressList != null) {
            return addressList;
        } else {
            if (ra != null) {
                return ((com.sun.messaging.jms.ra.ResourceAdapter)ra)._getEffectiveConnectionURL();
            } else {
                return "localhost";
            }
        }
    }

    public void _setDeliverySerial(boolean mode) {
        deliverySerial = mode;
    }

    protected boolean _getDeliverySerial() {
        return deliverySerial;
    }

    protected boolean _deliverySerial() {
        return deliverySerial;
    }

    protected String _getGroupName() {
        return groupName;
    }

    protected void _setGroupName(String groupName) {
        this.groupName = groupName;
    }

    protected String _getRAUID() {
        return raUID;
    }

    protected void _setRAUID(String raUID) {
        this.raUID = raUID;
    }

    protected void _setInClusteredContainer(boolean inClusteredContainer) {
        this.inClusteredContainer = inClusteredContainer;
    }

    protected boolean _isInClusteredContainerSet() {
        return inClusteredContainer;
    }

    protected boolean _isNoAckDeliverySet() {
        return (NOACKNOWLEDGE.equals(customAcknowledgeMode));
    }

    protected boolean _isDurableSet() {
        return (DURABLE.equals(subscriptionDurability));
    }

    protected boolean _isDestTypeQueueSet() {
        return (QUEUE.equals(destinationType));
    }

    protected boolean _isDestTypeTopicSet() {
        return (TOPIC.equals(destinationType));
    }

    protected boolean _isRADirectEnabled() {
        if (this.ra != null){
            return (ra._isRADirect() && this.enableRADirect);
        } else {
            return this.enableRADirect;
        }
    }
    
    protected boolean _isAPIDirectEnabled() {
        if (this.ra != null){
            return (ra._isAPIDirect() && this.enableAPIDirect);
        } else {
            return this.enableAPIDirect;
        }
    }    
    // Info Methods
    public String
    toString()
    {
        return ("ActvationSpec configuration=\n"+
                "\tDestinationType                     ="+destinationType+"\n"+
                "\tDestination                         ="+destination+"\n"+
                "\tMessageSelector                     ="+messageSelector+"\n"+
                "\tAcknowledgeMode                     ="+acknowledgeMode+"\n"+
                "\tSubscriptionDurability              ="+subscriptionDurability+"\n"+
                "\tuseSharedSubscriptionInClusteredContainer="+useSharedSubscriptionInClusteredContainer+"\n"+
                "\tClientId                            ="+clientId+"\n"+
                "\tSubscriptionName                    ="+subscriptionName+"\n"+
                "\tEndpointPoolMaxSize                 ="+endpointPoolMaxSize+"\n"+
                "\tEndpointPoolSteadySize              ="+endpointPoolSteadySize+"\n"+
                "\tEndpointPoolResizeCount             ="+endpointPoolResizeCount+"\n"+
                "\tEndpointPoolResizeTimeout           ="+endpointPoolResizeTimeout+"\n"+
                "\tEndpointExceptionRedeliveryAttempts ="+endpointExceptionRedeliveryAttempts+"\n"+
                "\tEndpointExceptionRedeliveryInterval ="+endpointExceptionRedeliveryInterval+"\n"+
                "\tSendUndeliverableMsgsToDMQ          ="+sendUndeliverableMsgsToDMQ+"\n"+
                "\tGroupName                           ="+groupName+"\n"+
                "\tRAUID                               ="+raUID+"\n"+
                "\tInClusteredContainer                ="+inClusteredContainer+"\n"+
                "\tMdbName                             ="+mdbName+"\n"+
                "\tUserName                            ="+userName+"\n"+
                "\tEnableRADirect                      ="+enableRADirect+"\n"+
                "\tEnableAPIDirect                      ="+enableAPIDirect+"\n"+                
                "\tAddressList (in effect)             ="+_AddressList()+"\n"+
                "\toptions                 			   ="+options+"\n");
    }


	public boolean isUseSharedSubscriptionInClusteredContainer() {
		return useSharedSubscriptionInClusteredContainer;
	}


	public void setUseSharedSubscriptionInClusteredContainer(
			boolean useSharedSubscriptionInClusteredContainer) {
		this.useSharedSubscriptionInClusteredContainer = useSharedSubscriptionInClusteredContainer;
	}

}
