/*
 * jBoss, the OpenSource EJB server
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */
package org.jboss.metadata;

import javax.jms.Session;

import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import org.jboss.deployment.DeploymentException;

/**
 *   <description>
 *   Based on SessionMetaData
 *
 * Have to add changes ApplicationMetaData and ConfigurationMetaData
 *   @see <related>
 *   @author <a href="mailto:sebastien.alborini@m4x.org">Sebastien Alborini</a>
 *   @author Peter Antman (peter.antman@tim.se)
 * @author <a href="mailto:andreas@jboss.org">Andreas Schaefer</a>
 *
 * <p><b>Revisions:</b></p>
 * <p><b>20011031: Andy</b>
 * <ul>
 * <li>Ensured that the <message-selector> value in the descriptor does not
 *     be compromised by leading and trailing spaces as well as line-breaks</li>
 * </ul>
 * </p>
 *
 *   @version $Revision: 1.7.4.4 $
 */
public class MessageDrivenMetaData extends BeanMetaData
{
   // Constants -----------------------------------------------------
   public static final int AUTO_ACKNOWLEDGE_MODE = Session.AUTO_ACKNOWLEDGE;
   public static final int DUPS_OK_ACKNOWLEDGE_MODE = Session.DUPS_OK_ACKNOWLEDGE;
   public static final int CLIENT_ACKNOWLEDGE_MODE = Session.CLIENT_ACKNOWLEDGE;
   public static final byte DURABLE_SUBSCRIPTION = 0;
   public static final byte NON_DURABLE_SUBSCRIPTION = 1;
   public static final byte TX_UNSET = 9;
   
   // Attributes ----------------------------------------------------
   private int acknowledgeMode = AUTO_ACKNOWLEDGE_MODE;
   private String destinationType;
   private byte subscriptionDurability = NON_DURABLE_SUBSCRIPTION;
   private byte methodTransactionType= TX_UNSET;
   private String messageSelector = null;
   private String destinationJndiName;
   private String user = null;
   private String passwd = null;
   private String clientId = null;
   
   // Static --------------------------------------------------------
   
   // Constructors --------------------------------------------------
   public MessageDrivenMetaData(ApplicationMetaData app)
   {
      super(app, BeanMetaData.MDB_TYPE);
   }
   
   // Public --------------------------------------------------------
   /**
    * returns MessageDrivenMetaData.AUTO_ACKNOWLADGE_MODE or
    * MessageDrivenMetaData.DUPS_OK_AKNOWLEDGE_MODE, or MessageDrivenMetaData.CLIENT_ACKNOWLEDGE_MODE
    *
    */
   public int getAcknowledgeMode()
   {
      // My interpretation of the EJB and JMS spec leads
      // me to that CLIENT_ACK is the only possible
      // solution. A transaction is per session in JMS, and
      // it is not possible to get access to the transaction.
      // According to the JMS spec it is possible to
      // multithread handling of messages (but not session),
      // but there is NO transaction support for this.
      // I,e, we can not use the JMS transaction for
      // message ack: hence we must use manual ack.
      
      // But for NOT_SUPPORTED this is not true here we
      // should have AUTO_ACKNOWLEDGE_MODE
      
      // This is not true for now. For JBossMQ we relly
      // completely on transaction handling. For JBossMQ, the
      // ackmode is actually not relevant. We keep it here
      // anyway, if we find that this is needed for other
      // JMS provider, or is not good.
      if ( getMethodTransactionType() == TX_REQUIRED)
         return  CLIENT_ACKNOWLEDGE_MODE;
      else
         return acknowledgeMode;
   }
   
   public String getDestinationType()
   {
      return destinationType;
   }
   public String getMessageSelector()
   {
      return messageSelector;
   }
   public String getDestinationJndiName()
   {
      return destinationJndiName;
   }
   public String getUser()
   {
      return user;
   }
   public String getPasswd()
   {
      return passwd;
   }
   public String getClientId()
   {
      return clientId;
   }
   public byte getMethodTransactionType()
   {
      if (methodTransactionType == TX_UNSET)
      {
         if (isContainerManagedTx())
         {
            //
            // Here we should have a way of looking up wich message class
            // the MessageDriven bean implements, by doing this we might
            // be able to use other MOM systems, aka XmlBlaser. TODO!
            // The MessageDrivenContainer needs this too!!
            //
            Class[] empty = {};
            if(super.getMethodTransactionType("onMessage", empty, true) == MetaData.TX_REQUIRED)
            {
               methodTransactionType = TX_REQUIRED;
            }
            else
            {
               methodTransactionType = TX_NOT_SUPPORTED;
            }
         }
         else
         {
            methodTransactionType = TX_UNKNOWN;
         }
      }
      return methodTransactionType;
   }
   
