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

//import java
import java.io.IOException;
import java.io.PrintWriter;
import java.net.MalformedURLException;

import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.j2ee.Management;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * This servlet is an example which shows how to access the MEJB from a servlet.
 * @author JOnAS team
 * @author Adriana Danes
 */
public class NewServerMgmtServlet extends J2eemanagementBaseServlet {

    // ---------------------------------------------------------- Constants
    /** Parameter */
    static final String PARAM_DOMAIN = "domainName";
    /** Parameter */
    static final String PARAM_CLUSTER = "clusterName";
    /** Parameter */
    static final String PARAM_SERVER = "serverName";
    /** Parameter */
    static final String PARAM_SERVER_URL = "serverURL";
    /** Parameter */
    static final String PARAM_VIEW = "view";
    /** Parameter */
    static final String VIEW_INIT = "init";
    // ---------------------------------------------------------- Public methods

    /**
     * Initialize the servlet.
     * @param pConfig See HttpServlet
     * @throws ServletException
     */
    public void init(ServletConfig pConfig) throws ServletException {
        super.init(pConfig);
    }

    // ---------------------------------------------------------- Protected
    // methods

    /**
     * Response to the GET request.
     * @param pRequest See HttpServlet
     * @param pResponse See HttpServlet
     * @throws IOException
     * @throws ServletException
     */
    protected void doGet(HttpServletRequest pRequest, HttpServletResponse pResponse) throws IOException,
    ServletException {
        dispatch(pRequest, pResponse);
    }

    /**
     * Response to the POST request.
     * @param pRequest See HttpServlet
     * @param pResponse See HttpServlet
     * @throws IOException
     * @throws ServletException
     */
    protected void doPost(HttpServletRequest pRequest, HttpServletResponse pResponse) throws IOException,
    ServletException {
        dispatch(pRequest, pResponse);
    }

    /**
     * Dispatch the response.
     * @param pRequest Request
     * @param pResponse Response
     * @throws IOException
     */
    protected void dispatch(HttpServletRequest pRequest, HttpServletResponse pResponse) throws IOException {

        pResponse.setContentType("text/html");
        PrintWriter out = pResponse.getWriter();

        // Get parameters
        String sParamDomain = pRequest.getParameter(PARAM_DOMAIN);
        String sParamCluster = pRequest.getParameter(PARAM_CLUSTER);
        String sParamView = pRequest.getParameter(PARAM_VIEW);
        String sParamServer = pRequest.getParameter(PARAM_SERVER);
        String sParamServerURL = pRequest.getParameter(PARAM_SERVER_URL);

        // Dispatching
        if ((sParamDomain == null) || (sParamDomain.length() == 0)) {
            doViewError("Parameter <i>Domain name</i> not found", pRequest, out);
        } else if ((sParamCluster == null) || (sParamCluster.length() == 0)) {
            doViewError("Parameter <i>Cluster name</i> not found", pRequest, out);
        } else if ((sParamServer == null) || (sParamServer.length() == 0)) {
            doViewError("Parameter <i>Server name</i> not found", pRequest, out);
        } else if ((sParamServerURL == null) || (sParamServerURL.length() == 0)) {
            doViewError("Parameter <i>Connector server url</i> not found", pRequest, out);
        } else if ((sParamView == null) || (sParamView.length() == 0) || VIEW_INIT.equals(sParamView)) {
            doViewInit(pRequest, out);
            doViewManagement(sParamDomain, sParamCluster, sParamServer, sParamServerURL, pRequest, out);
        } else {
            doViewError("Unknown View", pRequest, out);
        }

    }


