/*
 * 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): ______________________________________.
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */


package org.objectweb.jonas.tools;


import java.io.File;
import java.io.InputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import java.util.StringTokenizer;

import org.objectweb.common.Env;
import org.objectweb.jonas_ejb.lib.Version;
import org.objectweb.jonas.common.JProp;

/**
 *  This class allows to check if the environment is correct for JOnAS.
 */

public class CheckEnv {

    /**
     * CheckEnv allows to check if the JOnAS environment is correct or not.
     * <p>
     * Usage: java org.objectweb.jonas.tools.CheckEnv -help
     * <br>
     *         to print this help message
     * <p>
     * or    java org.objectweb.jonas.tools.CheckEnv
     * <br>
     *         to check if the JOnAS environment is correct or not,
     *         and to display the content of the configuration files.
     */

    public  static final int ENV_OK      = 0;
    public  static final int ENV_WARNING = 1;
    public  static final int ENV_ERROR   = 2;
    private static final int ENV_UNKNOWN = -1;
    private static int envStatus = ENV_UNKNOWN;

    private static final String INSTALL_ROOT = "install.root";
    private static final String JAVA_NAMING_PROVIDER_URL = "java.naming.provider.url";
    private static final String DBM_SERVICE = "dbm";
    private static final String DATASOURCES = "jonas.service.dbm.datasources";
    private static final String DATASOURCE_CLASS_NAME = "datasource.classname";
    private static final String RESOURCE_SERVICE = "resource";
    private static final String RESOURCES = "jonas.service.resource.resources";
    private static final String RESOURCE_CONNEC_FACT_CLASS_NAME = "managedconnectionfactoryclass";

    private static Hashtable classesToCheck = new Hashtable();
    static {
	classesToCheck.put("javax.ejb.EnterpriseBean","ejb.jar");
	classesToCheck.put("javax.naming.InitialContext","jndi.jar");
	classesToCheck.put("com.sun.jndi.url.jndi.jndiURLContextFactory","providerutil.jar");
	classesToCheck.put("com.sun.jndi.rmi.registry.RemoteReference","rmiregistry.jar");
	classesToCheck.put("javax.sql.DataSource","jdbc2_0-stdext.jar");
	classesToCheck.put("javax.transaction.UserTransaction","jta-spec1_0_1.jar");
	classesToCheck.put("org.apache.xerces.parsers.SAXParser","xerces.jar");
	classesToCheck.put("javax.jms.Message","jms.jar");
	classesToCheck.put("org.apache.regexp.REUtil","jakarta-regexp-1.2.jar");
	classesToCheck.put("fr.dyade.aaa.joram.Topic","joram.jar");
	classesToCheck.put("org.objectweb.util.pool.api.Pool","ow_util_pool_lib.jar");
	classesToCheck.put("org.objectweb.transaction.api.ConnectionManager","ow_tx_api.jar");
	classesToCheck.put("org.objectweb.transaction.ramanager.ConnectionManagerImpl","ow_tx_ramanager.jar");
	classesToCheck.put("org.objectweb.util.monolog.wrapper.printwriter.LoggerImpl","ow_util_log_wrp_pw_only.jar");
	// Don't control jaas for JDK 1.2
	//classesToCheck.put("javax.security.auth.Subject","jaas1_.jar");
	classesToCheck.put("javax.resource.cci.ConnectionFactory","connector-1_0.jar");
	if (Env.isJeremie()) {
	    classesToCheck.put("org.objectweb.jeremie.tools.jrmic.JRMICompiler","jonathan.jar");
	} else if (Env.isDavid()) {
	    classesToCheck.put("org.objectweb.david.tools.jrmic.JRMICompiler","jonathan.jar");
	} else if (Env.isSunRMI()) {
	    classesToCheck.put("java.rmi.server.UnicastRemoteObject","rt.jar");
	}
	//classesToCheck.put("only.for.Test","Test.jar");
    }

