/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999-2006 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.adm;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.rmi.RemoteException;
import java.util.Enumeration;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.Vector;

import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;

import org.objectweb.jonas.ear.EarServiceException;
import org.objectweb.jonas.resource.ResourceServiceException;
import org.objectweb.jonas.web.JWebContainerServiceException;

/**
 * This class implements a rmi client to administrate the server. JonasAdmin may
 * be run either in interactive mode or command mode.
 * @author Philippe Coq
 * Contributor(s): Florent Benoit & Ludovic Bert : Methods for wars and ear
 * files
 */
public class JonasAdmin {

    private static final String SERVERNAME = "JOnAS server ";

    private static String jonasName = null;

    private static AdmInterface admI = null;

    private static int state = -1;

    private static boolean reachable = false;

    private static boolean isNotEJB = false;

    private static boolean isError = false;
    /**
     * Default timeout (100 seconds)
     */
    private static final int DEFAULT_TIMEOUT = 100;

    /**
     * Define half a second by loop (sleep value) in ms
     */
    private static final long WAIT_LOOP_MSEC = 500;

    /**
     * List of servers where deployment will be done.
     */
    private static String [] target = null;

    /** Static states
     */
    public final static int ADDFILE = 101;
    public final static int REMOVEFILE = 102;
    public final static int LISTBEAN = 103;
    public final static int LISTJNDI = 104;
    public final static int LISTENV = 105;
    public final static int LISTTOPICS = 106;
    public final static int DEBUGOPTION =107;
    public final static int TTOPTION = 108;
    public final static int SYNCOPTION = 109;
    public final static int CUSTOMOPTION = 110;
    public final static int PASSIVATEOPTION = 111;
    public final static int GCOPTION = 112;
    public final static int ISDEPLOYOPTION = 113;
    public final static int STARTOPTION = 114;
    public final static int STOPOPTION = 115;

    private static boolean qOption = false;

    private static void checkAdm() {

        // Gets reference on Adm object
        String admName = jonasName + Adm.ADMNAME_SUFFIX;
        try {
            InitialContext initialContext = new InitialContext();
            admI = (AdmInterface) PortableRemoteObject.narrow(initialContext.lookup(admName), AdmInterface.class);
            state = admI.getServerState();
            reachable = (state == Adm.READY);
            if (reachable) {
                isNotEJB = !admI.isEJBContainer();
            }
        } catch (Exception e) {
            reachable = false;
        }
    }

    /**
     * check every second if server is ready and return when it's OK. don't wait
     * more than given timeout (DEFAULT_TIMEOUT if not set) sec.
     * @param pingTimeout value to wait
     */
    private static int waitServer(int pingTimeout) {
        if (pingTimeout <= 0) {
            throw new IllegalArgumentException("Timeout should be a value greater than 0");
        }
        // define the number of loops (WAIT_LOOP_MSEC milliseconds by loop)
        double loopValue = pingTimeout / (WAIT_LOOP_MSEC / (double) 1000);
        for (int i = 0; i < loopValue; i++) {
            try {
                // wait WAIT_LOOP_SEC second
                Thread.sleep(WAIT_LOOP_MSEC);
            } catch (InterruptedException e) {
                return 1;
            }
            // test if server is ready
            if (reachable) {
                return 0;
            }
            checkAdm();
            if (state == Adm.STOPPED) {
                return 1;
            }
        }
        System.out.println(SERVERNAME + jonasName + " unreachable");
        return 1;
    }

