/*
 * 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
 *
 * Initial developer(s): ____________________________________.
 * Contributor(s): 
 * JOnAS 2.4 Murad Meghani (Murad.Meghani@compuware.com) killServer and stopServer
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.objectweb.jonas.adm;

import java.io.BufferedReader; 
import java.io.InputStreamReader; 
import java.io.IOException;
import javax.naming.InitialContext;
import java.util.Properties;
import java.util.Vector;
import java.util.Enumeration;
import java.rmi.RemoteException;


/*
 * This class implements a rmi client to administrate the server.
 * JonasAdmin may be run either in interactive mode or command mode.
 */
public class JonasAdmin {
    static String SERVERNAME = "JOnAS server ";
    static String jonasName = null;
    static AdmInterface admI = null;
    static boolean reachable = false;
    static boolean isNotEJB = false;
    static boolean isError = false;

    static private void checkAdm() {

	// Gets reference on Adm object
	String admName = jonasName + Adm.ADMNAME_SUFFIX;
	try {
	    // are we using David ?
	    String host = System.getProperty("david.CosNaming.default_host");
	    InitialContext initialContext;

	    if (host == null) {
		// no, use jndi.properties
		initialContext = new InitialContext();
	    } else {
		// yes, build the initialcontext properties using CosNaming parameters
		// jndi.properties is not required nor used (it'safer this way, since
		// the information if given only one time)
		Properties properties = new Properties();
		properties.put("java.naming.factory.initial", "com.sun.jndi.cosnaming.CNCtxFactory");
		String port = System.getProperty("david.CosNaming.default_port");
		if (port == "")
		    port = "14727"; //default david port
		properties.put("java.naming.provider.url", "iiop://" + host + ":" + port);
		initialContext = new InitialContext(properties);
	    }
	    
	    admI = (AdmInterface) initialContext.lookup(admName);
	    isNotEJB = admI.ping();
	    reachable = true;
	} catch (Exception e) {
	    reachable = false;
	}
    }

    /*
     * Create a new JOnAS container for Beans relative to the file FileName
     *
     * @parameter fileName name of the .xml file or .jar file
     *
     */	     
    static private void addBeans(String fileName) {
	if (isNotEJB) {
	    System.err.println("no beans on TMServer");
	    isError = true;
	    return;
	}
	if (!reachable) {
	    System.err.println(SERVERNAME +jonasName+" unreachable");
	    isError = true;
	    return;
	}
	try {
	    admI.addBeans(fileName);
	} catch (RemoteException e) {
	    System.err.println("admI.addBeans: "+e);
	    isError = true;
	    return;
	}
    }

    static private void removeBeans(String fileName) {
	if (isNotEJB) {
	    System.err.println("no beans on TMServer");
	    isError = true;
	    return;
	}
	if (!reachable) {
	    System.err.println(SERVERNAME +jonasName+" unreachable");
	    isError = true;
	    return;
	}
	try {
	    admI.removeBeans(fileName);
	} catch (RemoteException e) {
	    System.err.println("admI.removeBeans: "+e);
	    isError = true;
	    return;
	}
    }

    static private void listbeans() {
	if (isNotEJB) {
	    System.err.println("no beans on TMServer");
	    isError = true;
	    return;
	}
	if (!reachable) {
	    System.err.println(SERVERNAME +jonasName+" unreachable");
	    isError = true;
	    return;
	}
	try {
	    String[] result = admI.listBeans();
	    if (result.length == 0)
		System.out.println("No bean in "+jonasName);
	    for (int i = 0; i < result.length; i++) {
		System.out.println(result[i]);
	    } 
	} catch (RemoteException e) {
	    System.err.println ("admI.listBeans() : "+e);
	    isError = true;
	    return;
	}
    }

