/*
 * The contents of this file are subject to the JOnAS Public License Version
 * 1.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License on the JOnAS web site.
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied.
 * See the License for the specific terms governing rights and limitations under
 * the License.
 *
 * The Original Code is JOnAS application server code released July 1999.
 *
 * The Initial Developer of the Original Code is Bull S.A.
 * The Original Code and portions created by Bull S.A. are
 *    Copyright (C) 1999 Bull S.A. All Rights Reserved.
 *
 * Contributor(s): Xavier Spengler
 *
 * --------------------------------------------------------------------------
 * $Id: Adm.java,v 1.18 2001/05/21 14:32:04 jonas Exp $
 * --------------------------------------------------------------------------
 */


package org.objectweb.jonas.adm;

import java.rmi.RemoteException;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Vector;
import javax.naming.InitialContext;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.NameClassPair;
import org.enhydra.naming.ContainerNaming;
import org.objectweb.common.RemoteObject;
import org.objectweb.jonas.common.JProp;
import org.objectweb.jonas.common.Trace;
import org.objectweb.jonas.container.EJBService;
import org.objectweb.jonas.container.EJBServiceImpl;
import org.objectweb.jonas.dbm.DataBaseService;
import org.objectweb.jonas.dbm.DataBaseServiceImpl;
import org.objectweb.jonas.naming.NamingManager;
import org.objectweb.jonas.naming.CompNamingContext;
import org.objectweb.jonas.jms.JmsService;
import org.objectweb.jonas.jms.JmsServiceImpl;
import org.objectweb.jonas.jtm.TransactionService;
import org.objectweb.jonas.jtm.TransactionServiceImpl;
import org.objectweb.jonas_ejb.container.JContainer;

/**
 * This class implements a remote interface used for administering
 *      the server.
 */
public class Adm extends RemoteObject implements AdmInterface {

    static final int trace = Trace.DB_18;

    public static final String ADMNAME_SUFFIX = "_Adm";

    private EJBService ejbserv  = null;
    private DataBaseService dbm  = null;
    private TransactionService tm = null;
    private JmsService jms = null;
    private JProp jonasProperties = null;
    private InitialContext ictx = null;
    private boolean isTM = false;

    /**
     * Adm constructor
     */
    public Adm(JProp jp, boolean isTM) throws RemoteException, NamingException  {

	Trace.outln(trace, "Adm.Adm() ");

	jonasProperties = jp;
	this.isTM = isTM;

	// Get Service references
	if (isTM == false) {
	    ejbserv = EJBServiceImpl.getInstance();
	    dbm = DataBaseServiceImpl.getInstance();
	    jms = JmsServiceImpl.getInstance();
	}
	tm = TransactionServiceImpl.getInstance();

	// Get an Initial Context and
	// registers the JOnAS Server Name to JNDI
	String name = null;
	if (isTM) {
	    name = "TMServer" + ADMNAME_SUFFIX;
	} else {
	    name = jonasProperties.getValue("jonas.name", "jonas") + ADMNAME_SUFFIX;
	}
	try {
	    ictx = new InitialContext();
	    ictx.rebind(name, this);
	    Trace.outln(trace, "rebind done " + name);
	} catch (NamingException e) {
	    Trace.errln("Cannot register "+name+" : " + e);
	    throw e;
	}
    }

    // ------------------------------------------------------------------
    //  AdmInterface implementation
    // ------------------------------------------------------------------

    /**
     * configure trace messages in EJB Server
     */
    public void setTraceLevel(String level) throws RemoteException {
	Trace.outln(trace, "Adm.setTraceLevel");
	Trace.setFilters(level);
    }

    /**
     * configure trace output device
     */
    public void setTraceOutput(String out) throws RemoteException {
	Trace.outln(trace, "Adm.setTraceOutput");
	Trace.setOutput(out);
    }

    /**
     * configure trace header
     */
    public void setTraceHeader(boolean h) throws RemoteException {
	Trace.outln(trace, "Adm.setTraceHeader");
	Trace.setHeader(h);
    }

    /**
     * Create a container and load beans in it
     *
     * @parameter fileName name of the ejb-jar or xml file with the beans to load
     */
    public void addBeans(String fileName) throws RemoteException {

	if (isTM) return;

	Trace.outln(trace, "Adm.addBeans");
	try {
	    Context ctx = new CompNamingContext(fileName);
	    ctx.rebind("filename", fileName);
	    ejbserv.createContainer(ctx);
	} catch(Exception ex) {
	    throw new RemoteException("cannot create a new JOnAS container");
	}
    }