    /**
     * This method can add beans, war file ear or rar file depending on the
     * extension of the file if it's a .jar file : -> Create a new JOnAS
     * container for Beans relative to the file FileName if it's a .war file : ->
     * deploy the war with the webcontainer service if it's a .ear file : ->
     * Deploy the ear if it's a .rar file : -> Deploy the rar
     * @param fileName name of the .jar file (Case of ejb-jar file) name of the
     *        .war fle (Case of WAR file) name of the .ear file (Case of EAR
     *        file) name of the .rar file (Case of RAR file)
     */
    private static void addFile(String fileName) {
        if (!qOption) {
            System.out.println("Add File:");
        }
        if (!reachable) {
            System.err.println(SERVERNAME + jonasName + " unreachable");
            isError = true;
            return;
        }
        try {
            if (fileName.toLowerCase().endsWith(".jar") || fileName.toLowerCase().endsWith(".xml")) {
                //jar file
                if (isNotEJB) {
                    System.err.println("This server doesn't implement an EJB Container");
                    isError = true;
                    return;
                }
                if (target == null) {
                    admI.addBeans(fileName);
                } else {
                    admI.deployFileOn(fileName, target);
                }
            } else if (fileName.toLowerCase().endsWith(".war")) {
                //War file
                if (target == null) {
                    admI.addWar(fileName);
                } else {
                    admI.deployFileOn(fileName, target);
                }
            } else if (fileName.toLowerCase().endsWith(".ear")) {
                //ear file
                if (target == null) {
                    admI.addEar(fileName);
                } else {
                    admI.deployFileOn(fileName, target);
                }
            } else if (fileName.toLowerCase().endsWith(".rar")) {
                //rar file
                if (target == null) {
                    admI.addRar(fileName);
                } else {
                    admI.deployFileOn(fileName, target);
                }
            } else {
                //bad format
                System.err.println("Valid file extensions are : .jar, .xml, .war, .ear, .rar");
                return;
            }
        } catch (JWebContainerServiceException e) {
            System.err.println("admI.addWar: " + e);
            isError = true;
            return;
        } catch (EarServiceException e) {
            System.err.println("admI.addEar: " + e);
            isError = true;
            return;
        } catch (ResourceServiceException e) {
            System.err.println("admI.addRar: " + e);
            isError = true;
            return;
        } catch (RemoteException e) {
            System.err.println("Cannot Deploy " + fileName + ": " + e.getCause().getMessage());
            return;
        }
    }

    /**
     * This method can remove beans, war file or ear file depending on the
     * extension of the file if it's a .jar file : -> Remove a JOnAS container
     * for Beans relative to the file FileName if it's a .war file : -> undeploy
     * the war with the webcontainer service if it's a .ear file : -> uneploy
     * the ear if it's a .rar file : -> uneploy the rar
     * @param fileName name of the .jar file (Case of ejb-jar file) name of the
     *        .war fle (Case of WAR file) name of the .ear file (Case of EAR
     *        file) name of the .rar file (Case of RAR file)
     */
    private static void removeFile(String fileName) {
        if (!qOption) {
            System.out.println("Remove File:");
        }
        if (!reachable) {
            System.err.println(SERVERNAME + jonasName + " unreachable");
            isError = true;
            return;
        }
        //Remove a file (based upon the extension file
        try {
            if (fileName.toLowerCase().endsWith(".jar") || fileName.toLowerCase().endsWith(".xml")) {
                //jar file
                if (isNotEJB) {
                    System.err.println("no beans on TMServer");
                    isError = true;
                    return;
                }
                admI.removeBeans(fileName);
            } else if (fileName.toLowerCase().endsWith(".war")) {
                //War file
                admI.removeWar(fileName);
            } else if (fileName.toLowerCase().endsWith(".ear")) {
                //ear file
                admI.removeEar(fileName);
            } else if (fileName.toLowerCase().endsWith(".rar")) {
                //rar file
                admI.removeRar(fileName);
            } else {
                //bad format
                System.err.println("Valid file extensions are : .jar, xml, .war, .ear, *.rar");
                return;
            }
        } catch (JWebContainerServiceException e) {
            System.err.println("admI.removeWar: " + e.getMessage());
            isError = true;
            return;
        } catch (EarServiceException e) {
            System.err.println("admI.removeEar: " + e.getMessage());
            isError = true;
            return;
        } catch (ResourceServiceException e) {
            System.err.println("admI.removeRar: " + e);
            isError = true;
            return;
        } catch (RemoteException e) {
            System.err.println("RemoteException : " + e.getMessage());
            isError = true;
            return;
        }
        System.out.println("");
    }

