/*
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999 Bull S.A.
 * Contact: jonas-team@objectweb.org
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * Initial developer(s): ____________________________________.
 * Contributor(s): ______________________________________.
 *
 * --------------------------------------------------------------------------
 * $$
 * --------------------------------------------------------------------------
 */


package org.objectweb.jonas_ejb.deployment.api;


import org.objectweb.jonas_ejb.deployment.xml.MessageDriven;
import org.objectweb.jonas_ejb.deployment.xml.AssemblyDescriptor;
import org.objectweb.jonas_ejb.deployment.xml.JonasMessageDriven;
import org.objectweb.jonas_ejb.deployment.xml.JonasMessageDrivenDestination;
import org.objectweb.jonas_ejb.deployment.xml.MessageDrivenDestination;
import org.objectweb.jonas_ejb.deployment.xml.SecurityRoleRef;


/*
 * Base class for deployment descriptor of message driven bean
 * @author Helene Joanin
 */
public class MessageDrivenDesc extends BeanDesc {

    public final static int AUTO_ACKNOWLEDGE = 1;
    public final static int DUPS_OK_ACKNOWLEDGE = 2;
    protected static final String[] ACKMODE = {null,"AUTO_ACKNOWLEDGE","DUPS_OK_ACKNOWLEDGE"};

    private final static int NONE_SUBS_DURABILITY = 0;
    public final static int SUBS_DURABLE = 1;
    public final static int SUBS_NON_DURABLE = 2;
    protected static final String[] SUBS_DURABILITY = {null,"SUBSCRIPTION_DURABLE","SUBSCRIPTION_NON_DURABLE"};

    public final static int DEFAULT_MAX_MESSAGES = 1;

    protected int transactionType;
    protected String selector = null;
    protected int acknowledgeMode;
    protected int subscriptionDurability = NONE_SUBS_DURABILITY;
    protected Class destinationType = null;
    protected String destinationJndiName = null;
    protected int  txAttribute = MethodDesc.TX_NOT_SET; // for onMessage method
    protected boolean isTopicDestination = false;

    /**
     * package protected constructor used by API
     */
    MessageDrivenDesc(ClassLoader classLoader,  MessageDriven md, AssemblyDescriptor asd, JonasMessageDriven jMd) 
            throws DeploymentDescException {

        super(classLoader, md.getDisplayName(), md.getEjbName(), null,
              null, null, null, null, md.getEjbClass(),
              md.getEnvEntryList(), md.getResourceRefList(), jMd.getJonasResourceList(),
              md.getResourceEnvRefList(), jMd.getJonasResourceEnvList(),
              md.getEjbRefList(), jMd.getJonasEjbRefList(), md.getEjbLocalRefList(), null, asd);

        // necessary check
        if (md.getEjbName() == null) {
            throw new Error("No ejb-name specified for a message-driven bean");
        }

        // transaction-type
        if (md.getTransactionType().getValue().equals("Bean")) {
            transactionType = BEAN_TRANSACTION_TYPE;
        } else if (md.getTransactionType().getValue().equals("Container")) {
            transactionType = CONTAINER_TRANSACTION_TYPE;
        } else {
            throw new DeploymentDescException("Invalid transaction-type content for ejb-name "+ejbName);
        }

        // message selector
        selector = (md.getMessageSelector()!=null)?md.getMessageSelector().getValue():null;

        // acknowledge mode
        if (md.getAcknowledgeMode()==null) {
            acknowledgeMode = AUTO_ACKNOWLEDGE;
        } else {
            if (md.getAcknowledgeMode().getValue().equals("Auto-acknowledge")) {
                acknowledgeMode = AUTO_ACKNOWLEDGE;
            } else  if (md.getAcknowledgeMode().getValue().equals("Dups-ok-acknowledge")) {
                acknowledgeMode = DUPS_OK_ACKNOWLEDGE;
            } else {
                throw new DeploymentDescException("Invalid acknowledge-mode content for ejb-name "+ejbName);
            }
        }

        // message driven destination
        destinationJndiName = jMd.getJonasMessageDrivenDestination().getJndiName().getValue();
        if (md.getMessageDrivenDestination() == null) {
            throw new Error("No message-driven-destination specified for message-driven bean "+ejbName);
        }
        MessageDrivenDestination d = md.getMessageDrivenDestination();
        if (d.getDestinationType().getValue().equals("javax.jms.Queue")) {
            destinationType = javax.jms.Queue.class;
        } else  if (d.getDestinationType().getValue().equals("javax.jms.Topic")) {
            destinationType = javax.jms.Topic.class;
            isTopicDestination = true;
        } else {
            throw new DeploymentDescException("Invalid destination-type content for ejb-name "+ejbName);
        }
        if (d.getSubscriptionDurability() != null) {
            if (destinationType.equals(javax.jms.Queue.class)) {
                throw new DeploymentDescException("subscription-durability of message-driven-destination for ejb-name "+ejbName+" defined");
            }
            if (d.getSubscriptionDurability().getValue().equals("Durable")) {
                subscriptionDurability = SUBS_DURABLE;
            } else  if (d.getSubscriptionDurability().getValue().equals("NonDurable")) {
                subscriptionDurability = SUBS_NON_DURABLE;
            } else {
                throw new DeploymentDescException("Invalid subscription-durability content for ejb-name "+ejbName);
            }
        } else {
            // non-durable subscription default value for topic
            if (destinationType.equals(javax.jms.Topic.class)) {
                subscriptionDurability = SUBS_NON_DURABLE;
            }
        }

        //
        java.lang.reflect.Method[] m = javax.jms.MessageListener.class.getMethods();
        for (int i=0; i<m.length;i++){
            if (m[i].getName().equals("onMessage")) {
                txAttribute = this.getMethodDesc(m[i]).getTxAttribute();
            }
        }
    }
        
