/*
 * 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
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */


package org.objectweb.jonas.jms;

import java.util.Properties;
import java.util.Hashtable;
import java.util.Enumeration;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.Set;
import java.util.HashSet;
import javax.jms.Queue;
import javax.jms.Topic;
import javax.management.ObjectName;
import javax.naming.Context;
import javax.naming.NamingException;
import org.objectweb.jonas_jms.api.JmsManager;
import org.objectweb.jonas_jms.JmsManagerImpl;
import org.objectweb.jonas_jms.JmsJmxManagement;
import org.objectweb.jonas.common.Log;
import org.objectweb.jonas.jtm.TransactionService;
import org.objectweb.jonas.jmx.JmxService;
import org.objectweb.jonas.jmx.JonasObjectName;
import org.objectweb.jonas.service.ServiceManager;
import org.objectweb.jonas.service.AbsServiceImpl;
import org.objectweb.jonas.service.ServiceException;
import org.objectweb.util.monolog.api.Logger;
import org.objectweb.util.monolog.api.BasicLevel;

/**
 * JMS Service implementation
 * @author Philippe Coq
 * Contributor(s): 
 */

public class JmsServiceImpl extends AbsServiceImpl implements JmsService, JmsServiceImplMBean {

    static private Logger logger = null;

    // Configuration information used when starting the JMS service
    String momProviderClassName;
    Vector queueNames = new Vector();
    Vector topicNames = new Vector();
    boolean isMomLocal;
    String url;
    TransactionService transactionService = null;
    
    // JMS manager
    JmsManager jonasjms = null;
    JmsJmxManagement jmsjmx = null;

    // -------------------------------------------------------------------
    // Service Implementation
    // -------------------------------------------------------------------

    /**
     * Init the Service.
     * Configuration information is passed thru a Context object.
     */
    public void doInit(Context ctx) throws ServiceException {

	// get logger for this service
	logger = Log.getLogger(Log.JONAS_SERVER_PREFIX);

	// Read the configuration information
	try {
	    momProviderClassName = (String) ctx.lookup("mom");
	} catch (NamingException e) {
	    logger.log(BasicLevel.ERROR, "JMS Service Cannot read configuration "+e);
	    throw new ServiceException("JMS Service Cannot read configuration ", e);
	}

	String ql = "sampleQueue";
	try {
	    ql = (String) ctx.lookup("queues");
	} catch (NamingException e) {
	    // No problem if there is no value --> default value
	}
	if (ql != null) {
	    StringTokenizer st = new StringTokenizer(ql, ",");
	    while (st.hasMoreTokens()) {
		queueNames.add(st.nextToken().trim());
	    }
	}

	String tl = "sampleTopic";
	try {
	    tl = (String) ctx.lookup("topics");
	} catch (NamingException e) {
	    // No problem if there is no value --> default value
	}
	if (tl != null) {
	    StringTokenizer st = new StringTokenizer(tl, ",");
	    while (st.hasMoreTokens()) {
		topicNames.add(st.nextToken().trim());
	    }
	}

	String local = "true";
	try {
	    local = (String) ctx.lookup("collocated");
	} catch (NamingException e) {
	    // No problem if there is no value --> default value
	}
	isMomLocal = local.equalsIgnoreCase("true");

	url = "";
	try {
	    url = (String) ctx.lookup("url");
	} catch (NamingException e) {
	    // No problem if there is no value --> default value
	}

	// Get the transaction service
	try {
	    transactionService =
		(TransactionService) ServiceManager.getInstance().getTransactionService();
	} catch (ServiceException e) {
	    logger.log(BasicLevel.ERROR, "Error when starting the JMS service "+e);
	    throw new ServiceException("Error when starting the JMS service ", e);
	}

	logger.log(BasicLevel.DEBUG, "JMS service initialized");
    }

    /**
     * Start the Service
     * Initialization of the service is already done.
     * For administrating objects we use the class specified in the jms.provider property
     * by default we use the Joram implementation
     */
    public void doStart() throws ServiceException {

	if (isMomLocal) {
	    logger.log(BasicLevel.DEBUG, "Starting JMS Service with collocated MOM");
	} else {
	    logger.log(BasicLevel.DEBUG, "Starting JMS Service with MOM at url "+url);
	}
	
	jonasjms = JmsManagerImpl.getJmsManager();
	jmsjmx = JmsManagerImpl.getJmsJmxManagement();
	
	Class c = null;
	try {
	    ClassLoader loader = JmsManagerImpl.class.getClassLoader();
	    if (loader == null) {
		loader = ClassLoader.getSystemClassLoader();
	    }
	    c = loader.loadClass(momProviderClassName);
	} catch (Exception e) {
	    logger.log(BasicLevel.ERROR, "JMS Service Cannot load admin class "+e);
	    throw new ServiceException("JMS Service Cannot load admin class", e);
	}
	
	// initialization of the JmsManager with implementation class for Administration
	try {
	    jonasjms.init(c, isMomLocal, url, transactionService.getTransactionManager());
	} catch (Exception e) {
	    logger.log(BasicLevel.ERROR, "JMS Service Cannot init the JMS manager "+e);
	    throw new ServiceException("JMS Service Cannot init the JMS manager", e);
	}
	
	// Create Topics and Queues
	try {
	    // Create administered objects for Queues
	    for (int i = 0; i < queueNames.size(); i++) {
		Queue q = jonasjms.createQueue((String) queueNames.elementAt(i));
	    }

	    // Create administered objects for Topics
	    for (int i = 0; i < topicNames.size(); i++) {
		Topic t = jonasjms.createTopic((String) topicNames.elementAt(i));
	    }
	} catch (Exception ex) {
	    logger.log(BasicLevel.ERROR, "JMS Service Cannot create administered object : "+ex.toString());
	    try {
		jonasjms.stop();
		jonasjms = null;
	    } catch (Exception e) {
	    }
	    throw new ServiceException("JMS Service Cannot create administered object", ex);
	}

	try {
	    // Register JmsService MBean : JmxJmsService 
	    ((JmxService)ServiceManager.getJmxService()).getJmxServer().registerMBean(this,JonasObjectName.jmsService());
	} catch (ServiceException se) {
	    // Jmx Service not available, do nothing
	} catch (Exception e) {
	    logger.log(BasicLevel.ERROR, "JmsService: Cannot start the JMS service:\n"+e);
	    throw new ServiceException("JmsService: Cannot start the JMS service",
				       e);
	}

    }

