/*
 * JBoss, the OpenSource J2EE webOS
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */

package org.jboss.resource.deployment;

import java.beans.IntrospectionException;
import java.util.Collection;
import java.util.Iterator;
import java.util.Properties;

import javax.management.ObjectName;
import javax.resource.spi.ActivationSpec;

import org.jboss.deployment.DeploymentException;
import org.jboss.logging.Logger;
import org.jboss.metadata.ActivationConfigPropertyMetaData;
import org.jboss.resource.metadata.MessageListenerMetaData;
import org.jboss.resource.metadata.RequiredConfigPropertyMetaData;
import org.jboss.util.propertyeditor.PropertyEditors;

/**
 * An activation spec factory
 *
 * @author  <a href="adrian@jboss.com">Adrian Brock</a>
 * @version $Revision: 1.3.4.2 $
 */
public class ActivationSpecFactory
{
   // Constants -----------------------------------------------------
   
   /** The logger */
   private static final Logger log = Logger.getLogger(ActivationSpecFactory.class);
   
   // Attributes ----------------------------------------------------
   
   // Static --------------------------------------------------------

   public static ActivationSpec createActivationSpec(ObjectName rarName,
      String messagingType, Collection activationConfig,
      MessageListenerMetaData mlmd)
      throws Exception
   {
      boolean trace = log.isTraceEnabled();
      
      if (trace)
         log.trace("Create ActivationSpec rar=" + rarName + " messagingType=" + messagingType +
            " activationConfig=" + activationConfig + " messageListner=" + mlmd);
      
      // Check we have all the required properties
      for (Iterator i = mlmd.getRequiredConfigProperties().iterator(); i.hasNext();)
      {
         RequiredConfigPropertyMetaData rcpmd = (RequiredConfigPropertyMetaData) i.next();
         if (trace)
            log.trace("Checking required config " + rcpmd.getName());
         boolean found = false;
         for (Iterator j = activationConfig.iterator(); j.hasNext();)
         {
            ActivationConfigPropertyMetaData acpmd = (ActivationConfigPropertyMetaData) j.next();
            if (rcpmd.getName().equals(acpmd.getName()))
            {
               if (trace)
                  log.trace("Found required config " + rcpmd.getName() + " " + acpmd);
               found = true;
               break;
            }
         }
         if (found == false)
            throw new DeploymentException("Required config property " + rcpmd + " for messagingType '" + messagingType +
               "' not found in activation config " + activationConfig + " ra=" + rarName);
      }

      // Determine the activation spec class
      String className = mlmd.getActivationSpecType();
      if (className == null)
         throw new DeploymentException("No activation spec type for messagingType '" + messagingType + "' ra=" + rarName);
      
      // Load the class
      if (trace)
         log.trace("Loading ActivationSpec class=" + className);
      Class asClass = Thread.currentThread().getContextClassLoader().loadClass(className);
      if (ActivationSpec.class.isAssignableFrom(asClass) == false)
         throw new DeploymentException(asClass.getName() + " is not an activation spec class '" + messagingType + "' ra=" + rarName);
      ActivationSpec result = (ActivationSpec) asClass.newInstance();
      if (trace)
         log.trace("Instantiated ActivationSpec class=" + result);

      /* Apply the properties to the ActivationSpec java bean using the util
      PropertyEditors.mapJavaBeanProperties method.
      */
      Properties beanProps = new Properties();
      for (Iterator i = activationConfig.iterator(); i.hasNext();)
      {
         ActivationConfigPropertyMetaData acpmd = (ActivationConfigPropertyMetaData) i.next();
         String name = acpmd.getName();
         String value = acpmd.getValue();
         beanProps.setProperty(name, value);
      }
      if (trace)
         log.trace("Configuring ActivationSpec properties=" + beanProps);
      try
      {
         PropertyEditors.mapJavaBeanProperties(result, beanProps);
      }
      catch(IntrospectionException e)
      {
         String msg = "Error for ActivationSpec class " + asClass.getName()
            + " as JavaBean";
         DeploymentException.rethrowAsDeploymentException(msg, e);
      }

      // Validate the activation spec
      try
      {
         if (trace)
            log.trace("Trying to validate ActivationSpec " + result);
         result.validate();
      }
      catch (UnsupportedOperationException e)
      {
         log.debug("Validation is not supported for ActivationSpec: " + className);
      }
      
      return result;
   }
   
   // Constructors --------------------------------------------------
   
   // Public --------------------------------------------------------
   
   // Package protected ---------------------------------------------

   // Protected -----------------------------------------------------
   
   // Private -------------------------------------------------------

   // Inner classes -------------------------------------------------

}