/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2008-2009 Bull S.A.S
 * Contact: jonas-team@ow2.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.ow2.jonas.lib.management.extensions.clusterdaemon;

import java.util.ArrayList;
import java.util.List;

import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;

import org.ow2.jonas.lib.management.domain.DomainMonitor;
import org.ow2.jonas.lib.management.domain.J2EEDomain;
import org.ow2.jonas.lib.management.domain.proxy.clusterd.ClusterDaemonProxy;
import org.ow2.jonas.lib.management.extensions.base.BaseManagement;
import org.ow2.jonas.lib.management.extensions.base.JonasManagementRepr;
import org.ow2.jonas.lib.util.JonasObjectName;
import org.ow2.jonas.management.extensions.base.api.ManagementException;
import org.ow2.jonas.management.extensions.clusterdaemon.api.IClusterdaemon;

/**
 * Implements clusterdaemon management functions.
 * @author Adriana Danes
 * @author Oualaa Hani
 * @author Thomas KOUASSI
 */
public class ClusterdaemonManagement extends BaseManagement implements IClusterdaemon {

    /**
     *ClusterDaemonProxy MBean attributes
     * domainName:type=ClusterDaemonProxy,name=clusterdaemonName
     */

    /**
     * Server State.
     */
    private static final String state = "State";

    /**
     * Controlled servers list.
     */

    private static final String controlledServersNames = "ControlledServersNames";

    /**
     * running State.
     */
    private static final String runningState = "RUNNING";

    /**
     * Ref. to DomainMonitor.
     */
    private DomainMonitor dm = null;

    /**
     * Constructor.
     */
    public ClusterdaemonManagement() {

        super();
        dm = J2EEDomain.getInstance().getDomainMonitor();

    }

    /**
     * Get the OperatingSystemAvailableProcessorsof a cluster Daemon Name in the
     * domain.
     * @param clusterDaemonName the cluster Daemon Name's name.
     * @return the OperatingSystemAvailableProcessors of the cluster Daemon
     */
    public String getOperatingSystemAvailableProcessors(final String clusterDaemonName) {
        ClusterDaemonProxy cdProxy = dm.findClusterDaemonProxy(clusterDaemonName);
        if (cdProxy != null) {
            return cdProxy.getOperatingSystemAvailableProcessors();
        }
        return null;

    }

    /**
     * Get the OperatingSystemName a cluster Daemon Name in the domain.
     * @param clusterDaemonName the cluster Daemon Name's name.
     * @return the operatingSystemName of the cluster Daemon
     */
    public String getOperatingSystemName(final String clusterDaemonName) {
        ClusterDaemonProxy cdProxy = dm.findClusterDaemonProxy(clusterDaemonName);
        if (cdProxy != null) {
            return cdProxy.getOperatingSystemName();
        }
        return null;
    }

    /**
     * Get the OperatingSystemVersion a cluster Daemon Name in the domain.
     * @param clusterDaemonName the cluster Daemon Name's name.
     * @return the OperatingSystemVersion of the cluster Daemon
     */
    public String getOperatingSystemVersion(final String clusterDaemonName) {
        ClusterDaemonProxy cdProxy = dm.findClusterDaemonProxy(clusterDaemonName);
        if (cdProxy != null) {
            return cdProxy.getOperatingSystemVersion();
        }
        return null;
    }

    /**
     * Get the RunTimeSpecVendor a cluster Daemon Name in the domain.
     * @param clusterDaemonName the cluster Daemon Name's name.
     * @return the RunTimeSpecVendor of the cluster Daemon
     */
    public String getRunTimeSpecVendor(final String clusterDaemonName) {
        ClusterDaemonProxy cdProxy = dm.findClusterDaemonProxy(clusterDaemonName);
        if (cdProxy != null) {
            return cdProxy.getRunTimeSpecVendor();
        }
        return null;
    }

    /**
     * Get the RunTimeSpecVersion a cluster Daemon Name in the domain.
     * @param clusterDaemonName the cluster Daemon Name's name.
     * @return the RunTimeSpecVersion of the cluster Daemon
     */
    public String getRunTimeSpecVersion(final String clusterDaemonName) {
        ClusterDaemonProxy cdProxy = dm.findClusterDaemonProxy(clusterDaemonName);
        if (cdProxy != null) {
            return cdProxy.getRunTimeSpecVersion();
        }
        return null;
    }

    /**
     * Get the RunTimeVmName a cluster Daemon Name in the domain.
     * @param clusterDaemonName the cluster Daemon Name's name.
     * @return the RunTimeVmName of the cluster Daemon
     */
    public String getRunTimeVmName(final String clusterDaemonName) {
        ClusterDaemonProxy cdProxy = dm.findClusterDaemonProxy(clusterDaemonName);
        if (cdProxy != null) {
            return cdProxy.getRunTimeVmName();
        }
        return null;
    }