    static private void listnames() {
	if (!reachable) {
	    System.err.println(SERVERNAME +jonasName+" unreachable");
	    isError = true;
	    return;
	}
	Vector result = new Vector();
	try {
	    result = admI.listContext();
	} catch (RemoteException ex) {
	    System.err.println ("admI.listBeans() : "+ex);
	    isError = true;
	    return;
	}
	    
	if (result.size() == 0)
	    System.out.println("No name in JNDI context.");
	for (int i = 0; i < result.size(); i++) {
	    System.out.println(result.elementAt(i));
	}
    }

    static private void listproperties() {
	if (!reachable) {
	    System.err.println(SERVERNAME +jonasName+" unreachable");
	    isError = true;
	    return;
	}
	Properties p = new Properties();
	try {
	    p = admI.listEnv();
	} catch (RemoteException ex) {
	    System.err.println ("admI.listBeans() : "+ex);
	    isError = true;
	    return;
	} 
	for (Enumeration e = p.keys(); e.hasMoreElements();) {
	    Object key   = e.nextElement();
	    Object value = p.get(key);
	    System.out.println(key.toString() + "=" + value.toString());
	}
    }

    static private void sync() {
	if (isNotEJB) {
	    System.err.println("no beans on TMServer");
	    isError = true;
	    return;
	}
	if (!reachable) {
	    System.err.println(SERVERNAME +jonasName+" unreachable");
	    isError = true;
	    return;
	}
	try {
	    admI.syncAllEntities();
	} catch (RemoteException e) {
	    System.err.println ("admI.syncAllEntities : "+e);
	    isError = true;
	    return;
	}
    }

    static private void runGC() {
	if (!reachable) {
	    System.err.println(SERVERNAME +jonasName+" unreachable");
	    isError = true;
	    return;
	}
	try {
	    admI.runGC();
	} catch (RemoteException e) {
	    System.err.println ("admI.runGC : "+e);
	    isError = true;
	    return;
	}
    }

    static private void setTTimeout(String tstr) {
	if (!reachable) {
	    System.err.println(SERVERNAME +jonasName+" unreachable");
	    isError = true;
	    return;
	}
	Integer i = new Integer(tstr);
	try {
	    admI.setTransactionTimeout(i.intValue());
	} catch (RemoteException e) {
	    System.err.println ("admI.setTransactionTimeout : "+e);
	    isError = true;
	    return;
	}
    }

    static private void listTopics() {
	if (!reachable) {
	    System.err.println(SERVERNAME +jonasName+" unreachable");
	    isError = true;
	    return;
	}
	try {
	    String [] result = admI.getTopics();
	    if (result.length == 0)
		System.out.println("No topics in "+jonasName);
	    for (int i = 0; i < result.length; i++) {
		String level = admI.getTopicLevel(result[i]);
		System.out.println(level+"\t"+result[i]);
	    } 
	} catch (RemoteException e) {
	    System.err.println ("admI.getTopics : "+e);
	    isError = true;
	    return;
	}
    }

    static private void setTopic(String t, String l) {
	try {
	    admI.setTopicLevel(t, l);
	} catch (RemoteException e) {
	    System.err.println ("admI.setTopics : "+e);
	    isError = true;
	    return;
	}
    }

    static private void stopserver() {
	if (!reachable) {
	    System.err.println(SERVERNAME +jonasName+" unreachable");
	    isError = true;
	    return;
	}
	try {
	    admI.killServer();
	} catch (RemoteException e) {
	    // go here usually: java.io.EOFException
	} 
	System.out.println(SERVERNAME +jonasName+ " stopped");
	reachable = false;	
    }

    static private void help() {
	System.out.println("addbeans    adds beans in a new JOnAS container");
	System.out.println("env         JOnAS properties used by the server");
	System.out.println("gc          run the garbage collector");
	System.out.println("help        help");
	System.out.println("jndinames   lists registered JNDI names");
	System.out.println("listbeans   lists beans");
	System.out.println("name        to identify a current JOnAS server");
	System.out.println("quit        quit JonasAdmin");
	System.out.println("removebeans remove beans in a new JOnAS container");
	System.out.println("stop        stop current JOnAS");
	System.out.println("sync        synchronize all entities");
	System.out.println("trace       get/set monolog topics");
	System.out.println("ttimeout    set default transaction timeout");
    }