    /**
     * Remove the container identified by fileName and remove all beans in it
     *
     * @parameter fileName name of the ejb-jar or xml file with the beans to load
     */
    public void removeBeans(String fileName) throws RemoteException {

	if (isTM) return;
	Trace.outln(trace, "Adm.removeBeans ", fileName);
	try {
	    JContainer cont = ejbserv.getContainer(fileName);
	    if (cont == null) {
		throw new RemoteException("Container "+fileName+" unknown");
	    }
	    ejbserv.removeContainer(cont);
	} catch(Exception e) {
	    Trace.errln("removeBeans raised exception:\n"+e);
	    throw new RemoteException("cannot remove JOnAS container");
	}
    }

    /**
     * List beans of all JOnAS containers
     */
    public String [] listBeans() throws RemoteException {

	if (isTM) return new String[0];

	Trace.outln(trace, "Adm.listBeans");
	JContainer[] lcont = ejbserv.listContainers();
	Vector lbeans = new Vector();
	for( int j = 0; j<lcont.length; j++) {
	    String[] lbn = lcont[j].listBeanNames();
	    String contname = lcont[j].getName();
	    for( int k = 0; k<lbn.length; k++){
		String s = new String(contname + ": " + lbn[k]);
		lbeans.addElement(s);
	    }
	}
	String[] ret = new String[lbeans.size()];
	lbeans.copyInto(ret);

	return ret;
    }

    /**
     * List JNDI context
     */
    public Vector listContext() throws RemoteException {
	Trace.outln(trace, "Adm.listContext()");
	String name = null;
	Vector ret  = new Vector();
	try {
	    NamingEnumeration ne = ictx.list("");
	    for (Enumeration e = ne; e.hasMoreElements(); ) {
		name = ((NameClassPair) e.nextElement()).getName();
		Trace.outln(trace, "    name found in context = "+ name);
		ret.addElement(name);
	    }
	} catch (Exception ex) {
	    throw new RemoteException("Cannot list JNDI context", ex);
	}
	return ret;
    }

    /**
     * List Environment
     */
    public Properties listEnv() {
	Trace.outln(trace, "Adm.listEnv() ");
	return jonasProperties.getFilesEnv();
    }

    /**
     * Stop the EJB Server
     */
    public void stopServer() throws RemoteException {

	Trace.outln(trace, "Adm.stopServer() ");

	if (isTM == false) {
	    try {
		ejbserv.stop();
	    } catch (Exception e) {
		Trace.errln("Cannot remove containers" + e);
		throw new RemoteException("Cannot remove containers", e);
	    }
	    try {
		dbm.unbindDataSources();
	    } catch (Exception e) {
		Trace.errln("Cannot unbind datasources" + e);
		throw new RemoteException("Cannot unbind datasources ", e);
	    }
	    try {
		jms.stop();
	    } catch (Exception e) {
	    }

	}
    }

    /**
     * Stop and Kill the EJB Server
     */

    public void killServer() throws RemoteException {

	Trace.outln(trace, "Adm.killServer() ");

    stopServer();
	System.exit(0);
    }

    /**
     * To test if an Adm is reachable
     */
    public boolean ping() throws RemoteException {
	if (isTM) {
	    Trace.outln(trace, "Adm.ping on TMServer");
	} else {
	    Trace.outln(trace, "Adm.ping on EJBServer");
	}
	return isTM;
    }

    /**
     * set the default value for transaction timeout
     */
    public void setTransactionTimeout(int timeout) throws RemoteException {
	Trace.outln(trace, "Adm.setTransactionTimeout");
	tm.setTimeout(timeout);
    }

    /**
     * run the garbage collector
     */
    public void runGC() throws RemoteException {
	Trace.outln(trace, "Adm.runGC");
	Runtime.getRuntime().gc();
    }

    /**
     * sync all entity instances outside transactions
     */
    public void syncAllEntities() throws RemoteException {
	if (isTM) return;
	Trace.outln(trace, "Adm.syncAllEntities");
	ejbserv.syncAllEntities();
    }
}