    /**
     * Get transaction management type of the message driven.
     * @return transaction type value within BEAN_TRANSACTION_TYPE,CONTAINER_TRANSACTION_TYPE
     */
    public int getTransactionType() {
        return transactionType;
    }

    /**
     * Return the transaction attribute for the onMessage method of
     * Message driven bean
     *
     */
    public int getTxAttribute() {
        return txAttribute;
    }

    /**
     * Return true if BEAN_TRANSACTION_TYPE
     */
    public boolean isBeanManagedTransaction(){
        return (transactionType == BeanDesc.BEAN_TRANSACTION_TYPE);
    }

    /**
     * Assessor for existence of a message-selector for the message driven bean
     * @return true if message-selector is defined for the bean
     */
    public boolean hasSelector() {
        return(selector!=null);
    }

    /**
     * Get the message-selector value of the message driven bean.
     * @return value of the message selector return null if no selector
     */
    public String getSelector() {
        return(selector);
    }

    /**
     * Get the acknowledge-mode of the message driven bean.
     * @return acknowledge-mode value within AUTO_ACKNOWLEDGE, DUPS_OK_ACKNOWLEDGE
     */
    public int getAcknowledgeMode() {
        return(acknowledgeMode);
    }

    /**
     * Get the the durability of the subscription of the message driven bean.
     * @return durability of the subscription value within SUBS_DURABLE, SUBS_NON_DURABLE
     */
    public int getSubscriptionDurability() {
        return(subscriptionDurability);
    }

    public boolean isSubscriptionDurable() {
        return(subscriptionDurability == SUBS_DURABLE);
    }

    /**
     * Get the the destination type of the message driven bean.
     * @return type of the destination of the message driven bean.
     */
    public Class getDestinationType() {
        return(destinationType);
    }
    /**
     * Return true if it is a Topic destination
     */
    public boolean isTopicDestination() {
        return (isTopicDestination);
    }

    /**
     * Return true if tx attribute for onMessage is Required
     */
    public boolean isRequired(){
        return (txAttribute == MethodDesc.TX_REQUIRED);
    }

    /**
     * Get the the destination JNDI name of the message driven bean.
     * @return JNDI name of the destination of the message driven bean.
     */
    public String getDestinationJndiName() {
        return(destinationJndiName);
    }


    /**
     * @return the maximum number of messages that can be assigned to a server session
     *    at one time.
     *   will be configurable in the future
     */
    public int getMaxMessages() {
        return DEFAULT_MAX_MESSAGES;
    }
    /**
     * check that trans-attribute is valid for bean
     */
    protected void checkTxAttribute(java.lang.reflect.Method m) throws DeploymentDescException {
        MethodDesc md = (MethodDesc)methodDesc.get(m);
        if (getTransactionType() == CONTAINER_TRANSACTION_TYPE) {
            // tx-attribute must be set
            if (md.getTxAttribute() == MethodDesc.TX_NOT_SET) {
                throw new DeploymentDescException("trans-attribute missing for method "+m.toString()+" in message driven bean "+getEjbName());
            }
            if ((md.getTxAttribute() != MethodDesc.TX_REQUIRED)
                && (md.getTxAttribute() != MethodDesc.TX_NOT_SUPPORTED)) {
                throw new DeploymentDescException(md.getTxAttributeName()+" is not a valid trans-attribute for method "+m.toString()+" in message driven bean "+getEjbName());
            }
        } else {
            if (md.getTxAttribute() != MethodDesc.TX_NOT_SET) {
                throw new DeploymentDescException("trans-attribute for message driven bean "+getEjbName()+" must not be defined (transaction bean managed)");
            }
        }
    }

    /**
     * Check that the message diven bean descriptor is valid
     * @exception DeploymentDescException thrown for non-valid bean
     */
    public void check() throws DeploymentDescException {
        super.check();
    }
    
    /**
     * String representation of the object for test purpose
     * @return String representation of this object
     */
    public String toString() {
        StringBuffer ret = new StringBuffer();
        ret.append(super.toString());
        ret.append("\ngetTransactionType()="+TRANS[getTransactionType()]);
        if (hasSelector()) {
            ret.append("\ngetSelector()=\""+getSelector()+"\"");
        }
        ret.append("\ngetAcknowledgeMode()="+ACKMODE[getAcknowledgeMode()]);
        ret.append("\ngetDestinationType()="+getDestinationType().getName());
        ret.append("\ngetSubscriptionDurability()="+SUBS_DURABILITY[getSubscriptionDurability()]);
        ret.append("\ngetDestinationJndiName()="+getDestinationJndiName());
        return ret.toString();
    }
    
}

