/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2007-2008 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 (at your option) 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.lib.jmbeans;

import java.util.Properties;

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

import org.ow2.jonas.configuration.ConfigurationManager;
import org.ow2.jonas.jmx.JmxService;
import org.ow2.jonas.lib.management.domain.J2EEDomain;
import org.ow2.jonas.lib.management.javaee.J2eeObjectName;
import org.ow2.jonas.lib.management.reconfig.ReconfigManager;
import org.ow2.jonas.management.J2EEServerService;
import org.ow2.jonas.management.ServiceManager;
import org.ow2.jonas.properties.ServerProperties;
import org.ow2.util.log.Log;
import org.ow2.util.log.LogFactory;
import org.ow2.jonas.lib.jmbeans.log.LogManagement;
import org.ow2.jonas.lib.jmbeans.log.LogBuffer;

/**
 * Activator for the bundle which creates the basic JSR77 MBeans. Provides an
 * OSGi service to update service manager.
 * @author Adriana Danes
 * @author Francois Fornaciari
 */
public class MBeansRegistration {
    /**
     * Property for the log file configuration.
     */
    private static final String LOG_CONFIGFILE = "jonas.log.configfile";

    /**
     * Default property value for the log file.
     */
    private static final String DEF_LOG_CONFIGFILE = "trace";

    /**
     * File for log configuration.
     */
    private String logConfigFile = null;

    /**
     * Logger.
     */
    private Log logger = LogFactory.getLog(MBeansRegistration.class);

    /**
     * Jmx service instance.
     */
    private JmxService jmxService = null;

    /**
     * The management domain name.
     */
    private String domainName = null;

    /**
     * The server instance name.
     */
    private String serverName = null;

    /**
     * J2EEServer object.
     */
    private J2EEServerService j2eeServer = null;

    /**
     * ServerProperties service instance.
     */
    private ServerProperties serverProperties = null;

    /**
     * The ServiceManager reference
     */
    private ServiceManager serviceManager;

    /**
     * Configuration manager.
     */
    private ConfigurationManager configurationManager = null;

    /**
     * Start bundle.
     * @throws Exception could not start bundle.
     */
    public void start() throws Exception {
        logger.debug("Starting jonas-mbeans bundle...");

        // Get domainName and serverName from the Bootstrap service
        // Got all we need to create and register JSR77 MBeans
        try {
            domainName = serverProperties.getDomainName();
            serverName = serverProperties.getServerName();

            // set configuration info into the Log System (monolog)
            String logConfigFileName = serverProperties.getValue(LOG_CONFIGFILE, DEF_LOG_CONFIGFILE);
            org.ow2.jonas.lib.util.Log.configure(logConfigFileName);
            Properties logProperties = org.ow2.jonas.lib.util.Log.getProperties();
            logConfigFile = org.ow2.jonas.lib.util.Log.getConfigFileName();

            ((J2EEServer) j2eeServer).setServiceManager(serviceManager);
            ((J2EEServer) j2eeServer).setConfigManager(configurationManager);

            registerMBeans(serverProperties, logProperties);
        } catch (MalformedObjectNameException me) {
            logger.error("Failed to register mbeans: " + me.getMessage());
            return;
        } catch (Exception e) {
            logger.error("Failed to register mbeans" + e.getMessage());
            return;
        }
    }

    /**
     * Stop the bundle.
     * @throws Exception could not stop the bundle.
     */
    public void stop() throws Exception {
        logger.debug("Stopping jonas-mbeans bundle...");
        if (jmxService != null) {
            unregisterMBeans(domainName, serverName);
        }
    }