    /**
     * Do management operations in this view.
     * @param pDomainName Name of domain to access
     * @param pClusterName Name of the cluster to manage in the domain
     * @param pServerName Name of the server to add in the domain
     * @param pServerURL Address of the server's remote JMX connector
     * @param pRequest Http request
     * @param pOut Printer
     */
    protected void doViewManagement(String pDomainName, String pClusterName, String pServerName, String pServerURL, HttpServletRequest pRequest, PrintWriter pOut) {
        Management mgmt = getMgmt();

        // ------------------------------
        // Access to the J2EEDomain MBean
        // ------------------------------
        ObjectName onDomain = accessJ2EEDomain(pDomainName, mgmt, pOut);
        if (onDomain == null) {
            return;
        }

        if (!isMaster(onDomain, mgmt, pOut)) {
            // End application
            pOut.println("<h2>Application is OK </h2>");
            // Footer
            printNavigationFooter(pRequest, pOut);
            return;
        }

        // TO DO extend interface in order to read cluster daemon name
        String clusterDaemonName = "cd";
        // Create the new server
        createServer(onDomain, pClusterName, clusterDaemonName, pServerName, pServerURL, mgmt, pOut);

        // -------------------------------------------------------------
        // Using the domain management EJB to list servers in the domain
        // -------------------------------------------------------------
        String[] serverNames = null;
        String[] serverNamesDom = null;
        String[] servers = null;
        String domainName = onDomain.getKeyProperty("name");
        try {
            pOut.println("<h2>Getting list of servers in the domain " + domainName + "</h2>");
            serverNames = (String[]) mgmt.getAttribute(onDomain, "serverNames");
            servers = (String[]) mgmt.getAttribute(onDomain, "servers");
            pOut.println("<ul>");
            for (int i = 0; i < serverNames.length; i++) {
                String name = serverNames[i];
                /*
                String[] signature = {"java.lang.String"};
                String[] params = {name};
                String state = (String) mgmt.invoke(onDomain, "getServerState", params, signature);
                pOut.println("<li>" + name + " - " + state + "</li>");*/
                pOut.println("<li>" + name + "</li>");
            }
            pOut.println("</ul>");

        } catch (Exception e) {
            pOut.println("<li>Could not get list of servers in " + domainName + "</li>" + e);
            e.printStackTrace(pOut);
            return;
        }
        // -------------------------------------------------------------
        // Using the cluster management EJBs to list servers in clusters
        // -------------------------------------------------------------
        String[] clusters = null;
        String clusterName = null;
        try {
            clusters = (String[]) mgmt.getAttribute(onDomain, "clusters");
            for (int i = 0; i < clusters.length; i++) {
                ObjectName onCluster = ObjectName.getInstance(clusters[i]);
                clusterName = onCluster.getKeyProperty("name");
                if (!domainName.equals(clusterName)) {
                    // this is a cluster created by the administrator
                    // or a physical cluster created transparently
                     pOut.println("<h2>Getting list of servers in cluster " + clusterName + "</h2>");
                     String[] signature = {"java.lang.String"};
                     String[] params = new String[1];
                     params[0] = clusterName;
                     String[] urls = null;
                     serverNames = (String[]) mgmt.invoke(onDomain, "getServerNames", params, signature);
                     pOut.println("<ul>");
                     if (serverNames.length == 0) {
                         pOut.println("<li>There are no servers.</li>");
                     }
                     for (int j = 0; j < serverNames.length; j++) {
                         String name = serverNames[j];
                         /*
                         String[] signature = {"java.lang.String"};
                         String[] params = {name};
                         String state = (String) mgmt.invoke(onCluster, "getServerState", params, signature);
                         pOut.println("<li>" + name + " - " + state + "</li>");
                         */
                         pOut.println("<li>" + name + "</li>");
                     }
                     pOut.println("</ul>");
                }
            }
        } catch (Exception e) {
            pOut.println("<li>Could not get list of servers in clusters with the MEJB. </li>" + e);
            e.printStackTrace(pOut);
            return;
        }

        pOut.println("<h2>Application is OK </h2>");

        // Footer
        printNavigationFooter(pRequest, pOut);
    }

    /**
     * Create J2EEDomain MBean's ObjectName and test if MBean registered
     * @param pDomainName the name provided by the user
     * @param mgmt MEJB
     * @param pOut output stream
     * @return true if management operation succeeded
     */
    private ObjectName accessJ2EEDomain(String pDomainName, Management mgmt, PrintWriter pOut) {
        ObjectName onDomain = null;
        pOut.println("<h2>Access the J2EEDomain MBean</h2>");
        pOut.println("<ul>");

        // Get the J2EEDomain MBean's ObjectName
        try {
            String name = pDomainName + ":j2eeType=J2EEDomain,name=" + pDomainName;
            onDomain = ObjectName.getInstance(name);
            pOut.println("<li>J2EEDomain object name created: \"" + name.toString() + "\"</li>");
        } catch (Exception e) {
            pOut.println("<li>Cannot create object name for J2EEDomain managed object: " + e + "</li>");
            pOut.println("</ul>");
            return null;
        }
        // Check that the J2EEDomain MBean registered
        try {
            boolean exists = mgmt.isRegistered(onDomain);
            if (exists) {
                pOut.println("<li>Found this J2EEDomain MBean in the current MBean server</li>");
                pOut.println("</ul>");
            } else {
                pOut.println("<li><b>Can't find this J2EEDomain MBean in the current MBean server</b></li>");
                pOut.println("</ul>");
                return null;
            }
        } catch (Exception e) {
            pOut.println("<li>Error when using this J2EEDomain MBean: " + e + "</li>");
            pOut.println("</ul>");
            return null;
        }
        return onDomain;
    }
    /**
     * Add a new server to the domain and possibly attach it to a cluster
     * @param pOnDomain J2EDomain ObjectName
     * @param pClusterName cluster name
     * @param pServerName server name
     * @param pServerURL server's JMX remote connection urls
     * @param mgmt MEJB
     * @param pOut output stream
     */
    private void createServer(ObjectName pOnDomain, String pClusterName, String pClusterDaemonName, String pServerName, String pServerURL, Management mgmt, PrintWriter pOut) {
        String domainName = pOnDomain.getDomain();
        try {
            pOut.println("<h2>Add a server named " + pServerName + " to the domain " + domainName + "</h2>");
            pOut.println("<ul>");

            String[] signature = new String[4];
            Object[] params = new Object[4];
            signature[0] = "java.lang.String";
            signature[1] = "java.lang.String";
            signature[2] = "java.lang.String";
            signature[3] = "[Ljava.lang.String;";
            params[0] = pServerName;
            params[1] = pClusterName;
            params[2] = pClusterDaemonName;
            String[] urls = new String[1];
            urls[0] = pServerURL;
            params[3] = urls;
            mgmt.invoke(pOnDomain, "addServer", params, signature);
            pOut.println("</ul>");
        } catch (Exception e) {
            pOut.println("<li>Cannot add server " + pServerName + ": " + e + "</li>");
            pOut.println("</ul>");
        }
    }
}
