/*
 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
 * This software is the proprietary information of Sun Microsystems, Inc.
 * Use is subject to license terms.
 * 
 * Copyright 2004 Sun Microsystems, Inc.  Tous droits réservés.
 * Ce logiciel est propriété de Sun Microsystems, Inc.
 * Distribué par des licences qui en restreignent l'utilisation.
 *
 * ident        "@(#)MfMetric.java 1.9     04/06/02 SMI"
 *
 */

package com.sun.mfwk.util.instrum;

import javax.management.*;
import java.util.logging.*;
import com.sun.mfwk.util.log.MfLogService;

/**
 * MfMetric contains the generic information for all metric types
 */

public abstract class MfMetric extends MfStatus
    implements MfMetricMBean, MBeanRegistration, NotificationListener {

    ////////////////////////////////////////////////////
    //
    // Implementation of MfMetricMBean interface
    //
    ////////////////////////////////////////////////////

    /**
     * Enables the monitoring for this instance.
     */
    public synchronized void enableMonitoring() {
	logger.entering("MfMetric", "enableMonitoring");
	if (isMonitoringEnabled())
	    return;
	monitoringEnabled = true;
	// Reset metrics
	resetMetrics();
	// Specific handler
	handleMonitoringEnabled();
    }


    /**
     * Disables the monitoring for this instance.
     */
    public synchronized void disableMonitoring() {
	logger.entering("MfMetric", "disableMonitoring");
	if (!isMonitoringEnabled())
	    return;
	monitoringEnabled = false;
	// Specific handler
	handleMonitoringDisabled();
    }

    /**
     * Check if the instrumentation is disabled for this instance.
     */
    public boolean isMonitoringEnabled() {
	return monitoringEnabled;
    }

    /**
     * Reset all the metrics.
     */
    public abstract void resetMetrics();


    ////////////////////////////////////////////////////
    //
    // Implementation of NotificationListener interface
    //
    ////////////////////////////////////////////////////

    public void handleNotification(Notification notification, Object handback) {
	logger.entering("MfMetric", "handleNotification");
	logger.finest("MfMetric -> handleNotification: Receive a notification" +
		      " of type " + notification.getType() +
		      " with the sequence number " + notification.getSequenceNumber());

	String type = notification.getType();
	ObjectName instrumMgmtName;
	try {
	    instrumMgmtName = MfObjectNameFactory.getInstrumManagementName();
	} catch(Exception e) {
	    // Should never happen!
	    logger.warning(e.toString());
	    return;
	}
	

	if (type.equals(MBeanServerNotification.REGISTRATION_NOTIFICATION)) {
	    ObjectName objName = ((MBeanServerNotification)notification).getMBeanName();
	    if (objName.equals(instrumMgmtName) && mbeanServer.isRegistered(instrumMgmtName)) {
		logger.finest(objName + " has been registered in the MBeanServer");

		// This MfMetric may have been already added 
                // if we have a set of register/unregister of MfInstrumManagement MBean
		// to be sure, try to remove the listener
		try {
		    mbeanServer.removeNotificationListener(instrumMgmtName, this, null, null);
		} catch(Exception e) {
		    // OK, if the listener has not been yet added
		}

		// add this MfMetric MBean as a listener of MfInstrumManagement MBean
		try {
		    mbeanServer.addNotificationListener(instrumMgmtName, this, null, null);
		} catch(Exception e) {
		    // Should never happen!
		    logger.warning(e.toString());
		    return;
		}
	    }
	} else if (type.equals(AttributeChangeNotification.ATTRIBUTE_CHANGE)) {
	    String attName = ((AttributeChangeNotification)notification).getAttributeName();

	    if (attName.equals("MonitoringEnabled")) {
		enableMonitoring();
	    } else if (attName.equals("MonitoringDisabled")) {
		disableMonitoring();
	    }
	}
    }



    //////////////////////////////////////////////////
    //
    // Implementation of MBeanRegistration interface
    //
    //////////////////////////////////////////////////

    public void postDeregister() {
    }

    public void postRegister(Boolean registrationDone) {
    }

    public void preDeregister()
	throws Exception {
	logger.entering("MfMetric", "preDeregister");
	try {
	    mbeanServer.removeNotificationListener(
						new ObjectName("JMImplementation:type=MBeanServerDelegate"),
						this, null, null);
        } catch(Exception e) {
	    throw e;
        }

	// remove this MfMetric MBean listener from MfInstrumManagement MBean 
	// if it has already been registered
	try {
	    ObjectName instrumMgmtName = MfObjectNameFactory.getInstrumManagementName();
	    if (mbeanServer.isRegistered(instrumMgmtName))
		mbeanServer.removeNotificationListener(instrumMgmtName, this, null, null);

	} catch(Exception e) {
	    // Should never happen!
	    logger.warning(e.toString());
	}
    }

    public ObjectName preRegister(MBeanServer server, ObjectName name)
	throws Exception {
	logger.entering("MfMetric", "preRegister");
	mbeanServer = server;
	try {
	    mbeanServer.addNotificationListener(
						new ObjectName("JMImplementation:type=MBeanServerDelegate"),
						this, null, null);
        } catch(Exception e) {
	    throw e;
        }

	// add this MfMetric MBean as a listener of MfInstrumManagement MBean 
	// if it has already been registered
	try {
	    ObjectName instrumMgmtName = MfObjectNameFactory.getInstrumManagementName();
	    if (mbeanServer.isRegistered(instrumMgmtName))
		mbeanServer.addNotificationListener(instrumMgmtName, this, null, null);

	} catch(Exception e) {
	    // Should never happen!
	    logger.warning(e.toString());
	}
	return name;
    }

    /**
     * Handle specific behaviour when the monitoring is enabled.
     */
    protected abstract void handleMonitoringEnabled();

    /**
     * Handle specific behaviour when the monitoring is disabled.
     */
    protected abstract void handleMonitoringDisabled();


    private MBeanServer mbeanServer = null;
    private boolean monitoringEnabled = true;

    private static Logger logger = MfLogService.getLogger("UtilInstrum");
}