    public static int getStatus() {

	Properties props = null;
	envStatus = ENV_OK;

	// Check classes
	Enumeration cList = classesToCheck.keys();
	while (cList.hasMoreElements()) {
	    String cname = (String)cList.nextElement();
	    if (!classIsAccessible(cname)) {
		System.err.println("JOnAS environment ERROR: Classes of '"
			    +classesToCheck.get(cname)+"' not accessible");
		System.err.println("(The JOnAS package is bad)");
		envStatus = ENV_ERROR;
	    }
	}

	// Trace the OBJECTWEB_ORB value
	System.out.println("");
	System.out.println("- OBJECTWEB_ORB value: ");
	if (Env.isSunRMI()) {
	    System.out.println("   RMI");
	} else if (Env.isJeremie()) {
	    System.out.println("   JEREMIE");
	} else if (Env.isDavid()) {
	    System.out.println("   DAVID");
	} else {
	    System.out.println("   nor RMI, neither JEREMIE or DAVID");
	}

	// Check the 'install.root' system property
	// (JONAS_ROOT variable environment)
	try {
	    String sRoot = System.getProperty(INSTALL_ROOT);
	    if (sRoot==null) {
		System.err.println("JOnAS environment ERROR: '"
			    +INSTALL_ROOT+"' system property not defined");
		envStatus = ENV_ERROR;
	    } else {
		File fRoot = new File(sRoot);
		if (!fRoot.isDirectory()) {
		    System.err.println("JOnAS environment ERROR: Invalid 'JONAS_ROOT' value");
		    System.err.println("                         '"+sRoot+"' directory not exist");
		    envStatus = ENV_ERROR;
		} else {
		    System.out.println("");
		    System.out.println("- JONAS_ROOT value: ");
		    System.out.println("   "+sRoot);
		}
	    }
	} catch (SecurityException e) {
	    System.err.println("CheckEnv ERROR: Cannot get the '"
			+INSTALL_ROOT+"' system property ("+e+")");
	    envStatus = ENV_ERROR;
	}

	// Check jonas.properties, <datasource>.properties and <resource>.properties
	try {
	    // Check jonas.properties
	    boolean isServiceDbm = false;
	    boolean isServiceResource = false;
	    JProp jonasProps = new JProp("jonas");
	    System.out.println("");
	    System.out.println("- JOnAS Services:");
	    System.out.println("   "+jonasProps.getValue("jonas.services", "none"));
	    String[] services = jonasProps.getValueAsArray("jonas.services");
	    for (int i=0; i<services.length; i++) {
		if (DBM_SERVICE.equals(services[i])) {
		    isServiceDbm = true;
		}
		if (RESOURCE_SERVICE.equals(services[i])) {
		    isServiceResource = true;
		}
		String serviceClass = jonasProps.getValue("jonas.service."+services[i]+".class");
		if (serviceClass==null) {
		    System.err.println("JOnAS environment ERROR: 'jonas.service."
				+services[i]+".class' property not defined");
		    envStatus = ENV_ERROR;
		} else {
		    if (!classIsAccessible(serviceClass)) {
			System.err.println("JOnAS environment ERROR: '"
				    +serviceClass+"' class not accessible ('"
				    +services[i]+"' service class)");
			envStatus = ENV_ERROR;
		    } 
		}
	    }
	    System.out.println("");
	    System.out.println("- Contents of 'jonas.properties':");
	    String[] jonasFilesNames = jonasProps.getPropFiles();
	    System.out.println("  (");
	    for (int i=0; i<jonasFilesNames.length; i++) {
		System.out.println("   "+jonasFilesNames[i]);
	    }
	    System.out.println("  )");
	    System.out.println(jonasProps.toString());
	    if (isServiceDbm) {
		// Check <datasource>.properties
		String dsList = jonasProps.getValue(DATASOURCES, "");
		StringTokenizer st = new StringTokenizer(dsList, ",");
		String dsName = null;
		while (st.hasMoreTokens()) {
		    try {
			dsName = st.nextToken().trim();
			JProp dsProps = new JProp(dsName);
			System.out.println("");
			System.out.println("- Contents of '"+dsName+".properties':");
			String[] dsFilesNames = dsProps.getPropFiles();
			System.out.println("  (");
			for (int i=0; i<dsFilesNames.length; i++) {
			    System.out.println("   "+dsFilesNames[i]);
			}
			System.out.println("  )");
			System.out.println(dsProps.toString());
			String driverName = dsProps.getValue(DATASOURCE_CLASS_NAME, "");
			if (!classIsAccessible(driverName)) {
			    System.err.println("JOnAS environment ERROR: '"
					+driverName+"' class not accessible ('"
					+dsName+"' datasource's driver)");
			    envStatus = ENV_ERROR;
			}
		    } catch (Exception e) {
			System.err.println("JOnAS environment ERROR: '"
				    +dsName+".properties' "
				    +"not available in JONAS_ROOT/config, HOME, or .");
			envStatus = ENV_ERROR;
		    }
		}
	    }
	    if (isServiceResource) {
		// Check <resource>.properties
		String resList = jonasProps.getValue(RESOURCES, "");
		StringTokenizer st = new StringTokenizer(resList, ",");
		String resName = null;
		while (st.hasMoreTokens()) {
		    try {
			resName = st.nextToken().trim();
			JProp resProps = new JProp(resName);
			System.out.println("");
			System.out.println("- Contents of '"+resName+".properties':");
			String[] resFilesNames = resProps.getPropFiles();
			System.out.println("  (");
			for (int i=0; i<resFilesNames.length; i++) {
			    System.out.println("   "+resFilesNames[i]);
			}
			System.out.println("  )");
			System.out.println(resProps.toString());
			String mcFactName = resProps.getValue(RESOURCE_CONNEC_FACT_CLASS_NAME, "");
			if (!classIsAccessible(mcFactName)) {
			    System.err.println("JOnAS environment ERROR: '"
					+mcFactName+"' class not accessible ("
					+"Managed connection factory for resource '"+resName+"')");
			    envStatus = ENV_ERROR;
			}
		    } catch (Exception e) {
			System.err.println("JOnAS environment ERROR: '"
				    +resName+".properties' "
				    +"not available in JONAS_ROOT/config, HOME, or .");
			envStatus = ENV_ERROR;
		    }
		}
	    }
	} catch (Exception e) {
	    System.err.println("JOnAS environment ERROR: 'jonas.properties' not accessible ("+e+")");
	    envStatus = ENV_ERROR;
	}

	// Check trace.properties
	if (getProperties("trace.properties") == null) {
	    System.err.println("JOnAS environment ERROR: 'trace.properties' not accessible");
	    envStatus = ENV_ERROR;
	}

	// Check jndi.properties
	props = getProperties("jndi.properties");
	if (props == null) {
	    System.err.println("JOnAS environment ERROR: 'jndi.properties' not accessible");
	    envStatus = ENV_ERROR;
	} else {
	    String val = props.getProperty(JAVA_NAMING_PROVIDER_URL);
	    if (val == null) {
		System.err.println("JOnAS environment ERROR: The content of 'jndi.properties' is bad");
		System.err.println("("+JAVA_NAMING_PROVIDER_URL+" not defined)");
		envStatus = ENV_ERROR;
	    } else {
		if (Env.isJeremie() && !val.startsWith("jrmi")) {
		    System.err.println("JOnAS environment ERROR: The content of 'jndi.properties' is bad");
		    System.err.println("(On JEREMIE, bad value for "+JAVA_NAMING_PROVIDER_URL+")");
		    envStatus = ENV_ERROR;
		}
		if (Env.isSunRMI() && !val.startsWith("rmi")) {
		    System.err.println("JOnAS environment ERROR: The content of 'jndi.properties' is bad");
		    System.err.println("(On RMI, bad value for "+JAVA_NAMING_PROVIDER_URL+")");
		    envStatus = ENV_ERROR;
		}
	    }
	}

	// Check jonas-users.properties
	if (getProperties("jonas-users.properties") == null) {
	    System.err.println("JOnAS environment WARNING: 'jonas-users.properties' not accessible");
	    envStatus = (envStatus>ENV_WARNING) ? envStatus : ENV_WARNING;
	}

	return(envStatus);	
    }

