/*
 * 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.jmx.vjadmin.servlet;

// standard imports
import java.util.Properties;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Set;
import java.util.HashMap;
import java.util.Date;
import java.util.Vector;

// naming imports
//import javax.naming.Context;
//import javax.naming.InitialContext;
import javax.naming.NamingEnumeration;
import javax.naming.NameClassPair;
import javax.naming.NamingException;

// servlet imports
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

// monolog imports
import org.objectweb.util.monolog.api.Logger;
import org.objectweb.util.monolog.api.BasicLevel;

// JOnAS log imports
import org.objectweb.jonas.common.Log;

// velocity imports
import org.apache.velocity.Template;
import org.apache.velocity.context.Context;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.servlet.VelocityServlet;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.exception.ParseErrorException;

// JOnAS JMX imports
import org.objectweb.jonas.jmx.*;

// Jadmin imports
import org.objectweb.jonas.jmx.vjadmin.*;

public class InitialServlet extends VelocityServlet {

    static private Logger logger = null;

    public void init(ServletConfig config) throws ServletException {
	super.init(config);
	logger = Log.getLogger(ServletLog.JONAS_VELO_SERVLET_PREFIX);
    }

    /**  Called by the VelocityServlet init(). 
      *   We set some properties so that Velocity templates will loaded from a directory
      *   called "templates" under the Jadmin web application installation directory
      *   (i.e. under ../wabapps/jadmin/templates, where jadmin is name of the war containing
      *   the web application).
      */
   protected java.util.Properties loadConfiguration(ServletConfig config )
        throws java.io.IOException, java.io.FileNotFoundException {
       /*
         *  get our properties file and load it
         */
       String propsFile = config.getInitParameter(INIT_PROPS_KEY); 
       
       java.util.Properties p = new java.util.Properties(); 
       
       if ( propsFile != null ) {
	   String realPath = getServletContext().getRealPath(propsFile);
	   if ( realPath != null ) {
                propsFile = realPath;
	   }
	   p.load( new java.io.FileInputStream(propsFile) );
       }
       /*
         *  first, normalize our velocity log file to be in the 
         *  webapp
         */
       String log = p.getProperty( Velocity.RUNTIME_LOG);
       if (log != null ) {
	   log = getServletContext().getRealPath( log );            
	   if (log != null) {
                p.setProperty( Velocity.RUNTIME_LOG, log );
	   }
       }     
       /*
         *  now, if there is a file loader resource path, treat it the
         *  same way.
         */
        String path = p.getProperty( Velocity.FILE_RESOURCE_LOADER_PATH );
        if (path != null) {
            path = getServletContext().getRealPath(path);
            if (path != null) {
                p.setProperty( Velocity.FILE_RESOURCE_LOADER_PATH, path );
            }
        }
        return p;
    }  

    /** 
     * Create and initialise the VelocityContext used by the handleRequest() method. The newly
     * created context is attached to the HTTP session.
     * @param request The current HTTP request is used to get the HTTP session object
     * @param response unnused
     */
    protected Context createContext(HttpServletRequest request, HttpServletResponse response) {
	
	VelocityContext initialContext = null;

	// get or create the HttpSession 
	HttpSession session = request.getSession(true);

	// get if exists the initialContext (a VelocityContext containing the common initialisation properties)
	initialContext = (VelocityContext)session.getAttribute("initialContext");
	if (initialContext == null) {
	    initialContext = InitVeloContext.doIt(session);
	    logger.log(BasicLevel.DEBUG, "Create initialize and attach to the session a new VelocityContext");
	} else {
	    logger.log(BasicLevel.DEBUG, "Got the initial VelocityContext from the session");
	}

	return initialContext;
	
    }

    /**
     *  <p>
     *  main routine to handle a request.  Called by
     *  VelocityServlet, your responsibility as programmer
     *  is to simply return a valid Template
     *  </p>
     *
     *  @param ctx a Velocity Context object to be filled with
     *             data.  Will be used for rendering this 
     *             template
     *  @return Template to be used for request
     */   

    public Template handleRequest(HttpServletRequest request, 
				  HttpServletResponse response, 
				  Context context ) {
	logger.log(BasicLevel.DEBUG, "Some Velocity properties :");
	logger.log(BasicLevel.DEBUG, "FILE_RESOURCE_LOADER_PATH = " + Velocity.getProperty(Velocity.FILE_RESOURCE_LOADER_PATH));
	logger.log(BasicLevel.DEBUG, "Velocimacro Library = " + Velocity.getProperty(Velocity.VM_LIBRARY));

	// Exception treatement
	String alertException = null;

	// Get Date
	String date = java.text.DateFormat.getInstance().format(new Date());
	context.put("date", date);

	// Get request parameters
	boolean list = false;
	boolean jmxList = false;
	boolean gotEjbServerParameter = false;
	boolean stopRequested = false;
	try {
	    String paramName = null;
	    //context.put("stop", new Boolean(false)); used with the META refresh	    
	    for (Enumeration paramNames = request.getParameterNames() ; paramNames.hasMoreElements() ;) {	
		paramName = (String)paramNames.nextElement();
		if (paramName.equals("list") && request.getParameter("list").equals("true")) {
		    list = true;
		} else if (paramName.equals("providerUrl")) {
		    ConnectorFactory.setJonasNamingServiceURL(request.getParameter("providerUrl"));
		} else if (paramName.equals("ejbServer")) {
		    ConnectorFactory.setCurrentRMIConnectorName(request.getParameter("ejbServer"));
		    context.put("currentRmiConnectorName", request.getParameter("ejbServer"));
		    gotEjbServerParameter = true;
		} else if (paramName.equals("stopReq")) {
		    stopRequested = true;
		    String warningMess = Script.alert("Jadmin may fail if the JOnAS server you stop is running the Tomcat service");
		    context.put("warningMess", warningMess);
		} else if (paramName.equals("stop")) {
		    //context.put("stop", new Boolean(true)); used with META refresh
		    // We save the current RMI connector name in order to restore it later:
		    String rmiConnectorNameBackup = ConnectorFactory.getCurrentRMIConnectorName();
		    // Select the server to stop:
		    ConnectorFactory.setCurrentRMIConnectorName(request.getParameter("stop"));
		    try {
			// Stop the server:
			JonasManagementRepr.invoke(JonasObjectName.ejbServer(), "stop", new Object[0], new String[0]);
		    } catch (ManagementException me) {
			// a java.rmi.UnmarshalException is thrown because the server is stopped!
			if ( (!(me.getCause() instanceof java.rmi.UnmarshalException))
			     && (!(me.getCause() instanceof java.rmi.MarshalException)) )
			    throw me;
		    }
		    // If the saved RMI connector name is the stopped server, then currentRMIConnectorName
		    // is set to null, if it is not the same, we restore the saved value:
		    if (rmiConnectorNameBackup.equals(request.getParameter("stop"))) 
			ConnectorFactory.resetCurrentRMIConnectorName();
		    else 
			ConnectorFactory.setCurrentRMIConnectorName(rmiConnectorNameBackup);
		    logger.log(BasicLevel.DEBUG, "Stop the server with parameter: " + request.getParameter("stop"));
		} else if (paramName.equals("jmxList") && request.getParameter("jmxList").equals("true")) {
                    logger.log(BasicLevel.DEBUG, "Asked to show JMX characteristics");
		    jmxList = true;
		}
	    }
	} catch (ManagementException e) {
	    alertException = Script.alert(e.getMessage());
	    context.put("alertException", alertException);
	} catch (NamingException ne) {
	    alertException = Script.alert(ne.getExplanation());
	    context.put("alertException", alertException);
	}
	context.put("list", new Boolean(list));
	context.put("jmxList", new Boolean(jmxList));

	// If list true, get the names bound in the naming context
	if (list) {
            String namingException = "";
	    Vector names = new Vector();
	    try {
		javax.naming.Context ctx = ConnectorFactory.getContext();
		for (NamingEnumeration e = ctx.list(""); e.hasMoreElements(); ) {
		    names.add (((NameClassPair)e.nextElement()).getName());
		}
	    } catch (javax.naming.NamingException ne) {
		namingException = "Cannot enumerates the names bound in the named context: " + 
			    ConnectorFactory.getJonasNamingServiceURL() +
			    " (registry probably not launched).";
	    }
	    context.put("namingException", namingException);
	    context.put("names", names);
	}

	String jonasNamingServiceURL = ConnectorFactory.getJonasNamingServiceURL();
	context.put("jonasNamingServiceURL", jonasNamingServiceURL);	

	// RMI connector names
	Set rmiConnectorNamesSet = null;
	Vector rmiConnectorNames = new Vector();
        int nbRmiConnectorNames = 0;
	String rmiConnectorNamesException = "";
	String currentRmiConnectorName = null;
  
	try {
	    rmiConnectorNamesSet = ConnectorFactory.getRMIConnectorsNames();
	    for (Iterator i = rmiConnectorNamesSet.iterator() ; i.hasNext() ;) {
		rmiConnectorNames.add((String)i.next());
		nbRmiConnectorNames++;
	    }
	} catch (javax.naming.NamingException ne) { 
	    rmiConnectorNamesException = ne.getMessage();
	} 
	currentRmiConnectorName = ConnectorFactory.getCurrentRMIConnectorName();

	context.put("rmiConnectorNames", rmiConnectorNames);
	context.put("nbRmiConnectorNames", new Integer(nbRmiConnectorNames));
	context.put("rmiConnectorNamesException", rmiConnectorNamesException);
	if (!gotEjbServerParameter)
	    context.put("currentRmiConnectorName", currentRmiConnectorName);

	// Determine if the JMS service is available
	boolean jmxMgtServiceExists = JonasManagementRepr.isRegistered(JonasObjectName.jmxService());
	context.put("jmxMgtServiceExists", new Boolean(jmxMgtServiceExists));

	// JMX service characteristics
	if (JonasManagementRepr.isRegistered(JonasObjectName.jmxService())) {
	    context.put("MBeanserverID", JonasManagementRepr.getAttribute(JonasObjectName.jmxService(), "MBeanServerId"));
	    context.put("Specification", JonasManagementRepr.getAttribute(JonasObjectName.jmxService(), "SpecificationName"));
	    context.put("SpecificationVersion", JonasManagementRepr.getAttribute(JonasObjectName.jmxService(), "SpecificationVersion"));
	    context.put("SpecificationVendor", JonasManagementRepr.getAttribute(JonasObjectName.jmxService(), "SpecificationVendor"));
	    context.put("Implementation", JonasManagementRepr.getAttribute(JonasObjectName.jmxService(), "ImplementationName"));
	    context.put("ImplementationVersion", JonasManagementRepr.getAttribute(JonasObjectName.jmxService(), "ImplementationVersion"));
	    context.put("ImplementationVendor", JonasManagementRepr.getAttribute(JonasObjectName.jmxService(), "ImplementationVendor"));
	}

	Template template = null;
	try {
	    if (stopRequested)
		template = getTemplate("MANAGEMENT_STOP.vm");
	    else
		template = getTemplate("MANAGEMENT.vm"); 
	} catch (ParseErrorException pee ) {
	    logger.log(BasicLevel.ERROR, "InitialServlet : parse error for MANAGEMENT template (" + pee + ")");
        } catch( ResourceNotFoundException rnfe ) {
            logger.log(BasicLevel.ERROR, "InitialServlet : template not found " + rnfe);
        } catch( Exception e ) {
	    logger.log(BasicLevel.ERROR, "Error " + e);
        }

	return template;
    }
}


