/*
 * 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 fr.dyade.aaa.agent.AgentServer;
import javax.jms.Queue;
import javax.jms.QueueConnectionFactory;
import javax.jms.XAQueueConnectionFactory;
import javax.jms.Topic;
import javax.jms.TopicConnectionFactory;
import javax.jms.XATopicConnectionFactory;
import javax.naming.InitialContext; 
import javax.naming.NamingException;
import java.util.Vector;
import java.util.Enumeration;
import org.objectweb.jonas_jms.api.JmsAdministration;

/**
 * Joram Administration. This Joram specific class implements
 * the JMS independant interface JmsAdministration.
 * @author Philippe Coq
 * Contributor(s): 
 *  Philippe Durieux
 *  Jeff Mesnil: for JORAM 3.x integration
 */
public class JmsAdminForJoram implements JmsAdministration {

    private boolean collocatedmom = false;
    private InitialContext ictx = null;
    private Vector namelist = new Vector();
    private fr.dyade.aaa.joram.XATopicConnectionFactory xatcf = null;
    private fr.dyade.aaa.joram.XAQueueConnectionFactory xaqcf = null;
    private fr.dyade.aaa.joram.TopicConnectionFactory jtcf = null;
    private fr.dyade.aaa.joram.QueueConnectionFactory jqcf = null;
    private fr.dyade.aaa.joram.admin.Admin admin = null;
    private fr.dyade.aaa.joram.admin.User user = null;
    private fr.dyade.aaa.joram.admin.User jonasUser = null;
    private String a3url = null;

    /**
     * default constructor.
     * This class will be created with newInstance().
     */
    public JmsAdminForJoram() {
    }

    // ------------------------------------------------------------
    // private methods
    // ------------------------------------------------------------

    /**
     * start the MOM in the same JVM than the current
     *
     * Start the A3 AgentServer with the default configuration
     * in transient mode and with the a3servers.xml file located into $JONAS_ROOT/config
     * what it is made here is equivalent to
     *  java -Dinstall.root=$JONAS_ROOT -DTransaction=fr.dyade.aaa.util.NullTransaction
     *       -Dfr.dyade.aaa.agent.A3CONF_DIR=$JONAS_ROOT/config
     *           fr.dyade.aaa.agent.AgentServer 0 ./s0&
     */
    private void startMOM() throws Exception {
	TraceJms.debug("JmsAdminForJoram startMOM");

	try {
	    // -DTransaction=fr.dyade.aaa.util.NullTransaction
	    String TRANSACTION_PROP = "Transaction";
	    String s1 = System.getProperty(TRANSACTION_PROP);
	    if (s1 == null) {
		System.setProperty(TRANSACTION_PROP, "fr.dyade.aaa.util.NullTransaction");
	    }

	    // -Dfr.dyade.aaa.agent.A3CONF_DIR=$JONAS_ROOT/config
	    String A3CONF_DIR_PROP = "fr.dyade.aaa.agent.A3CONF_DIR";
	    String a3config_dir = System.getProperty(A3CONF_DIR_PROP);
	    if (a3config_dir == null) {
		System.setProperty(A3CONF_DIR_PROP, System.getProperty("install.root")
				   + System.getProperty("file.separator") + "config");
	    }

	    TraceJms.debug("JmsAdminForJoram startMOM a3config_dir="+a3config_dir);
	    // java fr.dyade.aaa.agent.AgentServer 0 s0
	    // 0 identifies wich server to run among those described in config file.
	    // s0 is a directory used for persistence.
	    String []args = new String[2];
	    args[0] = "0";
	    args[1] = "s0";
	    AgentServer.init(args);
	    AgentServer.start();

	    // wait 10 millisec for the MOM to start ???
	    Thread.sleep(10);
	    
	    // Get url that must be used to start Admin
	    // mainly to get the port number set in a3servers.xml
	    short sid = AgentServer.getServerId();	// should be 0
	    String host = AgentServer.getHostname(sid);	// should be localhost
	    int port = 16010;
	    try {
		port = Integer.parseInt(AgentServer.getServiceArgs(sid, "fr.dyade.aaa.mom.proxies.ConnectionFactory"));
	    } catch (NumberFormatException exc) {
	    } catch (Exception e) {
		TraceJms.error("MOM Exception:"+e);
		throw e;
	    }
	    a3url = new String("joram://" + host + ":" + port);
	    TraceJms.verbose("Starting MOM on url "+a3url);

	} catch (Exception ex) {
	    TraceJms.error("JmsAdminForJoram startMOM : "+ex);
	    throw ex;
	}
    }
    
    // ------------------------------------------------------------
    // JmsAdministration implementation
    // ------------------------------------------------------------