    public static void main(String args[]) {
	boolean isHelp    = false;
	boolean isVerbose = true;
	// Get args
	for (int argn=0; argn<args.length; argn++) {
	    String arg = args[argn];
	    if (arg.equals("-help") || arg.equals("-?")) {
		isHelp = true;
		continue;
	    }
	}
	// Usage ?
	if (isHelp) {
	    usage();
	    System.exit(0);
	}

	// Status
	int status = getStatus();
	System.out.println("");
	if (status==ENV_OK) {
	    System.err.println("The JOnAS environment seems correct.");
	    System.exit(0);
	} else if (status==ENV_WARNING) {
	    System.err.println("WARNING: The JOnAS environment may be incomplete.");
	    System.exit(1);
	} else if (status==ENV_ERROR) {
	    System.err.println("ERROR: The JOnAS environment is NOT correct.");
	    System.exit(2);
	}
    }

    static boolean classIsAccessible(String name) {
	try {
	    Class.forName(name);
	    return(true);
	} catch (Exception e) {
	    return(false);
	} catch (Error e) {
	    System.err.println(e);
	    return(false);
	}
    }

    // Return null if properties are not accessible
    static Properties getProperties(String name) {
	boolean isAccessible = true;
	Properties props = null;
	InputStream is = ClassLoader.getSystemResourceAsStream(name);
	if (is != null) {
	    props = new Properties();
	    try {
		props.load(is);
		System.out.println("");
		System.out.println("- Contents of '"+name+"':");
		System.out.println("  ("+ClassLoader.getSystemResource(name).toString()+")");
		Enumeration pList = props.propertyNames();
		while (pList.hasMoreElements()) {
		    String pname = (String)pList.nextElement();
		    System.out.println("   "+pname+" = "+props.getProperty(pname));
		}
	    } catch (IOException e) {
		props = null;
	    }
	} else {
	    props = null;
	}
	return(props);
    }

    private static void usage() {
	System.out.println("");
	System.out.println("Usage: CheckEnv [ -help | -? ]");
	System.out.println("    to print this help message");
	System.out.println("");
	System.out.println("or     CheckEnv");
	System.out.println("    to check if the JOnAS environment is correct or not,");
	System.out.println("    and to display the content of the configuration files.");
	System.out.println("");
    }

}