    /**
     * This method tells if the given file is deployed or not.
     * @param fileName name of the .jar file (Case of ejb-jar file) name of the
     *        .war file (Case of WAR file) name of the .ear file (Case of EAR
     *        file) name of the .rar file (Case of RAR file)
     */
    private static void isDeployedFile(String fileName) {
        if (!qOption) {
            System.out.println("Is File Deployable:");
        }
        if (!reachable) {
            System.err.println(SERVERNAME + jonasName + " unreachable");
            isError = true;
            return;
        }
        //Remove a file (based upon the extension file
        try {
            boolean isDeployed = false;
            if (fileName.toLowerCase().endsWith(".jar") || fileName.toLowerCase().endsWith(".xml")) {
                //jar file
                if (isNotEJB) {
                    System.err.println("no beans on TMServer");
                    isError = true;
                    return;
                }
                isDeployed = admI.isLoaded(fileName);
            } else if (fileName.toLowerCase().endsWith(".war")) {
                //War file
                isDeployed = admI.isWarLoaded(fileName);
            } else if (fileName.toLowerCase().endsWith(".ear")) {
                //ear file
                isDeployed = admI.isEarLoaded(fileName);
            } else if (fileName.toLowerCase().endsWith(".rar")) {
                //rar file
                isDeployed = admI.isRarLoaded(fileName);
            } else {
                //bad format
                System.err.println("Valid file extensions are : .jar, xml, .war, .ear, .rar");
                return;
            }
            if (isDeployed) {
                System.out.println(fileName + " deployed in " + jonasName);
            } else {
                System.out.println(fileName + " NOT deployed in " + jonasName);
            }
        } catch (JWebContainerServiceException e) {
            System.err.println("admI.removeWar: " + e.getMessage());
            isError = true;
            return;
        } catch (EarServiceException e) {
            System.err.println("admI.removeEar: " + e.getMessage());
            isError = true;
            return;
        } catch (ResourceServiceException e) {
            System.err.println("admI.removeRar: " + e);
            isError = true;
            return;
        } catch (RemoteException e) {
            System.err.println("RemoteException : " + e.getMessage());
            isError = true;
            return;
        }
        System.out.println("");
    }

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