    /**
     * Get the RunTimeVmVendor a cluster Daemon Name in the domain.
     * @param clusterDaemonName the cluster Daemon Name's name.
     * @return the runTimeVmVendor of the cluster Daemon
     */
    public String getRunTimeVmVendor(final String clusterDaemonName) {
        ClusterDaemonProxy cdProxy = dm.findClusterDaemonProxy(clusterDaemonName);
        if (cdProxy != null) {
            return cdProxy.getRunTimeVmVendor();
        }
        return null;
    }

    /**
     * Get the RunTimeVmVersion a cluster Daemon Name in the domain.
     * @param clusterDaemonName the cluster Daemon Name's name.
     * @return the RunTimeVmVersion of the cluster Daemon
     */
    public String getRunTimeVmVersion(final String clusterDaemonName) {
        ClusterDaemonProxy cdProxy = dm.findClusterDaemonProxy(clusterDaemonName);
        if (cdProxy != null) {
            return cdProxy.getRunTimeVmVersion();
        }
        return null;
    }

    /**
     * Get the OperatingSystemArch a cluster Daemon Name in the domain.
     * @param clusterDaemonName the cluster Daemon Name's name.
     * @return the OperatingSystem Architecture
     */
    public String getOperatingSystemArch(final String clusterDaemonName) {
        ClusterDaemonProxy cdProxy = dm.findClusterDaemonProxy(clusterDaemonName);
        if (cdProxy != null) {
            return cdProxy.getOperatingSystemArch();
        }
        return null;
    }

    /**
     * Get the vmCurrentUsedMemory a cluster Daemon Name in the domain.
     * @param clusterDaemonName the cluster Daemon Name's name. Getting remote
     *        Vm used Memory
     * @return the value of current used memory of the cluster Daemon
     */
    public String getVmCurrentUsedMemory(final String clusterDaemonName) {
        ClusterDaemonProxy cdProxy = dm.findClusterDaemonProxy(clusterDaemonName);
        if (cdProxy != null) {
            return cdProxy.getVmCurrentUsedMemory();
        }
        return null;
    }

    /**
     * Get the vmTotalMemory a cluster Daemon Name in the domain.
     * @param clusterDaemonName the cluster Daemon Name's name. Getting remote
     *        Vm Total Memory
     * @return the value of Vm Total memory of the cluster Daemon
     */
    public String getVmTotalMemory(final String clusterDaemonName) {
        ClusterDaemonProxy cdProxy = dm.findClusterDaemonProxy(clusterDaemonName);
        if (cdProxy != null) {
            return cdProxy.getVmTotalMemory();
        }
        return null;
    }

    /**
     * Getting remote Vm's Current used Heap memory.
     * @param clusterDaemonName the cluster Daemon Name's name
     * @return the value of Vm's Current used Heap memory
     */
    public String getVmCurrentUsedHeapMemory(final String clusterDaemonName) {
        ClusterDaemonProxy cdProxy = dm.findClusterDaemonProxy(clusterDaemonName);
        if (cdProxy != null) {
            return cdProxy.getVmCurrentUsedHeapMemory();
        }
        return null;
    }

    /**
     * Getting remote Vm's Current used non Heap memory.
     * @param clusterDaemonName the cluster Daemon Name's name
     * @return the value of Vm's Current used non Heap memory of the cluster
     *         Daemon
     */
    public String getVmCurrentUsedNonHeapMemory(final String clusterDaemonName) {
        ClusterDaemonProxy cdProxy = dm.findClusterDaemonProxy(clusterDaemonName);
        if (cdProxy != null) {
            return cdProxy.getVmCurrentUsedNonHeapMemory();
        }
        return null;
    }

    /**
     * Getting Operating system Current used space.
     * @param clusterDaemonName the cluster Daemon Name's name
     * @return the value of Operating system Current used space of the cluster
     *         Daemon
     */
    public String getOsCurrentUsedSpace(final String clusterDaemonName) {
        ClusterDaemonProxy cdProxy = dm.findClusterDaemonProxy(clusterDaemonName);
        if (cdProxy != null) {
            return cdProxy.getOsCurrentUsedSpace();
        }
        return null;
    }

    /**
     * Getting Operating system Total space.
     * @param clusterDaemonName the cluster Daemon Name's name
     * @return the value of Operating system Total space of the cluster Daemon
     */
    public String getOsTotalSpace(final String clusterDaemonName) {
        ClusterDaemonProxy cdProxy = dm.findClusterDaemonProxy(clusterDaemonName);
        if (cdProxy != null) {
            return cdProxy.getOsTotalSpace();
        }
        return null;
    }