    static void usage() {
	System.out.println("usage : JonasAdmin <options>");
	System.out.println("if no option(except -n), mode is interactive.");
	System.out.println("list of available options:");
	System.out.println("    -n JonasName : to identify an JOnAS Server");
	System.out.println("    -s : stops the EJB server.");
	System.out.println("    -l : lists beans currently in the JOnAS Server.");
	System.out.println("    -j : lists registered JNDI names.");
	System.out.println("    -e : lists JOnAS properties currently used by the JOnAS Server.");
	System.out.println("    -a fileName : dynamically adds beans from fileName in a new container");
	System.out.println("    -r fileName : dynamically remove beans from container fileName");
	System.out.println("    -sync: synchronize all entities");
	System.out.println("    -gc: run the garbage collector");
	System.out.println("    -tt timeout: set default transaction timeout");
	System.out.println("    -t list monolog topics");
	System.out.println("    -debug topic : set DEBUG for a monolog topic");
	System.out.println("    -h : help message.");
	System.out.println("    -? : help message.");
    }

    /*
     * interactive mode
     */
    static public void menu() throws IOException {
	// First name the jonas server
	if (!reachable) {
	    System.out.println("You must first choose a jonas server. (command `name`)");
	    System.out.println("Type `help` to get the list of available commands");
	}

	// User interface
	BufferedReader inbuf = new BufferedReader(new InputStreamReader(System.in));
	while (true) {
	    System.out.print("JonasAdmin ("+jonasName+") > ");
	    String command = inbuf.readLine();
	    if (command.length() == 0)
		continue;
	    if ("addbeans".startsWith(command)) {
		String bFName = null;
		System.out.print("file name ? > ");
		if ((bFName = inbuf.readLine()).length() != 0) { 
		    addBeans(bFName);
		}
		continue;
	    }
	    if ("env".startsWith(command)) {
		listproperties();
		continue;
	    }
	    if ("gc".startsWith(command)) {
		runGC();
		continue;
	    }
	    if ("help".startsWith(command) || command.equals("?")) {
		help();
		continue;
	    }
	    if ("jndinames".startsWith(command)) {
		listnames();
		continue;
	    }
	    if ("listbeans".startsWith(command)) {
		listbeans();
		continue;
	    }
	    if ("name".startsWith(command)) {
		System.out.print("Enter the "+SERVERNAME+"'s name (jonas.name property) : ");
		jonasName = new String(inbuf.readLine());
		checkAdm();
		continue;
	    }
	    if ("quit".startsWith(command)) {
		return;
	    }
	    if ("removebeans".startsWith(command)) {
		String cFName = null;
		System.out.print("file name ? > ");
		if ((cFName = inbuf.readLine()).length() != 0) { 
		    removeBeans(cFName);
		}
		continue;
	    }
	    if ("trace".startsWith(command)) {
		while (true) {
		    listTopics();
		    System.out.print("topic name ? > ");
		    String tname = inbuf.readLine().trim();
		    if (tname.length() == 0) {
			break;
		    }
		    System.out.print("topic level ? (DEBUG | WARN | INFO | ERROR | UNSET) > ");
		    String levstr = inbuf.readLine().trim();
		    setTopic(tname, levstr);
		}
		continue;
	    }
	    if ("stop".startsWith(command)) {
		stopserver();
		continue;
	    }
	    if ("sync".startsWith(command)) {
		sync();
		continue;
	    }
	    if ("ttimeout".startsWith(command)) {
		String tstr = null;
		System.out.print("transaction timeout in seconds ? > ");
		if ((tstr = inbuf.readLine()).length() != 0) { 
		    setTTimeout(tstr);
		}
		continue;
	    }
	    System.out.println("Unknown command. Type help to get for the list of commands.");
	}
    } 

