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

import java.util.Properties;
import java.util.Set;

import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.RuntimeErrorException;
import javax.management.RuntimeMBeanException;
import javax.management.RuntimeOperationsException;
import javax.naming.Context;

import org.objectweb.jonas.common.Log;
import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;

/**
 * Provides a management representative to be used by JMX based management applications.
 * @author Adriana Danes
 */
public class ManagementReprImpl implements ManagementRepr
{

    static private Logger logger = null;

    protected ManagementReprImpl()
    {
        logger = Log.getLogger("org.objectweb.jonas.jmx");
        if (logger.isLoggable(BasicLevel.DEBUG)) {
            logger.log(BasicLevel.DEBUG, "Management Representativ created for jonasAdmin");
        }
    }

    /**
     * @return True if the MBean is already registered in the MBean server, false otherwise or if an exception is catched.
     */
    public boolean isRegistered(ObjectName on) {
        try {
            return ConnectorFactory.getRMIConnector().isRegistered(on);
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * @param on The ObjectName of the MBean from which the attribute is to be retrieved.
     * @param attribute A String specifying the name of the attribute to be retrieve.
     * @return The value of the attribute.
     */
    public Object getAttribute(ObjectName on, String attribute)
        throws ManagementException {

        try {
            // DEBUG
            if (ConnectorFactory.getRMIConnector() == null) {
                throw new ManagementException("Null RMIConnector");
            }
            return ConnectorFactory.getRMIConnector().getAttribute(on, attribute);
        } catch (Exception e) {
            logger.log(BasicLevel.WARN, "Error while getting attribute on " + on);
            throw new ManagementException("Error while getting attribute " + attribute + " from " + on + ": "
                                              + e.getClass().getName(), e);
        }
    }

    /**
     * @param on The ObjectName of the MBean of which attribute are to be retrieved.
     * @param attributes A list of the attributes to be retrieved.
     * @return Thelist of retrieved attributes.
     */
    public AttributeList getAttributes(ObjectName on, String[] attributes)
        throws ManagementException {

        try {
            return ConnectorFactory.getRMIConnector().getAttributes(on, attributes);
        } catch (Exception e) {
            logger.log(BasicLevel.WARN, "Error while getting attributes on " + on);
            throw new ManagementException("Error while getting attributes: "
                                          + e.getClass().getName(), e);
        }
    }

        /**
         * @param on The ObjectName of the MBean within which the attribute is to be set.
         * @param attribute A String specifying the name of the attribute to be retrieve.
         * @param value The value to set to the attribute.
         */
        public void setAttribute(ObjectName on, String attribute, Object value)
            throws ManagementException {

            //Logger logger = Log.getLogger("org.objectweb.jonas.jmx");
            if(logger.isLoggable(BasicLevel.DEBUG))
                logger.log(BasicLevel.DEBUG
                           , "Set Attribute called, on " + on.toString() + " to change attribute " + attribute
                           + " value to " + (String) value.toString());
            try {
                ConnectorFactory.getRMIConnector().setAttribute(on, new Attribute(attribute, value));
            } catch (Exception e) {
                throw new ManagementException("Error while setting attribute " + attribute + ": "
                                                      + e.getClass().getName(), e);
            }
        }

    /**
     * @param on The ObjectName of the MBean of which the attribute is to be set.
     * @param attributes A list of attributes: The identification of the attribute to be set and the value it is to be set to
     * @return The list of attributes that were set, with their new values.
     */
    public AttributeList setAttributes(ObjectName on, AttributeList attributes)
        throws ManagementException {

        try {
            return ConnectorFactory.getRMIConnector().setAttributes(on, attributes);
        } catch (Exception e) {
            throw new ManagementException("Error while setting attributes: "
                                          + e.getClass().getName(), e);
        }
    }

    /**
     * @param on
     */
    public Object invoke(ObjectName on, String operation, Object[] param, String[] signature)
            throws ManagementException {

        try {
            return ConnectorFactory.getRMIConnector().invoke(on, operation, param, signature);
        }
        catch (Exception e) {
            String message = "";
            String targetExcName = null;
            Throwable exc = null;
            if (e instanceof MBeanException ||
                e instanceof ReflectionException ||
                e instanceof RuntimeMBeanException ||
                e instanceof RuntimeOperationsException ||
                e instanceof RuntimeErrorException) {

                Exception targetExc = null;
                if (e instanceof MBeanException)                {
                    targetExc = ((MBeanException) e).getTargetException();
                }
                else if (e instanceof ReflectionException) {
                    targetExc = ((ReflectionException) e).getTargetException();
                }
                else if (e instanceof RuntimeMBeanException) {
                    targetExc = ((RuntimeMBeanException) e).getTargetException();
                }
                else if (e instanceof RuntimeOperationsException) {
                    targetExc = ((RuntimeOperationsException) e).getTargetException();
                }
                else if (e instanceof RuntimeErrorException) {
                    Error atargetExc = ((RuntimeErrorException) e).getTargetError();
                    targetExc = new Exception(atargetExc.getMessage());
                }
                targetExcName = targetExc.toString();
                exc = targetExc;
            }
            else {
                exc = e;
            }
            if(logger.isLoggable(BasicLevel.DEBUG)) {
                logger.log(BasicLevel.DEBUG
                    , "Exception ----[ " + e.toString() + " while invoking operation " + operation +
                    " on MBean " + on.toString() + " ]-------");
                if (targetExcName != null) {
                    logger.log(BasicLevel.DEBUG, "-------[ Embedded error : ]-------");
                    logger.log(BasicLevel.DEBUG, "-------[ " + targetExcName + " ]-------");
                }
            }

            throw new ManagementException(message, exc);
        }
    }

        /**
         * @return A set containing the ObjectNames for the MBeans selected.
         */
        public java.util.Set queryNames(ObjectName on)
            throws ManagementException
            {
                try
                    {
                        return (java.util.Set) ConnectorFactory.getRMIConnector().queryNames(on, null);
                    }
                catch (Exception e)
                    {
                        throw new ManagementException("Error while getting MBeans names: " + e.getClass().getName()
                                                      , e);
                    }
            }

        /**
         * @return An instance of MBeanInfo allowing the retrieval of all
         * attributes and operations of this MBean.
         */
        public MBeanInfo getMBeanInfo(ObjectName name)
            throws ManagementException
            {
                try
                    {
                        return (MBeanInfo) ConnectorFactory.getRMIConnector().getMBeanInfo(name);
                    }
                catch (Exception e)
                    {
                        throw new ManagementException("Error while getting MBean info: " + e.getClass().getName()
                                                      , e);
                    }
            }

        /**
         * @return Context the current application context, create an initial context
         * if there is no current context.
         */
        public Context getContext()
            throws javax.naming.NamingException
            {
                return ConnectorFactory.getContext();
            }

        /**
         * @return String the name of the current RMI connector.
         * Return null if no RMI connector is available.
         */
        public String getCurrentRMIConnectorName()
            {
                return ConnectorFactory.getCurrentRMIConnectorName();
            }

        /**
         * Set the currentRMIConnectorName to the specified value
         */
        public void setCurrentRMIConnectorName(String name)
            throws Exception
            {
                ConnectorFactory.setCurrentRMIConnectorName(name);
            }

        /**
         * Set the currentRMIConnectorName to null
         */
        public void resetCurrentRMIConnectorName()
            {
                ConnectorFactory.resetCurrentRMIConnectorName();
            }

        /**
         * @return Set a set containning all RMI connector names available in the current context.
         */
        public Set getRMIConnectorsNames()
            throws javax.naming.NamingException
            {
                return ConnectorFactory.getRMIConnectorsNames();
            }

        /**
         * @return String the value of the PROVIDER_URL property in the current context.
         */
        public String getJonasNamingServiceURL()
            {
                return ConnectorFactory.getJonasNamingServiceURL();
            }

        /**
         * Sets  the PROVIDER_URL property to the specified value.
         */
        public void setJonasNamingServiceURL(String url)
            throws javax.naming.NamingException
            {
                ConnectorFactory.setJonasNamingServiceURL(url);
            }

        /**
         * Create a new naming context based on the given env. properties
         * @param env properties to create a new naming context
         */
        public void setNamingEnvCtx(Properties env) throws javax.naming.NamingException {
            ConnectorFactory.setNamingEnvCtx(env);
        }
}