    private static void listbeans() {
        if (!qOption) {
            System.out.println("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;
        }
        System.out.println("");
    }

    private static void listnames() {
        if (!qOption) {
            System.out.println("List JndiNames:");
        }
        if (!reachable) {
            System.err.println(SERVERNAME + jonasName + " unreachable");
            isError = true;
            return;
        }
        Vector result = new Vector();
        try {
            result = admI.listContext();
        } catch (RemoteException e) {
            System.err.println("admI.listContext() : " + e);
            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));
        }
        System.out.println("");
    }

    private static void listproperties() {
        if (!qOption) {
            System.out.println("ListProperties:");
        }
        if (!reachable) {
            System.err.println(SERVERNAME + jonasName + " unreachable");
            isError = true;
            return;
        }
        Properties p = new Properties();
        try {
            p = admI.listEnv();
        } catch (RemoteException e) {
            System.err.println("admI.listEnv() : " + e);
            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());
        }
        System.out.println("");
    }

    private static void sync(boolean passivate) {
        if (!qOption) {
            System.out.println("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(passivate);
        } catch (RemoteException e) {
            System.err.println("admI.syncAllEntities : " + e);
            isError = true;
            return;
        }
        System.out.println("");
    }

    private static void runGC() {
        if (!qOption) {
            System.out.println("Run GC:");
        }
        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;
        }
        System.out.println("");
    }

    private static void setTTimeout(String tstr) {
        if (!qOption) {
            System.out.println("Set TransactionTimeout:");
        }
        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;
        }
        System.out.println("");
    }

    private static void listTopics() {
        if (!qOption) {
            System.out.println("List Monolog Topics:");
        }
        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;
        }
        System.out.println("");
    }

    private static void setTopic(String t, String l) {
        if (!qOption) {
            System.out.println("Set Monolog Topic:");
        }
        try {
            admI.setTopicLevel(t, l.toUpperCase());
        } catch (RemoteException e) {
            System.err.println("admI.setTopics : " + e);
            isError = true;
            return;
        }
        System.out.println("");
    }

    private static void startserver() {
        if (!reachable) {
            System.err.println(SERVERNAME + jonasName + " unreachable");
            isError = true;
            return;
        }
        if (target == null) {
            System.out.println("ERROR: Current Server Already started");
            return;
        }
        try {
            admI.startRemoteServers(target);
        } catch (RemoteException e) {
            System.err.println("Error while starting servers:" + e.getCause().getMessage());
        }
    }

    private static void stopserver() {
        if (!reachable) {
            System.err.println(SERVERNAME + jonasName + " unreachable");
            isError = true;
            return;
        }
        try {
            if (target == null) {
                admI.killServer();
            } else {
                admI.stopRemoteServers(target);
            }
        } catch (RemoteException e) {
            if (target != null) {
                System.err.println("Error while stopping servers:" + e.getCause().getMessage());
            }
        }
        if (target == null) {
            System.out.println(SERVERNAME + jonasName + " stopped");
        }
    }

    private static void help() {
        System.out.println("addbeans    adds beans in a new JOnAS container");
        System.out.println("addfile     adds beans/servlets/j2ee app/rars based upon the file extension");
        System.out.println("custom      dump jonas customization");
        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("removefile  remove beans/servlets/j2ee app/rars (based upon the file extension)");
        System.out.println("start       stop target servers");
        System.out.println("stop        stop target servers");
        System.out.println("sync        synchronize all entities");
        System.out.println("passivate   passivate all entities");
        System.out.println("trace       get/set monolog topics");
        System.out.println("ttimeout    set default transaction timeout");
        System.out.println("target      set list of servers where command must be applied");
    }

    private static void usage() {
        System.out.println("usage : jonas admin <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("                                     : - servlets from a WAR file");
        System.out.println("                                     : - j2ee application from an EAR file");
        System.out.println("                                     : - resource adapter from a RAR file");
        System.out.println("    -r fileName : dynamically remove : - beans from container fileName");
        System.out.println("                                     : - servlets of a WAR file");
        System.out.println("                                     : - j2ee application of an EAR file");
        System.out.println("                                     : - resource adapter from a RAR file");
        System.out.println("    -isdeployed fileName : tells if the file is deployed or not");
        System.out.println("    -sync: synchronize all entities");
        System.out.println("    -passivate: passivate all entities");
        System.out.println("    -gc: run the garbage collector");
        System.out.println("    -tt timeout: set default transaction timeout");
        System.out.println("    -start: Start servers designed by '-target' arg");
        System.out.println("    -target target: set target for commands (default is local server)");
        System.out.println("    -ping [-timeout <val (sec)>]: ping server for a given time.(default=100s)");
        System.out.println("    -t list monolog topics");
        System.out.println("    --debug-level topic : set DEBUG for a monolog topic");
        System.out.println("    -q : quiet mode, no processing header information.");
        System.out.println("    -h : help message.");
        System.out.println("    -? : help message.");
    }

    /*
     * interactive mode
     */
    public static 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("Admin (" + jonasName + ") > ");
            String command = inbuf.readLine();
            if (command.length() == 0) {
                continue;
            }
            if ("addbeans".startsWith(command) || "addfile".startsWith(command)) {
                String fName = null;
                System.out.print("file name ? > ");
                if ((fName = inbuf.readLine()).length() != 0) {
                    addFile(fName);
                }
                continue;
            }
            if ("start".startsWith(command)) {
                startserver();
                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 ("custom".startsWith(command)) {
                custom();
                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) || "exit".startsWith(command)) {
                return;
            }
            if ("removebeans".startsWith(command) || "removefile".startsWith(command)) {
                String fName = null;
                System.out.print("file name ? > ");
                if ((fName = inbuf.readLine()).length() != 0) {
                    removeFile(fName);
                }
                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 | INHERIT) > ");
                    String levstr = inbuf.readLine().trim();
                    setTopic(tname, levstr);
                }
                continue;
            }
            if ("stop".startsWith(command)) {
                stopserver();
                continue;
            }
            if ("sync".startsWith(command)) {
                sync(false);
                continue;
            }
            if ("passivate".startsWith(command)) {
                sync(true);
                continue;
            }
            if ("ttimeout".startsWith(command)) {
                String tstr = null;
                System.out.print("transaction timeout in seconds ? > ");
                if ((tstr = inbuf.readLine()).length() != 0) {
                    setTTimeout(tstr);
                }
                continue;
            }
            if ("target".startsWith(command)) {
                System.out.print("Server or Cluster where to deploy the beans ? > ");
                target = makeArrayFrom(inbuf.readLine());
                continue;
            }
            System.out.println("Unknown command. Type help to get for the list of commands.");
        }
    }

    /**
     * Make an Array of OBJECT_NAMEs
     * @param line A comma separated list of names
     * @return Array of Stringified objectnames
     */
    private static String [] makeArrayFrom(String line) {
        StringTokenizer stk = new StringTokenizer(line, ",");
        int nb  = stk.countTokens();
        String [] ret = new String[nb];
        for (int i = 0; i < nb; i++) {
            ret[i] = stk.nextToken();
        }
        return ret;
    }

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

        String fileName = null;
        String timeout = null;
        String topic = null;
        String pingTimeoutValue = null;

        boolean pingOption = false;
        boolean sOption = false;

        boolean interactive = true;
        boolean namedServer = false;
        Vector lstArgs = new Vector();
        // Get command args
        for (int argn = 0; argn < args.length; argn++) {
            String arg = args[argn];
            boolean nextArgument = argn < args.length - 1;

            if (arg.equals("-a") && nextArgument) {
                fileName = args[++argn];
                JonasArg ja = new JonasArg(ADDFILE, fileName);
                lstArgs.add(ja);
                interactive = false;
                continue;
            }
            if (arg.equals("-ping")) {
                pingOption = true;
                continue;
            }
            if (arg.equals("-custom")) {
                JonasArg ja = new JonasArg(CUSTOMOPTION);
                lstArgs.add(ja);
                interactive = false;
                continue;
            }
            if (arg.equals("-e")) {
                JonasArg ja = new JonasArg(LISTENV);
                lstArgs.add(ja);
                interactive = false;
                continue;
            }
            if (arg.equals("-h") || arg.equals("-?")) {
                usage();
                System.exit(0);
            }
            if (arg.equals("-gc")) {
                JonasArg ja = new JonasArg(GCOPTION);
                lstArgs.add(ja);
                interactive = false;
                continue;
            }
            if (arg.equals("-j")) {
                JonasArg ja = new JonasArg(LISTJNDI);
                lstArgs.add(ja);
                interactive = false;
                continue;
            }
            if (arg.equals("-l")) {
                JonasArg ja = new JonasArg(LISTBEAN);
                lstArgs.add(ja);
                interactive = false;
                continue;
            }
            if (arg.equals("-n") && nextArgument) {
                jonasName = args[++argn];
                namedServer = true;
                continue;
            }
            if (arg.equals("-timeout") && nextArgument) {
                pingTimeoutValue = args[++argn];
                continue;
            }
            if (arg.equals("-target") && nextArgument) {
                target = makeArrayFrom(args[++argn]);
                continue;
            }
            if (arg.equals("-r") && nextArgument) {
                fileName = args[++argn];
                JonasArg ja = new JonasArg(REMOVEFILE, fileName);
                lstArgs.add(ja);
                interactive = false;
                continue;
            }
            if (arg.equals("-s")) {
                sOption = true;
                interactive = false;
                continue;
            }
            if (arg.equals("-stop")) {
                JonasArg ja = new JonasArg(STOPOPTION);
                lstArgs.add(ja);
                interactive = false;
                continue;
            }
            if (arg.equals("-start")) {
                JonasArg ja = new JonasArg(STARTOPTION);
                lstArgs.add(ja);
                interactive = false;
                continue;
            }
            if (arg.equals("-sync")) {
                JonasArg ja = new JonasArg(SYNCOPTION);
                lstArgs.add(ja);
                interactive = false;
                continue;
            }
            if (arg.equals("-passivate")) {
                JonasArg ja = new JonasArg(PASSIVATEOPTION);
                lstArgs.add(ja);
                interactive = false;
                continue;
            }
            if (arg.equals("--debug-level") && nextArgument) {
                topic = args[++argn];
                JonasArg ja = new JonasArg(DEBUGOPTION, topic);
                lstArgs.add(ja);
                interactive = false;
                continue;
            }
            if (arg.equals("-t")) {
                JonasArg ja = new JonasArg(LISTTOPICS);
                lstArgs.add(ja);
                interactive = false;
                continue;
            }
            if (arg.equals("-tt") && nextArgument) {
                timeout = args[++argn];
                JonasArg ja = new JonasArg(TTOPTION, timeout);
                lstArgs.add(ja);
                interactive = false;
                continue;
            }
            if (arg.equals("-isdeployed") && nextArgument) {
                fileName = args[++argn];
                JonasArg ja = new JonasArg(ISDEPLOYOPTION, fileName);
                lstArgs.add(ja);
                interactive = false;
                continue;
            }
            if (arg.equals("-q")) {
                qOption = true;
                interactive = false;
                continue;
            }
            System.out.println("Bad option: " + arg);
            usage();
            System.exit(2);
        }

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

        if (pingOption) {
            //
            int pingTimeout = DEFAULT_TIMEOUT;
            // if a timeout is set by user, use it.
            if (pingTimeoutValue != null) {
                try {
                    pingTimeout = Integer.parseInt(pingTimeoutValue);
                } catch (NumberFormatException nfe) {
                    System.err.println("Incorrect timeout value for ping. Value is '" + pingTimeoutValue + "'.");
                }
            }
            // Wait EJB server is ready
            System.exit(waitServer(pingTimeout));
        }

        // for all other options, first check server is reachable
        checkAdm();

        // Stopserver is special, don't process anything else
        if (sOption) {
            // Stops Server
            stopserver();
            if (isError) {
                System.exit(2);
            } else {
                return;
            }

        }

        // No option => interactive mode.
        if (interactive) {
            menu();
        } else {
            boolean first = true;
            boolean forQuiet = qOption;
            qOption = true;
            for (Enumeration e = lstArgs.elements() ; e.hasMoreElements() ;) {
                JonasArg ai = (JonasArg) e.nextElement();
                switch (ai.argType) {
                    case ADDFILE:
                        // Adds file into JOnAS container
                        addFile(ai.argName);
                        break;
                    case REMOVEFILE:
                        // Remove file from JOnAS container
                        removeFile(ai.argName);
                        break;
                    case STARTOPTION:
                        startserver();
                        break;
                    case STOPOPTION:
                        stopserver();
                        break;
                    case LISTBEAN:
                        // List beans in JOnAS container
                        listbeans();
                        break;
                    case LISTJNDI:
                        // List jndi names in JOnAS container
                        listnames();
                        break;
                    case LISTENV:
                        // List JOnAS environment
                        listproperties();
                        break;
                    case LISTTOPICS:
                        // List Monolog topics
                        listTopics();
                        break;
                    case DEBUGOPTION:
                        // set debug for a topic
                        setTopic(ai.argName, "DEBUG");
                        break;
                    case TTOPTION:
                        // set the default value for transaction timeout
                        setTTimeout(ai.argName);
                        break;
                    case SYNCOPTION:
                        // sync all entity instances outside transactions
                        sync(false);
                        break;
                    case CUSTOMOPTION:
                        // Custom option
                        custom();
                        break;
                    case PASSIVATEOPTION:
                        // passivate all entity instances outside transactions
                        sync(true);
                        break;
                    case GCOPTION:
                        // run the garbage collector
                        runGC();
                        break;
                    case ISDEPLOYOPTION:
                        // is the file deployed ?
                        isDeployedFile(ai.argName);
                        break;
                }
                // Keep original functionality w/ first option then add header
                // lines for each additional command if -q not set.
                if (first) {
                    first = false;
                    qOption = forQuiet;
                }
                // Exit if error
                if (isError) {
                    System.exit(2);
                }
            }
        }
    }

    // Class to hold the arguments for processing
    public static class JonasArg {
        public int argType;
        public String argName = "";

        public JonasArg(int type) {
            argType = type;
        }
        public JonasArg(int type, String name) {
            argType = type;
            argName = name;
        }
    }
}