    /**
     * Jms Administrator is created with newInstance().
     * initialization is done later with this method.
     * The MOM will be started if collocated.
     * This method should create an XATopicConnectionFactory and
     * an XAQueueConnectionFactory
     * @param boolean true for if the MOM in run in the current JVM
     * @param String url connexion that must be used if not collocated
     */
    public void start(boolean collocated, String url) throws Exception {

	// Start the MOM in this JVM if collocated.
	if (collocated) {
	    collocatedmom = true;
	    startMOM();
	}

	// Create an InitialContext
	ictx = new InitialContext();

	if (admin == null) {
	    if (a3url != null) {
		// collocated: use url got from the MOM
		TraceJms.verbose("Starting JmsAdmin with url "+a3url);
		admin = new fr.dyade.aaa.joram.admin.Admin(a3url, "root", "root", 100);
	    } else if (url != null && url.length() > 0) {
		// not collocated: use url from jonas.properties
		TraceJms.verbose("Starting JmsAdmin with url "+url);
		admin = new fr.dyade.aaa.joram.admin.Admin(url, "root", "root", 100);
	    } else {
		// use default url
		TraceJms.verbose("Starting JmsAdmin with default url");
		admin = new fr.dyade.aaa.joram.admin.Admin("root", "root", 100);
	    }
	}

	try {
	    user = admin.getUser("anonymous");
	} catch (fr.dyade.aaa.joram.admin.AdminException e) {
	    user = admin.createUser("anonymous", "anonymous");
	}

	try {
	    jonasUser = admin.getUser("jonas");
	} catch (fr.dyade.aaa.joram.admin.AdminException e) {
	    jonasUser = admin.createUser("jonas", "jonas");
	}

	// Create Agent Clients that will be used by the EJB components.
	xatcf = admin.createXATopicConnectionFactory();
	if (xatcf == null) {
	    TraceJms.error("JmsAdminForJoram cannot create xatcf");
	}
	xaqcf = admin.createXAQueueConnectionFactory();
	if (xaqcf == null) {
	    TraceJms.error("JmsAdminForJoram cannot create xaqcf");
	}

	// Create Agent Clients that will be used by a pure JMS Client
	String name = "JQCF";
	try {
	    jqcf = admin.createQueueConnectionFactory();
	    ictx.rebind(name, jqcf);
	    namelist.addElement(name);
	} catch (NamingException e) {
	    TraceJms.error("JmsAdminForJoram cannot register "+name);
	}

	name = "JTCF";
	try {
	    jtcf = admin.createTopicConnectionFactory();
	    ictx.rebind(name, jtcf);
	    namelist.addElement(name);
	} catch (NamingException e) {
	    TraceJms.error("JmsAdminForJoram cannot register "+name);
	}
    }

    /**
     * Stop the Jms Administrator
     */
    public void stop() {
	if (admin != null) {
	    try {
		admin.close(); 
	    } catch  (Exception ex) {
		TraceJms.error("JmsAdminForJoram : problem for closing Admin object "+ex);
	    }
	    Enumeration ln = namelist.elements();
	    while (ln.hasMoreElements()) {
		String name = (String)ln.nextElement();
		try {		    
		    ictx.unbind(name);
		    TraceJms.debug("JmsAdminForJoram : unbind "+name);
		} catch(Exception ex) {
		    TraceJms.error("JmsAdminForJoram : cannot unbind "+name);
		}
	    }
	}
	if (collocatedmom) {
	    AgentServer.stop();
	    TraceJms.debug("JmsAdminForJoram : AgentServer stopped");
	}
    }

    /**
     * Get the XATopicConnectionFactory
     */
    public XATopicConnectionFactory getXATopicConnectionFactory() {
	return xatcf;
    }

    /**
     * Get the XAQueueConnectionFactory
     */
    public XAQueueConnectionFactory getXAQueueConnectionFactory() {
	return xaqcf;
    }

    /**
     * Create a Queue and bind it to the registry
     */
    public Queue createQueue(String name) throws Exception {
	TraceJms.debug("JmsAdminForJoram createQueue ");
	Queue queue = admin.createQueue(name);
	admin.setWriter(user, name);
	admin.setReader(user, name);
	admin.setWriter(jonasUser, name);
	admin.setReader(jonasUser, name);
	return queue;
    }

    /**
     * Create a Topic and bind it to the registry
     */
    public Topic createTopic(String name) throws Exception {
	TraceJms.debug("JmsAdminForJoram createTopic ");
	Topic topic = admin.createTopic(name);
	admin.setWriter(user, name);
	admin.setReader(user, name);
	admin.setWriter(jonasUser, name);
	admin.setReader(jonasUser, name);
	return topic;
    }
}