    /**
     * Get the ClusterDaemonProxy MBean ObjectName for a given cluster daemon.
     * @param clusterdaemonName the name of the cluster daemon
     * @return ClusterDaemonProxy MBean ObjectName
     */
    private ObjectName getClusterdaemonOn(final String clusterdaemonName) {
        String domain = getDomainName();
        ObjectName clusterdaemonOn = null;
        try {
            clusterdaemonOn = JonasObjectName.clusterDaemonProxy(domain, clusterdaemonName);
        } catch (MalformedObjectNameException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return clusterdaemonOn;
    }

    /**
     * @param clusterdaemonName name of the cluster daemon to manage.
     * @return the state of a cluster daemon in the domain
     */
    public String getClusterdaemonState(final String clusterdaemonName) {
        ObjectName clusterdaemonOn = getClusterdaemonOn(clusterdaemonName);
        String clusterdaemonState = null;
        try {
            clusterdaemonState = (String) JonasManagementRepr.getAttribute(clusterdaemonOn, state, getServerName());
        } catch (ManagementException e) {
            logger.debug("Cannot get state for cluster daemon " + clusterdaemonName + " :" + e);
        }
        return clusterdaemonState;
    }

    /**
     * @param clusterdaemonName name of the cluster daemon to manage.
     * @return true if the cluster daemon is in RUNNING state, false otherwise
     */
    public boolean isRunning(final String clusterdaemonName) {
        boolean result = false;
        ObjectName clusterdaemonOn = getClusterdaemonOn(clusterdaemonName);
        try {
            String clusterdaemonState = (String) JonasManagementRepr.getAttribute(clusterdaemonOn, state, getServerName());
            if (runningState.equals(clusterdaemonState)) {
                result = true;
            }
        } catch (ManagementException e) {
            logger.debug("Cannot get state for cluster daemon " + clusterdaemonName + " :" + e);
        }
        return result;
    }

    /**
     * @param clusterdaemonName name of the cluster daemon to manage.
     * @return list of servers controlled by a clusterdaemon
     */
    public String[] getControlledServersNames(final String clusterdaemonName) {
        ObjectName clusterdaemonOn = getClusterdaemonOn(clusterdaemonName);
        List<String> servers = new ArrayList<String>();
        try {
            servers = (ArrayList<String>) JonasManagementRepr.getAttribute(clusterdaemonOn, controlledServersNames,
                    getServerName());
            if (servers == null) {
                return new String[0];
            }
        } catch (ManagementException e) {
            logger.debug("Cannot get controlled server names for cluster daemon " + clusterdaemonName + " :" + e);
            return null;
        }
        String[] controlledServers = new String[servers.size()];
        for (int i = 0; i < servers.size(); i++) {
            controlledServers[i] = servers.get(i);
        }
        return controlledServers;
    }

    /**
     * Start a server controlled by a cluster daemon. Use already defined start
     * parameters and configuration.
     * @param clusterdaemonName name of the cluster daemon
     * @param serverName name of the server to start
     * @return true if successfully started
     */
    public boolean startServer(final String clusterdaemonName, final String serverName) {
        ObjectName clusterdaemonOn = getClusterdaemonOn(clusterdaemonName);
        Boolean result = null;
        String opName = "startServer";
        String[] opParams = new String[2];
        String[] opSignature = {"java.lang.String", "java.lang.String"};
        /** first parameter : server name */
        opParams[0] = serverName;
        /** second parameter : extra start parameters */
        opParams[1] = null;
        try {
            result = (Boolean) JonasManagementRepr.invoke(clusterdaemonOn, opName, opParams, opSignature, getServerName());
        } catch (ManagementException e) {
            logger.debug("Cannot start server " + serverName + " by cluster daemon " + clusterdaemonName + " :" + e);
            return false;
        }
        return result.booleanValue();
    }

    /**
     * Stop a server controlled by a cluster daemon.
     * @param clusterdaemonName name of the cluster daemon
     * @param serverName name of the server to stop
     * @return true if successfully stoped
     */
    public boolean stopServer(final String clusterdaemonName, final String serverName) {
        ObjectName clusterdaemonOn = getClusterdaemonOn(clusterdaemonName);
        Boolean result = null;
        String opName = "stopServer";
        String[] opParams = new String[2];
        String[] opSignature = {"java.lang.String", "java.lang.String"};
        /** first parameter : server name */
        opParams[0] = serverName;
        /** second parameter : extra start parameters */
        opParams[1] = null;
        try {
            result = (Boolean) JonasManagementRepr.invoke(clusterdaemonOn, opName, opParams, opSignature, getServerName());
        } catch (ManagementException e) {
            logger.debug("Cannot stop server " + serverName + " by cluster daemon " + clusterdaemonName + " :" + e);
            return false;
        }
        return result.booleanValue();
    }

    /**
     * Add a server to cluster daemon control.
     * @param clusterDaemonName the cluster Daemon name
     * @param serverName the server name
     * @param description server description
     * @param javaHome path to JRE
     * @param jonasRoot path to bin repository
     * @param jonasBase path to lib repository
     * @param xprem extra parameter e.g: -Djava.net.preferIPv4Stack=true
     * @param autoBoot true if the server is launched when cluster daemon starts
     * @param jonasCmd user command
     * @param saveIt true to flush the clusterd configuration
     */
    public void addServer(final String clusterDaemonName, final String serverName, final String description,
            final String jonasRoot, final String jonasBase, final String javaHome, final String xprem, final String autoBoot,
            final String jonasCmd, final String saveIt) {
        ClusterDaemonProxy cdProxy = dm.findClusterDaemonProxy(clusterDaemonName);
        if (cdProxy != null) {
            cdProxy.addServer(serverName, description, jonasRoot, jonasBase, javaHome, xprem, autoBoot, jonasCmd, saveIt);
        }
    }

    /**
     * Add a server to cluster daemon control.
     * @param serverName the server name
     * @param description server description
     * @param javaHome path to JRE
     * @param jonasRoot path to bin repository
     * @param jonasBase path to lib repository
     * @param xprem extra parameter e.g: -Djava.net.preferIPv4Stack=true
     * @param autoBoot true if the server is launched when cluster daemon starts
     * @param saveIt true to flush the clusterd configuration
     */

    public void AddServer(final String clusterDaemonName, final String serverName, final String description,
            final String jonasRoot, final String jonasBase, final String javaHome, final String xprem, final String autoBoot,
            final String saveIt) {
        ObjectName clusterdaemonOn = getClusterdaemonOn(clusterDaemonName);
        // If all parameter are different to null
        if ((clusterdaemonOn != null)
                && (!((serverName == null) || (description == null) || (jonasRoot == null) || (jonasRoot == null)
                        || (javaHome == null) || (xprem == null) || (autoBoot == null) || (saveIt == null)))) {
            String opName = "addServer";
            String[] opParams = new String[8];
            String[] opSignature = {"java.lang.String", "java.lang.String", "java.lang.String", "java.lang.String",
                    "java.lang.String", "java.lang.String", "java.lang.String", "java.lang.String"};
            /** 1er parameter : server name */
            opParams[0] = serverName;
            /** 2eme parameter : server description */
            opParams[1] = description;
            /** 3eme parameter : server jonas Root */
            opParams[2] = jonasRoot;
            /** 4eme parameter : server jonas Base */
            opParams[3] = jonasBase;
            /** 5eme parameter : server java Home */
            opParams[4] = javaHome;
            /** 6eme parameter : server xprem */
            opParams[5] = xprem;
            /** 7eme parameter : server autoBoot */
            opParams[6] = autoBoot;
            /** 8eme parameter : server saveIt */
            opParams[7] = saveIt;
            try {
                JonasManagementRepr.invoke(clusterdaemonOn, opName, opParams, opSignature, getServerName());
            } catch (ManagementException e) {
                logger.debug("Cannot Add server named " + serverName + " to cluster daemon " + clusterDaemonName + " control :"
                        + e);
            }
        }
    }

    /**
     * Remove this server from cluster daemon control.
     * @param clusterDaemonName name of the cluster daemon
     * @param serverName the server to remove
     * @param saveIt true to flush the clusterd configuration
     */
    public void removeServer(final String clusterDaemonName, final String serverName, final String saveIt) {
        ClusterDaemonProxy cdProxy = dm.findClusterDaemonProxy(clusterDaemonName);
        if (cdProxy != null) {
            cdProxy.removeServer(serverName, saveIt);
        }
    }

    /**
     * Ask Cluster Daemon to start all the Servers from cluster daemon control.
     * @param clusterDaemonName name of the cluster daemon
     * @param otherParams the servers to start
     */
    public void startAllServers(final String clusterDaemonName, final String otherParams) {
        ClusterDaemonProxy cdProxy = dm.findClusterDaemonProxy(clusterDaemonName);
        if (cdProxy != null) {
            cdProxy.startAllServers(otherParams);
        }
    }

    /**
     * Ask Cluster Daemon to stop all the Servers from cluster daemon control.
     * @param clusterDaemonName name of the cluster daemon
     * @param otherParams the servers to stop
     */
    public void stopAllServers(final String clusterDaemonName, final String otherParams) {
        ClusterDaemonProxy cdProxy = dm.findClusterDaemonProxy(clusterDaemonName);
        if (cdProxy != null) {
            cdProxy.stopAllServers(otherParams);
        }
    }

}
