/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2006 Bull S.A.
 * 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.domain.cluster.ha;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import java.util.StringTokenizer;

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

import org.objectweb.util.monolog.api.BasicLevel;
import org.ow2.jonas.lib.management.domain.DomainMonitor;
import org.ow2.jonas.lib.management.domain.cluster.BaseCluster;
import org.ow2.jonas.lib.management.domain.cluster.ClusterFactory;
import org.ow2.jonas.lib.management.domain.proxy.server.ServerProxy;

/**
 * Factory for HA clusters
 * These Clusters are built dynamically, when a new server is discovered
 * as being part of a cluster of this type.
 * @author durieuxp
 */
public class EjbHaClusterFactory extends ClusterFactory {

    /**
     * List of TomcatCluster objects
     * There may be more than 1 TomcatCluster in the domain.
     * key = clusterName, value = TomcatCluster
     */
    private HashMap<String, EjbHaCluster> myclusters = new HashMap<String, EjbHaCluster>();

    /**
     * Constructor
     */
    public EjbHaClusterFactory(final DomainMonitor dm) {
        super(dm);
    }

    /**
     * Look for a cluster by its name
     * @param name for the cluster
     * @return cluster or null if not found
     */
    @Override
    public BaseCluster getCluster(final String name) {
        return myclusters.get(name);
    }

    /**
     * A new server has been discovered.
     * In case this server is recognized, it is added in a Cluster.
     * If not, nothing is done.
     * @param proxy The new ServerProxy
     * @return True if recognized as a tomcat server.
     */
    @Override
    public boolean notifyServer(final ServerProxy proxy) {

        String serverName = proxy.getServerName();
        logger.log(BasicLevel.DEBUG, serverName);

        // Determine if a HA Cluster MBean exists in the server
        // referenced by this proxy.
        ObjectName ons;
        try {
            ons = ObjectName.getInstance(domainName + ":name=HA,*");
        } catch (MalformedObjectNameException e1) {
            logger.log(BasicLevel.ERROR, "MalformedObjectNameException");
            return false;
        }
        Set<?> set = proxy.queryNames(ons);
        if (set == null) {
            logger.log(BasicLevel.DEBUG, "Cannot reach " + serverName);
            return false;
        }
        if (set.isEmpty()) {
            logger.log(BasicLevel.DEBUG, "No EjbHA Cluster with name=HA declared");
            return false;
        }
        // ObjectName = "<domain>:type=CMI,J2EEServer=<server>,name=JGroupsHA,channel=<ch>,protocol="UDP"
        ObjectName on = null;
        String protocol = null;
        for (Iterator<?> it = set.iterator(); it.hasNext(); ) {
            on = (ObjectName) it.next();
            protocol = on.getKeyProperty("protocol");
            if ("UDP".equals(protocol) || "TCP".equals(protocol)) {
                break;
            }
        }

        // Found an MBean: Get information about this cluster
        logger.log(BasicLevel.DEBUG, "Found EjbHaCluster protocol=" + protocol);
        String clusterName = on.getKeyProperty("cluster");

        // Retrieve the EjbHaCluster. Create it if necessary.
        EjbHaCluster cluster = myclusters.get(clusterName);
        if (cluster == null) {
            ObjectName clon = null;
            try {
                cluster = new EjbHaCluster(this);
                clon = cluster.setName(clusterName);
            } catch (JMException e) {
                logger.log(BasicLevel.ERROR, "Cannot create EJbHa Cluster:" + e);
                return false;
            }

            // Get additional info
            String strprop = (String) proxy.getAttribute(on, "PropertiesAsString");
            StringTokenizer stk = new StringTokenizer(strprop, "{},");
            int nb = stk.countTokens();
            for (int i = 0; i < nb; i++) {
                String str = stk.nextToken();
                int ind = str.indexOf('=', 0);
                if (ind <= 0) {
                    logger.log(BasicLevel.ERROR, "Bad property: " + str);
                }
                String key = str.substring(0, ind).trim();
                String value = str.substring(ind + 1).trim();
                logger.log(BasicLevel.DEBUG, key + "=" + value);
                if (key.equals("mcast_port")) {
                    int mcastPort = (new Integer(value)).intValue();
                    cluster.setMcastPort(mcastPort);
                }
                if (key.equals("mcast_addr")) {
                    cluster.setMcastAddr(value);
                }
                // TODO Add other parameters
            }

            // Register the MBean if not done
            if (!mbeanServer.isRegistered(clon)) {
                try {
                    // A MBean is registered for each Cluster
                    mbeanServer.registerMBean(cluster, clon);
                } catch (Exception e) {
                    logger.log(BasicLevel.ERROR, "Cannot register cluster:" + e);
                    return false;
                }
            }
            myclusters.put(clusterName, cluster);
        }

        // add a server to the cluster
        return cluster.addHaServer(serverName, proxy);
    }

    @Override
    public Collection getClusterList() {
        return myclusters.values();
    }

    /**
     * Update dynamic info for all the ha clusters.
     */
    @Override
	public void getMonitoringInfo() {
        // Not implemented.
    }
}