   public byte getMethodTransactionType(String methodName, Class[] params, boolean remote)
   {
      // An MDB may only ever have on method
      return getMethodTransactionType();
   }
   /**
    * returns MessageDrivenMetaData.DURABLE_SUBSCRIPTION or
    * MessageDrivenMetaData.NON_DURABLE_SUBSCRIPTION
    */
   public byte getSubscriptionDurability()
   {
      return subscriptionDurability;
   }

   public String getDefaultConfigurationName()
   {
      return jdk13Enabled() ? ConfigurationMetaData.MESSAGE_DRIVEN_13 : ConfigurationMetaData.MESSAGE_DRIVEN_12;
      
   }
   
   public void importEjbJarXml(Element element) throws DeploymentException
   {
      super.importEjbJarXml(element);
      
      messageSelector = getElementContent(getOptionalChild(element, "message-selector"));
      if( messageSelector != null )
      {
         //AS Check for Carriage Returns, remove them and trim the selector
         int i = -1;
         // Note this only works this way because the search and replace are distinct
         while( ( i = messageSelector.indexOf( "\r\n" ) ) >= 0 )
         {
            // Replace \r\n by a space
            messageSelector = ( i == 0 ? "" : messageSelector.substring( 0, i ) ) +
            " " +
            ( i >= messageSelector.length() - 2 ? "" : messageSelector.substring( i + 2 ) );
         }
         i = -1;
         while( ( i = messageSelector.indexOf( "\r" ) ) >= 0 )
         {
            // Replace \r by a space
            messageSelector = ( i == 0 ? "" : messageSelector.substring( 0, i ) ) +
            " " +
            ( i >= messageSelector.length() - 1 ? "" : messageSelector.substring( i + 1 ) );
         }
         i = -1;
         while( ( i = messageSelector.indexOf( "\n" ) ) >= 0 )
         {
            // Replace \n by a space
            messageSelector = ( i == 0 ? "" : messageSelector.substring( 0, i ) ) +
            " " +
            ( i >= messageSelector.length() - 1 ? "" : messageSelector.substring( i + 1 ) );
         }
         // Finally trim it. This is here because only carriage returns and linefeeds are transformed
         // to spaces
         messageSelector = messageSelector.trim();
         if( "".equals( messageSelector ) )
         {
            messageSelector = null;
         }
      }
      
      // set
      Element destination = getUniqueChild(element, "message-driven-destination");
      destinationType = getElementContent(getUniqueChild(destination
      , "destination-type"));
      
      if (destinationType.equals("javax.jms.Topic"))
      {
         String subscr = getElementContent(getOptionalChild(destination, "subscription-durability"));
         // Should we do sanity check??
         if (subscr.equals("Durable"))
            subscriptionDurability = DURABLE_SUBSCRIPTION;
         else
            subscriptionDurability = NON_DURABLE_SUBSCRIPTION;//Default
      }
      
      // set the transaction type
      String transactionType = getElementContent(getUniqueChild(element, "transaction-type"));
      if (transactionType.equals("Bean"))
      {
         containerManagedTx = false;
         String ack = getElementContent(getUniqueChild(element, "acknowledge-mode"));
         if ( ack.equals("Auto-acknowledge") || ack.equals("AUTO_ACKNOWLEDGE"))
            acknowledgeMode = AUTO_ACKNOWLEDGE_MODE;
         else
            acknowledgeMode = DUPS_OK_ACKNOWLEDGE_MODE;
         // else defaults to AUTO
      }
      else if (transactionType.equals("Container"))
      {
         containerManagedTx = true;
      }
      else
      {
         throw new DeploymentException("transaction type should be 'Bean' or 'Container'");
      }
   }
   public void importJbossXml(Element element) throws DeploymentException
   {
      
      super.importJbossXml(element);
      // set the jndi name, (optional)
      destinationJndiName = getElementContent(getUniqueChild(element, "destination-jndi-name"));
      user = getElementContent(getOptionalChild(element,"mdb-user"));
      passwd = getElementContent(getOptionalChild(element,"mdb-passwd"));
      clientId = getElementContent(getOptionalChild(element,"mdb-client-id"));
   }
   // Package protected ---------------------------------------------
   
   // Protected -----------------------------------------------------
   
   // Private -------------------------------------------------------
   
   // Inner classes -------------------------------------------------
}
