/*
 * 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.tomcat;

import javax.naming.Context;
import javax.naming.NamingException;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.MalformedURLException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.StringTokenizer;
import org.apache.catalina.startup.BootstrapService;
import org.apache.catalina.startup.ClassLoaderFactory;
import org.apache.catalina.loader.Extension;
import org.apache.catalina.loader.StandardClassLoader;

import org.objectweb.jonas.common.Log;
import org.objectweb.jonas.service.ServiceException;
import org.objectweb.jonas.service.AbsDynamicServiceImpl;
import org.objectweb.util.monolog.api.Logger;
import org.objectweb.util.monolog.api.BasicLevel;

/**
 * Tomcat service implementation for Tomcat 4.0.x
 *
 * @author Philippe Coq
 *  Contributor(s):
 * Julien Lehembre - Libelis 
 *
 */

public class EmbeddedTomcatImpl40 extends AbsDynamicServiceImpl  implements TomcatService {

    static private Logger logger = null;
    private String catalinaHome = null;
    private String jonasHome = null;
    private static final String TOMCAT_ARGS = "args";

    
    private Object catalinaService = null;

    public void doInit(Context ctx) {
	int debug = 0;	                                 
        if( logger == null)
            logger = Log.getLogger(Log.JONAS_TOMCAT_PREFIX);
	logger.log(BasicLevel.DEBUG, "entering");
	jonasHome = System.getProperties().getProperty("install.root");
	catalinaHome = System.getProperties().getProperty("catalina.home");
	if ((catalinaHome == null) || (catalinaHome.equalsIgnoreCase(""))) {
	    logger.log(BasicLevel.ERROR, "The catalina.home isn't set during JonAS's launching");
	    throw new ServiceException("catalina.home property is not set");
	}
	// Configure catalina.base from catalina.home if not yet set
	if (System.getProperty("catalina.base") == null)
	    System.setProperty("catalina.base", catalinaHome);



	try {
	    String args  = (String) ctx.lookup(TOMCAT_ARGS); 
	    java.util.StringTokenizer st = new StringTokenizer(args);
  
	    while (st.hasMoreTokens()) {
		String s = (String)st.nextToken();
		if ("-debug".equals(s))
                        debug = 1;
		}

	} catch (NamingException e) {
	}

	String argsforTomcat[] = new String[2];

	argsforTomcat[0] = "-nonaming";   // we have to launch catalina with -nonaming option         
	argsforTomcat[1] = "start";
	
	// Construct the class loaders we will need
	ClassLoader commonLoader = null;
	ClassLoader catalinaLoader = null;
	ClassLoader sharedLoader = null;
	try {

	    File unpacked[] = new File[1];
	    File packed[] = new File[1];
	    ClassLoaderFactory.setDebug(debug);

	    

	    unpacked[0] = new File(catalinaHome,"common" + File.separator + "classes");
	    packed[0] = new File(catalinaHome,"common" + File.separator + "lib");
	    commonLoader =
		ClassLoaderFactory.createClassLoader(unpacked, packed, null);

	    unpacked[0] = new File(catalinaHome,
                                   "server" + File.separator + "classes");
	    packed = new File[2];
	    packed[0] = new File(catalinaHome,
                                 "server" + File.separator + "lib");
	    packed[1] = new File(jonasHome,"lib");
	    catalinaLoader =
		ClassLoaderFactory.createClassLoader(unpacked, packed,
                                                     commonLoader);

	    unpacked[0] = new File(catalinaHome,"classes");
	    packed  = new File[1];
	    packed[0] = new File(catalinaHome,"lib");
	    sharedLoader =
		ClassLoaderFactory.createClassLoader(unpacked, packed, commonLoader);

	} catch (Throwable t) {
	    throw new ServiceException("Error while initializing classLoader in the Tomcat service.", t);
	}

	Thread.currentThread().setContextClassLoader(catalinaLoader);

	// Load catalina startup class and call its process() method
	try {
	    if( System.getSecurityManager() != null ) {
		// Pre load some classes required for SecurityManager
		// so that defineClassInPackage does not throw a
		// security exception.
		String basePackage = "org.apache.catalina.";
		catalinaLoader.loadClass(basePackage +
                                             "core.ApplicationContext$PrivilegedGetRequestDispatcher");
		catalinaLoader.loadClass(basePackage +
                                             "core.ApplicationContext$PrivilegedGetResource");
		catalinaLoader.loadClass(basePackage +
                                             "core.ApplicationContext$PrivilegedGetResourcePaths");
		catalinaLoader.loadClass(basePackage +
                                             "core.ApplicationContext$PrivilegedLogMessage");
		catalinaLoader.loadClass(basePackage +
                                             "core.ApplicationContext$PrivilegedLogException");
		catalinaLoader.loadClass(basePackage +
                                             "core.ApplicationContext$PrivilegedLogThrowable");
		catalinaLoader.loadClass(basePackage +
                                             "core.ApplicationDispatcher$PrivilegedForward");
		catalinaLoader.loadClass(basePackage +
                                             "core.ApplicationDispatcher$PrivilegedInclude");
		catalinaLoader.loadClass(basePackage +
                                             "connector.HttpRequestBase$PrivilegedGetSession");
		catalinaLoader.loadClass(basePackage +
                                             "loader.WebappClassLoader$PrivilegedFindResource");
		catalinaLoader.loadClass(basePackage + "session.StandardSession");
		catalinaLoader.loadClass(basePackage + "util.CookieTools");
		catalinaLoader.loadClass(basePackage + "util.URL");
		catalinaLoader.loadClass(basePackage + "util.Enumerator");
		catalinaLoader.loadClass("javax.servlet.http.Cookie");
	    }

	    // Instantiate a startup class instance
	    logger.log(BasicLevel.DEBUG, "Loading catalina startup class");

	    Class startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.CatalinaService");
	    Object startupInstance = startupClass.newInstance();

	    // Set the shared extensions class loader
	    logger.log(BasicLevel.DEBUG,"Setting catalina  startup class properties");
	    String methodName = "setParentClassLoader";
	    Class paramTypes[] = new Class[1];
	    paramTypes[0] = Class.forName("java.lang.ClassLoader");
	    Object paramValues[] = new Object[1];
	    paramValues[0] = sharedLoader;
	    Method method = startupInstance.getClass().getMethod(methodName, paramTypes);
	    method.invoke(startupInstance, paramValues);
	    catalinaService = startupInstance;
	    // Call the process() method
	    logger.log(BasicLevel.DEBUG, "Calling catalina startup class process() method");
	    methodName = "process";
	    paramTypes = new Class[1];
	    paramTypes[0] = argsforTomcat.getClass();
	    paramValues = new Object[1];
	    paramValues[0] = argsforTomcat;
	    method = catalinaService.getClass().getMethod(methodName, paramTypes);
	    method.invoke(catalinaService, paramValues);
	} catch (Throwable e) {
	    e.printStackTrace();
	    throw new ServiceException("Error while initializing the Tomcat service.", e);
	}
    }

    public void run() throws ServiceException {

    }

    public void doStop() throws ServiceException {
	logger.log(BasicLevel.DEBUG, "entering");
        if(isStarted()){
            try {
                String methodName = "stop";
                Method method = catalinaService.getClass().getMethod(methodName, null);
                method.invoke(catalinaService, null);
            } catch (Exception te) {
                te.printStackTrace();
                throw new ServiceException(te.getMessage());
            }
        }
    }
}