    public static void main(String args[]) throws IOException { 

	String beansFileName = null;
	String timeout = null;
	String toutput = null;
	String topic = null;
	boolean header = false;

	boolean lOption = false;
	boolean jOption = false;
	boolean eOption = false;
	boolean aOption = false;
	boolean tOption = false;
	boolean hOption = false;
	boolean sOption = false;
	boolean rOption = false;
	boolean syncOpt = false;
	boolean debugOption = false;
	boolean ttOpt = false;
	boolean logOpt = false;
	boolean gcOpt = false;

	boolean interactive = true;
	boolean namedServer = false;

	// Get command args
	for (int argn = 0; argn < args.length; argn++) {
	    String arg = args[argn];
	    
	    if (arg.equals("-a")) {
		beansFileName = args[++argn];
		aOption = true;
		interactive = false;
		continue;
	    }
	    if (arg.equals("-e")) {
		eOption = true;
		interactive = false;
		continue;
	    }
	    if (arg.equals("-h") || arg.equals("-?")) {
		hOption = true;
		usage();
		System.exit(0);
	    }
	    if (arg.equals("-gc")) {
		gcOpt = true;
		interactive = false;
		continue;
	    }
	    if (arg.equals("-j")) {
		jOption = true;
		interactive = false;
		continue;
	    }
	    if (arg.equals("-l")) {
		lOption = true;
		interactive = false;
		continue;
	    }
	    if (arg.equals("-n")) {
		jonasName = args[++argn];
		namedServer = true;
		checkAdm();
		continue;
	    }
	    if (arg.equals("-r")) {
		beansFileName = args[++argn];
		rOption = true;
		interactive = false;
		continue;
	    }
	    if (arg.equals("-s")) {
		sOption = true;
		interactive = false;
		continue;
	    }
	    if (arg.equals("-sync")) {
		syncOpt = true;
		interactive = false;
		continue;
	    }
	    if (arg.equals("-debug")) {
		topic = args[++argn];
		debugOption = true;
		interactive = false;
		continue;
	    }
	    if (arg.equals("-t")) {
		tOption = true;
		interactive = false;
		continue;
	    }
	    if (arg.equals("-tt")) {
		timeout = args[++argn];
		ttOpt = true;
		interactive = false;
		continue;
	    }
	    System.out.println("Bad option: "+arg);
	    usage();
	    System.exit(2);
	}

	if (!namedServer) {
	    jonasName = "jonas"; // default value
	    checkAdm();
	}

	if (aOption) {
	    // Adds beans in new JOnAS container
	    addBeans(beansFileName);	
	}
	if (rOption) {
	    // Remove beans in JOnAS container
	    removeBeans(beansFileName);	
	}
	if (lOption) {
	    // Lists beans
	    listbeans();
	}
	if (jOption) {
	    // jndi names
	    listnames();
	}
	if (eOption) {
	    // Lists JOnAS properties 
	    listproperties();
	}
	if (tOption) {
	    // get monolog topics
	    listTopics();
	}
	if (debugOption) {
	    // set debug for a topic
	    setTopic(topic, "DEBUG");
	}
	if (sOption) {
	    // Stops Server
	    stopserver();
	}
	if (ttOpt) {
	    // set the default value for transaction timeout
	    setTTimeout(timeout);
	}
	if (syncOpt) {
	    // sync all entity instances outside transactions
	    sync();
	}
	if (gcOpt) {
	    // run the garbage collector
	    runGC();
	}

	// No option => interactive mode.
	if (interactive) {
	    menu();
	}

	// Return status
	if (!interactive) {
	    if (isError) {
		System.exit(2);
	    }
	}
    }
}