    /**
     * Stop the JMS Service
     */
    public void doStop() throws ServiceException {

	try {
	    jonasjms.stop();
	} catch (Exception e) {
	    logger.log(BasicLevel.ERROR, "JMS Service Cannot stop the JMS manager "+e);
	    throw new ServiceException("JMS Service Cannot stop the JMS manager", e);
	}
	// unregister MBean	
	try {
	    // unregister jms Service MBean
	    ((JmxService)ServiceManager.getJmxService()).getJmxServer().unregisterMBean(JonasObjectName.jmsService());
	} catch (ServiceException se) {
	    // Jmx Service not available, do nothing
	} catch (Exception e) {
	    logger.log(BasicLevel.ERROR, "EJBService: Cannot stop the EJB service:\n"+e);
	    throw new ServiceException("EJBService: Cannot stop the EJB service",e);
	}
	logger.log(BasicLevel.DEBUG, "JMS Service stopped");
    }


    // -------------------------------------------------------------------
    // JMS Service Implementation
    // -------------------------------------------------------------------

    public JmsManager  getJmsManager() {
	return jonasjms;
    }

    /**
     * MBean method
     * @return the current number of Topic Jms Connection Factory
     */ 
    public Integer getCurrentNumberOfJmsTopicConnectionFactory(){
	return new Integer(jmsjmx.getCurrentNumberOfJmsTopicConnectionFactory());

    }

    /**
     * MBean method
     * @return the current number of Queue Jms Connection Factory
     */ 
    public Integer getCurrentNumberOfJmsQueueConnectionFactory(){
		return new Integer(jmsjmx.getCurrentNumberOfJmsQueueConnectionFactory());
    }

    /**
     * MBean method
     * @return the current number of Topic Jms Destination
     */ 
    public Integer getCurrentNumberOfJmsTopicDestination(){
	return new Integer(jmsjmx.getCurrentNumberOfJmsTopicDestination());
    }

    /**
     * MBean method
     * @return the current number of Queue Jms Destination
     */ 
    public Integer getCurrentNumberOfJmsQueueDestination(){
	return new Integer(jmsjmx.getCurrentNumberOfJmsQueueDestination());
    }

    /**
     * MBean method
     * Create a new Jms queue destination
     * @param String jndi Name
     * not yet implement with a remote host
     */
    public void createJmsQueueDestination(String jndiName){
	try {
	    jonasjms.createQueue(jndiName);
	    // MBean registering
	} catch (Exception e) {
	    logger.log(BasicLevel.ERROR, "JmxJmsService: Exception when create destination"+e);
	}
    } 

    /**
     * MBean method
     * Create a new Jms topic destination
     * @param String jndi Name
     * not yet implement with a remote host
     */
    public void createJmsTopicDestination(String jndiName){
	try {
	    jonasjms.createTopic(jndiName);
	    // MBean registering
	} catch (Exception e) {
	    logger.log(BasicLevel.ERROR, "JmxJmsService: Exception when create destination"+e);
	}   
    } 

    /**
     * MBean method
     * Remove a Jms destination
     * @param String jndi name
     */
    public void removeJmsDestination(String jndiName){
	try{
	    jmsjmx.removeJmsDestination(jndiName);
	} catch (Exception e){
	    // remove problem
	    logger.log(BasicLevel.ERROR, "JmxJmsService: Exception when remove destination"+e);
	}
    }

    /**
     * MBean method
     * return Set of Queue Destinations Names
     */
    public Set getAllJmsQueueDestinationNames() {
	HashSet result = new HashSet();
	for (Enumeration enu = jonasjms.getQueuesNames() ; enu.hasMoreElements() ;) {
	    result.add(enu.nextElement());
	}
	return result;
    }

    /**
     * MBean method
     * return Set of Topic Destination Names
     */
    public Set getAllJmsTopicDestinationNames(){
	HashSet result = new HashSet();
	for (Enumeration enu = jonasjms.getTopicsNames() ; enu.hasMoreElements() ;) {
	    result.add(enu.nextElement());
	}
	return result;
    }

    /**
     * MBean method
     * return Set of Queue Connection Factory Names
     */
    public Set getAllJmsQueueConnectionFactoryNames() {
	HashSet result = new HashSet();
	return result;
    }

    /**
     * MBean method
     * return Set of Topic Connection Factory Names
     */
    public Set getAllJmsTopicConnectionFactoryNames() {
	HashSet result = new HashSet();
	return result;	
    }

    /**
     * MBean method
     * @return String name of default Queue Connection factory
     */
    public String getDefaultQueueConnectionFactoryName() {
	return jmsjmx.getDefaultQueueConnectionFactoryName(); 
    }

    /**
     * MBean method
     * @return String name of default Topic Connection factory
     */
    public String getDefaultTopicConnectionFactoryName() {
	return jmsjmx.getDefaultTopicConnectionFactoryName(); 
    }


}