    /**
     * Register JSR77 MBeans.
     * @param serverProperties JONAS server properties
     * @param logProperties logging system properties
     * @throws Exception problem with some MBeans creation or registration
     */
    private void registerMBeans(final ServerProperties serverProperties, final Properties logProperties) throws Exception {
        String name = domainName + ":j2eeType=J2EEServer,name=" + serverName;
        ObjectName objectName = ObjectName.getInstance(name);
        ((J2EEServer) j2eeServer).setObjectName(objectName.toString());

        // Load the J2EEServer, J2EEDomain, JVM, WorkManager MBean descriptions
        Package p = j2eeServer.getClass().getPackage();
        jmxService.loadDescriptors(p.getName(), getClass().getClassLoader());

        // Register J2EEServer MBean
        jmxService.registerModelMBean(j2eeServer, objectName);
        logger.debug("MBeans registered: " + objectName);

        // Create and register J2EEDomain MBean
        // ------------------------------------
        ObjectName domainOn = J2eeObjectName.J2EEDomain(domainName);
        J2EEDomain domain = new J2EEDomain(domainOn.toString());
        domain.setJmxService(jmxService);
        boolean master = serverProperties.isMaster();
        domain.setMaster(master, serverName);
        jmxService.registerModelMBean(domain, domainOn);
        logger.debug("MBeans registered: " + domainOn.toString());

        // Set relation J2EEDomain -> J2EEServer
        domain.setMyJ2EEServerOn(objectName.toString());

        // Create and register JavaVM MBean
        // --------------------------------
        String jvmName = serverName; // maybe this could be another name
        objectName = J2eeObjectName.JVM(domainName, serverName, jvmName);
        JavaVm jvm = new JavaVm(objectName.toString(), serverProperties);
        jmxService.registerModelMBean(jvm, objectName);
        logger.debug("MBeans registered: " + objectName.toString());

        // Set relation J2EEServer -> JavaVM
        ((J2EEServer) j2eeServer).addJavaVM(objectName.toString());

        logger.debug("MBeans registered: " + objectName);

        // Create and register the ReconfigManager
        String nameReconfigManager = domainName + ":type=management,name=reconfigManager";
        objectName = ObjectName.getInstance(nameReconfigManager);
        ReconfigManager reconfigManager = new ReconfigManager(objectName, serverProperties);
        reconfigManager.setJmxService(jmxService);
        reconfigManager.setLogConfigFileName(logConfigFile);
        reconfigManager.setServerConfigFileName(serverProperties.getPropFileName());
        reconfigManager.addMBeanServerDelegateListener();
        jmxService.registerModelMBean(reconfigManager, objectName);
        logger.debug("MBeans registered: " + objectName.toString());

        // Create and register a MBean for the logging management
        String nameLogging = domainName + ":type=service,name=log";
        objectName = ObjectName.getInstance(nameLogging);
        LogManagement logManagement = new LogManagement();
        logManagement.setProps(logProperties);
        logManagement.setConfigFile(logConfigFile);
        jmxService.registerModelMBean(logManagement, objectName);
        logger.debug("MBeans registered: " + objectName.toString());

        String nameLogBuffer = domainName + ":type=LogBuffer,name=logBuff";
        LogBuffer logBuffer = new LogBuffer("logBuff");
        jmxService.registerMBean(logBuffer, nameLogBuffer);
    }

    /**
     * Unregister JSR77 MBeans.
     * @param domainName domain name
     * @param serverName server name
     * @throws Exception MBean unregistration problem
     */
    private void unregisterMBeans(final String domainName, final String serverName) throws Exception {
        // Unregister J2EEServer MBean
        String name = domainName + ":j2eeType=J2EEServer,name=" + serverName;
        ObjectName objectName = ObjectName.getInstance(name);
        jmxService.unregisterModelMBean(objectName);
        logger.debug("MBeans unregistered: " + objectName.toString());

        // Unregister JVM MBean
        String jvmName = serverName; // maybe this could be another name
        objectName = J2eeObjectName.JVM(domainName, serverName, jvmName);
        jmxService.unregisterModelMBean(objectName);
        logger.debug("MBeans unregistered: " + objectName.toString());

        // Unregister J2EEDomain MBean
        objectName = J2eeObjectName.J2EEDomain(domainName);
        jmxService.unregisterModelMBean(objectName);
        logger.debug("MBeans unregistered: " + objectName.toString());

        // Unregister the MBean for logging management
        String nameLogBuffer = domainName + ":type=LogBuffer,name=logBuff";
        objectName = ObjectName.getInstance(nameLogBuffer);
        jmxService.unregisterMBean(objectName);
        String nameLogging = domainName + ":type=service,name=log";
        objectName = ObjectName.getInstance(nameLogging);
        jmxService.unregisterModelMBean(objectName);
        logger.debug("MBeans unregistered: " + objectName.toString());

        // Unregister the ReconfigManager MBean
        String nameReconfigManager = domainName + ":type=management,name=reconfigManager";
        objectName = ObjectName.getInstance(nameReconfigManager);
        jmxService.unregisterModelMBean(objectName);
        logger.debug("MBeans unregistered: " + objectName.toString());
    }

    /**
     * @param jmxService the jmxService to set
     */
    public void setJmxService(final JmxService jmxService) {
        this.jmxService = jmxService;
    }

    /**
     * @param serverProperties the serverProperties to set
     */
    public void setServerProperties(final ServerProperties serverProperties) {
        this.serverProperties = serverProperties;
    }

    /**
     * @param serviceManager reference to the serviceManager
     */
    public void setServiceManager(final ServiceManager serviceManager) {
        this.serviceManager = serviceManager;
    }

    /**
     * @param j2eeServer the j2eeServer to set
     */
    public void setJ2EEServer(final J2EEServerService j2eeServer) {
        this.j2eeServer = j2eeServer;
    }

    /**
     * @param configManager the configManager to set
     */
    public void setConfigurationManager(final ConfigurationManager configManager) {
        this.configurationManager = configManager;
    }
}
