/********************************************************************
 * Copyright © 2004 VHA. All rights reserved
 ********************************************************************/

// Package
package gov.va.med.fw.service.jms;

// Java classes
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.jndi.JndiTemplate;

import gov.va.med.fw.service.AbstractComponent;
import gov.va.med.fw.service.ServiceException;

// Framework

/** Encapsulates JMS-related information neccessary to send and receive JMS messages.
 * 
 * @author Vu Le
 * @version 1.0
 */
public class AbstractMessageDescriptor extends AbstractComponent implements InitializingBean {
  public static final String URL_PROTOCOL_HEADER = "t3://";

   private String contextName = null;

   private String factoryName = null;

   /** Internal cache of Spring JndiTemplate objects that is lazily built */
   private Map providerURLtoJndiTemplate = new HashMap();
   
   /**
    * Contains the providerURL that should be published to, in order of priority.  Once
    * one is able to be connected to, the others will not be used (actually depends on usage
    * by JMS producers).
    */
   private List providerURLs;        

   /** Creates a new instance of JMSService */
   public AbstractMessageDescriptor() {
      super();
   }

   /**
    * Checks if a service broker is set correctly
    * @throws Exception Thrown if a service broker is not set
    */
   public void afterPropertiesSet() throws Exception {
      if (factoryName == null ||           
          contextName == null || 
          providerURLs == null || providerURLs.isEmpty()) {
         throw new ServiceException(
               "Missing properties: factoryName, providerURLs or contextName");
      }
   }

   public void setContextName(String name) {
      contextName = name;
   }

   public String getContextName() {
      return contextName;
   }

   public void setFactoryName(String name) {
      this.factoryName = name;
   }

   public String getFactoryName() {
      return factoryName;
   }
   
   /** Does not perform synchronization due to the overhead of serialization behind
    * this descriptor's object monitor.  Acceptable cost of re-creating a JndiTemplate.
    * 
    * @param providerURL
    * @return
    */
   protected JndiTemplate getInitialContext(String providerURL) {
	   JndiTemplate jndi = (JndiTemplate) providerURLtoJndiTemplate.get(providerURL);
      if (jndi == null) {
         Properties data = new Properties();
         data.put(Context.INITIAL_CONTEXT_FACTORY, getContextName());
         data.put(Context.PROVIDER_URL, providerURL);
         jndi = new JndiTemplate( data );
         providerURLtoJndiTemplate.put(providerURL, jndi);
      }
      return jndi;
   }

  /**
   * 
   * @param name
   * @param factoryType
   * @return
   * @throws ServiceException
   */
   protected ConnectionFactory getConnectionFactory(String providerURL, String name, java.lang.Class factoryType) throws ServiceException {
       ConnectionFactory factory = null;
      try {
         factory = (ConnectionFactory)PortableRemoteObject.narrow( getInitialContext(providerURL).lookup(name), factoryType );
      }
      catch (ClassCastException e) {
         throw new ServiceException("Invalid connection factory returned", e);
      }
      catch (NamingException e) {
         throw new ServiceException("Invalid factory name", e);
      }
      return factory;
   }
   
/**
 * 
 * @param name
 * @param objType
 * @return
 * @throws ServiceException
 */  

   protected Destination getDestination(String providerURL, String name, java.lang.Class destinationType) throws ServiceException {
       Destination destination = null;
      try {
          destination = (Destination)PortableRemoteObject.narrow( getInitialContext(providerURL).lookup(name), destinationType );
      }
      catch (ClassCastException e) {
         throw new ServiceException("Invalid destination returned", e);
      }
      catch (NamingException e) {
         throw new ServiceException("Invalid destination name", e);
      }
      return destination;
   }

	public List getProviderURLs() {
		return providerURLs;
	}

	public void setProviderURLs(List providerURLs) {
		this.providerURLs = providerURLs;
	}   
	
	public String getPrimaryProviderURL() {
		return (String) providerURLs.get(0);
	}
	
  }