Package org.apache.geronimo.gbean.jmx

Source Code of org.apache.geronimo.gbean.jmx.GBeanMBean

/**
*
* Copyright 2003-2004 The Apache Software Foundation
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/

package org.apache.geronimo.gbean.jmx;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.DynamicMBean;
import javax.management.JMException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanConstructorInfo;
import javax.management.MBeanInfo;
import javax.management.MBeanNotificationInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.ReflectionException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.geronimo.gbean.GAttributeInfo;
import org.apache.geronimo.gbean.GBeanInfo;
import org.apache.geronimo.gbean.GBeanLifecycle;
import org.apache.geronimo.gbean.GBeanLifecycleController;
import org.apache.geronimo.gbean.GConstructorInfo;
import org.apache.geronimo.gbean.GOperationInfo;
import org.apache.geronimo.gbean.GOperationSignature;
import org.apache.geronimo.gbean.GReferenceInfo;
import org.apache.geronimo.gbean.InvalidConfigurationException;
import org.apache.geronimo.gbean.GBeanData;
import org.apache.geronimo.kernel.Kernel;
import org.apache.geronimo.kernel.management.NotificationType;

/**
* A GBeanMBean is a J2EE Management Managed Object, and is standard base for Geronimo services.
* This wraps one or more target POJOs and exposes the attributes and operations according to a supplied
* {@link GBeanInfo} instance.  The GBeanMBean also supports caching of attribute values and invocation results
* which can reduce the number of calls to a target.
*
* @version $Rev: 56525 $ $Date: 2004-11-03 14:45:34 -0600 (Wed, 03 Nov 2004) $
*/
public class GBeanMBean extends AbstractManagedObject implements DynamicMBean {
    /**
     * Attribute name used to retrieve the RawInvoker for the GBean
     */
    static final String RAW_INVOKER = "$$RAW_INVOKER$$";

    /**
     * Attribute name used to retrieve the GBeanData for the GBean
     */
    public static final String GBEAN_DATA = "$$GBEAN_DATA$$";

    private static final Log log = LogFactory.getLog(GBeanMBean.class);
    private final Constructor constructor;
    private final GBeanLifecycleController gbeanLifecycleController;

    /**
     * Gets the context class loader from the thread or the system class loader if there is no context class loader.
     *
     * @return the context class loader or the system classloader
     */
    private static ClassLoader getContextClassLoader() {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        if (classLoader == null) {
            classLoader = GBeanMBean.class.getClassLoader();
        }
        return classLoader;
    }

    /**
     * Attributes lookup table
     */
    private final GBeanMBeanAttribute[] attributes;

    /**
     * Attributes supported by this GBeanMBean by (String) name.
     */
    private final Map attributeIndex = new HashMap();

    /**
     * References lookup table
     */
    private final GBeanMBeanReference[] references;

    /**
     * References supported by this GBeanMBean by (String) name.
     */
    private final Map referenceIndex = new HashMap();

    /**
     * Operations lookup table
     */
    private final GBeanMBeanOperation[] operations;

    /**
     * Operations supported by this GBeanMBean by (GOperationSignature) name.
     */
    private final Map operationIndex = new HashMap();

    /**
     * Notifications (MBeanNotificationInfo) fired by this mbean.
     */
    private final Set notifications = new HashSet();

    /**
     * The classloader used for all invocations and creating targets.
     */
    private final ClassLoader classLoader;

    /**
     * Metadata describing the attributes, operations and references of this GBean
     */
    private final GBeanInfo gbeanInfo;

    /**
     * JMX sped mbeanInfo for this gbean (translation of the above gbeanInfo
     */
    private final MBeanInfo mbeanInfo;

    /**
     * Our name
     */
    private final String name;

    /**
     * Java type of the wrapped GBean class
     */
    private final Class type;

    /**
     * Is this gbean offline?
     */
    private boolean offline = true;

    /**
     * Target instance of this GBean wrapper
     */
    private Object target;

    /**
     * A fast index based raw invoker for this GBean.
     */
    private final RawInvoker rawInvoker;

    /**
     * Constructa a GBeanMBean using the supplied GBeanData and class loader
     *
     * @param gbeanData the data for the new GBean including GBeanInfo, intial attribute values, and reference patterns
     * @param classLoader the class loader used to load the gbean instance and attribute/reference types
     * @throws InvalidConfigurationException if the gbeanInfo is inconsistent with the actual java classes, such as
     * mismatched attribute types or the intial data can not be set
     */
    public GBeanMBean(GBeanData gbeanData, ClassLoader classLoader) throws InvalidConfigurationException {
        this(gbeanData.getGBeanInfo(), classLoader);
        try {
            setGBeanData(gbeanData);
        } catch (Exception e) {
            throw new InvalidConfigurationException("GBeanData could not be loaded into the GBeanMBean", e);
        }
    }

    /**
     * Constructa a GBeanMBean using the supplied gbeanInfo and class loader
     *
     * @param gbeanInfo the metadata describing the attributes, operations, constructor and references of the gbean
     * @param classLoader the class loader used to load the gbean instance and attribute/reference types
     * @throws InvalidConfigurationException if the gbeanInfo is inconsistent with the actual java classes, such as
     * mismatched attribute types
     */
    public GBeanMBean(GBeanInfo gbeanInfo, ClassLoader classLoader) throws InvalidConfigurationException {
        this.gbeanInfo = gbeanInfo;
        this.classLoader = classLoader;
        try {
            type = classLoader.loadClass(gbeanInfo.getClassName());
        } catch (ClassNotFoundException e) {
            throw new InvalidConfigurationException("Could not load GBeanInfo class from classloader: " +
                    " className=" + gbeanInfo.getClassName());
        }

        name = gbeanInfo.getName();

        // get the constructor
        constructor = searchForConstructor(gbeanInfo, type);

        // build a map from constructor argument names to type
        Class[] constructorParameterTypes = constructor.getParameterTypes();
        Map constructorTypes = new HashMap(constructorParameterTypes.length);
        List constructorAttributeNames = this.gbeanInfo.getConstructor().getAttributeNames();
        for (int i = 0; i < constructorParameterTypes.length; i++) {
            Class type = constructorParameterTypes[i];
            constructorTypes.put(constructorAttributeNames.get(i), type);
        }

        // attributes
        Map attributesMap = new HashMap();
        for (Iterator iterator = gbeanInfo.getAttributes().iterator(); iterator.hasNext();) {
            GAttributeInfo attributeInfo = (GAttributeInfo) iterator.next();
            attributesMap.put(attributeInfo.getName(), new GBeanMBeanAttribute(this, attributeInfo, constructorTypes.containsKey(attributeInfo.getName())));
        }
        addManagedObjectAttributes(attributesMap);
        attributes = (GBeanMBeanAttribute[]) attributesMap.values().toArray(new GBeanMBeanAttribute[attributesMap.size()]);
        for (int i = 0; i < attributes.length; i++) {
            attributeIndex.put(attributes[i].getName(), new Integer(i));
        }

        // references
        Set referencesSet = new HashSet();
        for (Iterator iterator = gbeanInfo.getReferences().iterator(); iterator.hasNext();) {
            GReferenceInfo referenceInfo = (GReferenceInfo) iterator.next();
            referencesSet.add(new GBeanMBeanReference(this, referenceInfo, (Class) constructorTypes.get(referenceInfo.getName())));
        }
        references = (GBeanMBeanReference[]) referencesSet.toArray(new GBeanMBeanReference[gbeanInfo.getReferences().size()]);
        for (int i = 0; i < references.length; i++) {
            referenceIndex.put(references[i].getName(), new Integer(i));
        }

        // operations
        Map operationsMap = new HashMap();
        for (Iterator iterator = gbeanInfo.getOperations().iterator(); iterator.hasNext();) {
            GOperationInfo operationInfo = (GOperationInfo) iterator.next();
            GBeanMBeanOperation operation = new GBeanMBeanOperation(this, operationInfo);
            GOperationSignature signature = new GOperationSignature(operation.getName(), operation.getParameterTypes());
            operationsMap.put(signature, operation);
        }
        addManagedObjectOperations(operationsMap);
        operations = new GBeanMBeanOperation[operationsMap.size()];
        int opCounter = 0;
        for (Iterator iterator = operationsMap.entrySet().iterator(); iterator.hasNext();) {
            Map.Entry entry = (Map.Entry)iterator.next();
            operations[opCounter] = (GBeanMBeanOperation) entry.getValue();
            operationIndex.put(entry.getKey(), new Integer(opCounter));
            opCounter++;
        }

        // add notification type from the ManagedObject interface
        notifications.add(new MBeanNotificationInfo(NotificationType.TYPES,
                "javax.management.Notification",
                "J2EE Notifications"));

        // Build the MBeanInfo
        ArrayList mbeanAttributesList = new ArrayList(attributes.length);
        for (int i = 0; i < attributes.length; i++) {
            // only add the attributes that are readable or writable
            MBeanAttributeInfo mbeanAttributeInfo = attributes[i].getMBeanAttributeInfo();
            if (mbeanAttributeInfo != null) {
                mbeanAttributesList.add(mbeanAttributeInfo);
            }
        }
        MBeanAttributeInfo[] mbeanAttributes = (MBeanAttributeInfo[]) mbeanAttributesList.toArray(new MBeanAttributeInfo[mbeanAttributesList.size()]);

        MBeanOperationInfo[] mbeanOperations = new MBeanOperationInfo[operations.length];
        for (int i = 0; i < operations.length; i++) {
            mbeanOperations[i] = operations[i].getMbeanOperationInfo();
        }

        mbeanInfo = new MBeanInfo(gbeanInfo.getClassName(),
                null,
                mbeanAttributes,
                new MBeanConstructorInfo[0],
                mbeanOperations,
                // Is there any way to add notifications before an instance of the class is created?
                (MBeanNotificationInfo[]) notifications.toArray(new MBeanNotificationInfo[notifications.size()]));

        rawInvoker = new RawInvoker(this);

        gbeanLifecycleController = new GBeanMBeanLifecycleController(this);
    }

    /**
     * Search for a single valid constructor in the class.  A valid constructor is determined by the
     * attributes and references declared in the GBeanInfo.  For each, constructor gbean attribute
     * the parameter must have the exact same type.  For a constructor gbean reference parameter, the
     * parameter type must either match the reference proxy type, be java.util.Collection, or be
     * java.util.Set.
     *
     * @param beanInfo the metadata describing the constructor, attrbutes and references
     * @param type the target type in which we search for a constructor
     * @return the sole matching constructor
     * @throws InvalidConfigurationException if there are no valid constructors or more then one valid
     * constructors; multiple constructors can match in the case of a gbean reference parameter
     */
    private static Constructor searchForConstructor(GBeanInfo beanInfo, Class type) throws InvalidConfigurationException {
        Set attributes = beanInfo.getAttributes();
        Map attributeTypes = new HashMap(attributes.size());
        for (Iterator iterator = attributes.iterator(); iterator.hasNext();) {
            GAttributeInfo attribute = (GAttributeInfo) iterator.next();
            attributeTypes.put(attribute.getName(), attribute.getType());
        }

        Set references = beanInfo.getReferences();
        Map referenceTypes = new HashMap(references.size());
        for (Iterator iterator = references.iterator(); iterator.hasNext();) {
            GReferenceInfo reference = (GReferenceInfo) iterator.next();
            referenceTypes.put(reference.getName(), reference.getType());
        }

        List arguments = beanInfo.getConstructor().getAttributeNames();
        String[] argumentTypes = new String[arguments.size()];
        boolean[] isReference = new boolean[arguments.size()];
        for (int i = 0; i < argumentTypes.length; i++) {
            String argumentName = (String) arguments.get(i);
            if (attributeTypes.containsKey(argumentName)) {
                argumentTypes[i] = (String) attributeTypes.get(argumentName);
                isReference[i] = false;
            } else if (referenceTypes.containsKey(argumentName)) {
                argumentTypes[i] = (String) referenceTypes.get(argumentName);
                isReference[i] = true;
            }
        }

        Constructor[] constructors = type.getConstructors();
        Set validConstructors = new HashSet();
        for (int i = 0; i < constructors.length; i++) {
            Constructor constructor = constructors[i];
            if (isValidConstructor(constructor, argumentTypes, isReference)) {
                validConstructors.add(constructor);
            }
        }

        if (validConstructors.isEmpty()) {
            throw new InvalidConfigurationException("Could not find a valid constructor for GBean: " + beanInfo.getName());
        }
        if (validConstructors.size() > 1) {
            throw new InvalidConfigurationException("More then one valid constructors found for GBean: " + beanInfo.getName());
        }
        return (Constructor) validConstructors.iterator().next();
    }

    /**
     * Is this a valid constructor for the GBean.  This is determined based on the argument types and
     * if an argument is a reference, as determined by the boolean array, the argument may also be
     * java.util.Collection or java.util.Set.
     *
     * @param constructor the class constructor
     * @param argumentTypes types of the attributes and references
     * @param isReference if the argument is a gbean reference
     * @return true if this is a valid constructor for gbean; false otherwise
     */
    private static boolean isValidConstructor(Constructor constructor, String[] argumentTypes, boolean[] isReference) {
        Class[] parameterTypes = constructor.getParameterTypes();

        // same number of parameters?
        if (parameterTypes.length != argumentTypes.length) {
            return false;
        }

        // is each parameter the correct type?
        for (int i = 0; i < parameterTypes.length; i++) {
            String parameterType = parameterTypes[i].getName();
            if (isReference[i]) {
                // reference: does type match
                // OR is it a java.util.Collection
                // OR is it a java.util.Set?
                if (!parameterType.equals(argumentTypes[i]) &&
                        !parameterType.equals(Collection.class.getName()) &&
                        !parameterType.equals(Set.class.getName())) {
                    return false;
                }
            } else {
                // attribute: does type match?
                if (!parameterType.equals(argumentTypes[i])) {
                    return false;
                }
            }
        }
        return true;
    }

    public GBeanMBean(GBeanInfo beanInfo) throws InvalidConfigurationException {
        this(beanInfo, getContextClassLoader());
    }

    /**
     * "Bootstrapping" constructor.  The class specified is loaded and the static method
     * "getGBeanInfo" is called to get the gbean info.  Usually one will include
     * this static method in the class to be wrapped in the GBeanMBean instance.
     *
     * @param className name of the class to call getGBeanInfo on
     * @param classLoader the class loader for this GBean
     * @throws java.lang.Exception if an exception occurs while getting the GBeanInfo from the class
     */
    public GBeanMBean(String className, ClassLoader classLoader) throws Exception {
        this(GBeanInfo.getGBeanInfo(className, classLoader), classLoader);
    }

    /**
     * "Bootstrapping" constructor.  The class specified is loaded and the static method
     * "getGBeanInfo" is called to get the gbean info.  Usually one will include
     * this static method in the class to be wrapped in the GBeanMBean instance.
     *
     * @param className name of the class to call getGBeanInfo on
     * @throws java.lang.Exception if an exception occurs while getting the GBeanInfo from the class
     */
    public GBeanMBean(String className) throws Exception {
        this(className, ClassLoader.getSystemClassLoader());
    }

    /**
     * Gets the name of the GBean as defined in the gbean info.
     *
     * @return the gbean name
     */
    public String getName() {
        return name;
    }

    /**
     * The class loader used to build this gbean.  This class loader is set into the thread context
     * class loader before callint the target instace.
     *
     * @return the class loader used to build this gbean
     */
    public ClassLoader getClassLoader() {
        return classLoader;
    }

    /**
     * Is this gbean offline. An offline gbean is not registered with jmx and effectivly invisible
     * to external users.
     *
     * @return true if the gbean is offline
     */
    public boolean isOffline() {
        return offline;
    }

    /**
     * The java type of the wrapped gbean instance
     *
     * @return the java type of the gbean
     */
    public Class getType() {
        return type;
    }

    public Object getTarget() {
        return target;
    }

    /**
     * Gets an unmodifiable map from attribute names to index number (Integer).  This index number
     * can be used to efficiently set or retrieve an attribute value.
     *
     * @return an unmodifiable map of attribute indexes by name
     */
    public Map getAttributeIndex() {
        return Collections.unmodifiableMap(new HashMap(attributeIndex));
    }

    /**
     * Gets an unmodifiable map from operation signature (GOperationSignature) to index number (Integer).
     * This index number can be used to efficciently invoke the operation.
     *
     * @return an unmodifiable map of operation indexec by signature
     */
    public Map getOperationIndex() {
        return Collections.unmodifiableMap(new HashMap(operationIndex));
    }

    /**
     * Gets the GBeanInfo used to build this gbean.
     *
     * @return the GBeanInfo used to build this gbean
     */
    public GBeanInfo getGBeanInfo() {
        return gbeanInfo;
    }

    /**
     * Gets the MBeanInfo equivilent of the GBeanInfo used to construct this gbean.
     *
     * @return the MBeanInfo for this gbean
     */
    public MBeanInfo getMBeanInfo() {
        return mbeanInfo;
    }

    public synchronized ObjectName preRegister(MBeanServer server, ObjectName objectName) throws Exception {
        ObjectName returnValue = super.preRegister(server, objectName);

        setAttribute("objectName", getObjectName());
        setAttribute("gbeanLifecycleController", gbeanLifecycleController);
        setAttribute("classLoader", classLoader);
        try {
            String kernelName = (String) server.getAttribute(Kernel.KERNEL, "KernelName");
            Kernel kernel = Kernel.getKernel(kernelName);
            setAttribute("kernel", kernel);
        } catch (Exception e) {
            setAttribute("kernel", null);
        }

        GConstructorInfo constructorInfo = gbeanInfo.getConstructor();
        Class[] parameterTypes = constructor.getParameterTypes();

        // create parameter array
        Object[] parameters = new Object[parameterTypes.length];
        Iterator names = constructorInfo.getAttributeNames().iterator();
        for (int i = 0; i < parameters.length; i++) {
            String name = (String) names.next();
            if (attributeIndex.containsKey(name)) {
                parameters[i] = getAttribute(name);
            } else if (referenceIndex.containsKey(name)) {
                GBeanMBeanReference reference = getReferenceByName(name);
                reference.online();
                parameters[i] = reference.getProxy();
            } else {
                throw new InvalidConfigurationException("Unknown attribute or reference name in constructor: name=" + name);
            }
            assert parameters[i] == null || parameterTypes[i].isPrimitive() || parameterTypes[i].isAssignableFrom(parameters[i].getClass()):
                    "Attempting to construct " + objectName + " of type " + gbeanInfo.getClassName()
                    + ". Constructor parameter " + i + " should be " + parameterTypes[i].getName()
                    + " but is " + parameters[i].getClass().getName();
        }

        // create instance
        try {
            target = constructor.newInstance(parameters);
        } catch (InvocationTargetException e) {
            Throwable targetException = e.getTargetException();
            if (targetException instanceof Exception) {
                throw (Exception) targetException;
            } else if (targetException instanceof Error) {
                throw (Error) targetException;
            }
            throw e;
        } catch (IllegalArgumentException e) {
            log.warn("Constructor mismatch for " + returnValue, e);
            throw e;
        }

        // bring all of the attributes online; this causes the persistent
        // values to be set into the instance if it is not a constructor arg
        for (int i = 0; i < attributes.length; i++) {
            attributes[i].online();
        }

        // bring any reference not used in the constructor online; this causes
        // the proxy to be set into the intstance
        for (int i = 0; i < references.length; i++) {
            GBeanMBeanReference reference = references[i];
            if (!constructorInfo.getAttributeNames().contains(reference.getName())) {
                reference.online();
            }
        }

        return returnValue;
    }

    public void postRegister(Boolean registrationDone) {
        super.postRegister(registrationDone);

        if (registrationDone.booleanValue()) {
            // we're now offically on line
            offline = false;
        } else {
            // we need to bring the reference back off line
            for (int i = 0; i < references.length; i++) {
                references[i].offline();
            }

            // well that didn't work, ditch the instance
            target = null;
        }
    }

    public void postDeregister() {
        // take all of the attributes offline
        for (int i = 0; i < attributes.length; i++) {
            attributes[i].offline();
        }

        // take all of the reference offline
        for (int i = 0; i < references.length; i++) {
            references[i].offline();
        }

        offline = true;
        target = null;

        super.postDeregister();
    }

    protected void doStart() throws Exception {
        // start all of the references
        for (int i = 0; i < references.length; i++) {
            references[i].start();
        }

        if (target instanceof GBeanLifecycle) {
            ((GBeanLifecycle) target).doStart();
        }
    }

    protected void doStop() throws Exception {
        if (target instanceof GBeanLifecycle) {
            ((GBeanLifecycle) target).doStop();
        }

        // stop all of the references
        for (int i = 0; i < references.length; i++) {
            references[i].stop();
        }
    }

    protected void doFail() {
        if (target instanceof GBeanLifecycle) {
            ((GBeanLifecycle) target).doFail();
        }

        // stop all of the references
        for (int i = 0; i < references.length; i++) {
            references[i].stop();
        }
    }

    /**
     * Gets the attribute value using the attribute index.  This is the most efficient way to get
     * an attribute as it avoids a HashMap lookup.
     *
     * @param index the index of the attribute
     * @return the attribute value
     * @throws ReflectionException if a problem occurs while getting the value
     * @throws IndexOutOfBoundsException if the index is invalid
     */
    public Object getAttribute(int index) throws ReflectionException {
        GBeanMBeanAttribute attribute = attributes[index];
        return attribute.getValue();
    }

    /**
     * Gets an attribute's value by name.  This get style is less efficient becuse the attribute must
     * first be looked up in a HashMap.
     *
     * @param attributeName the name of the attribute to retrieve
     * @return the attribute value
     * @throws ReflectionException if a problem occurs while getting the value
     * @throws AttributeNotFoundException if the attribute name is not found in the map
     */
    public Object getAttribute(String attributeName) throws ReflectionException, AttributeNotFoundException {
        try {
            return getAttributeByName(attributeName).getValue();
        } catch (AttributeNotFoundException e) {
            if (attributeName.equals(RAW_INVOKER)) {
                return rawInvoker;
            }

            if (attributeName.equals(GBEAN_DATA)) {
                return getGBeanData();

            }

            throw e;
        }
    }

    /**
     * Gets the gbean data for the gbean held by this gbean mbean.
     * @return the gbean data
     */
    public GBeanData getGBeanData() {
        GBeanData gbeanData = new GBeanData(objectName, gbeanInfo);

        // add the attributes
        for (int i = 0; i < attributes.length; i++) {
            GBeanMBeanAttribute attribute = attributes[i];
            if (attribute.isPersistent()) {
                String name = attribute.getName();
                Object value = attribute.getPersistentValue();
                gbeanData.setAttribute(name, value);
            }
        }

        // add the references
        for (int i = 0; i < references.length; i++) {
            GBeanMBeanReference reference = references[i];
            String name = reference.getName();
            Set patterns = reference.getPatterns();
            gbeanData.setReferencePatterns(name, patterns);
        }
        return gbeanData;
    }

    public void setGBeanData(GBeanData gbeanData) throws ReflectionException, AttributeNotFoundException {
        // set the attributes
        Map attributes = gbeanData.getAttributes();
        for (Iterator iterator = attributes.entrySet().iterator(); iterator.hasNext();) {
            Map.Entry entry = (Map.Entry) iterator.next();
            String name = (String) entry.getKey();
            Object value = entry.getValue();
            setAttribute(name, value);
        }

        // add the references
        Map references = gbeanData.getReferences();
        for (Iterator iterator = references.entrySet().iterator(); iterator.hasNext();) {
            Map.Entry entry = (Map.Entry) iterator.next();
            String name = (String) entry.getKey();
            Set patterns = (Set) entry.getValue();
            setReferencePatterns(name, patterns);
        }
    }

    /**
     * Sets the attribute value using the attribute index.  This is the most efficient way to set
     * an attribute as it avoids a HashMap lookup.
     *
     * @param index the index of the attribute
     * @param value the new value of attribute value
     * @throws ReflectionException if a problem occurs while setting the value
     * @throws IndexOutOfBoundsException if the index is invalid
     */
    public void setAttribute(int index, Object value) throws ReflectionException, IndexOutOfBoundsException {
        GBeanMBeanAttribute attribute = attributes[index];
        attribute.setValue(value);
    }

    /**
     * Sets an attribute's value by name.  This set style is less efficient becuse the attribute must
     * first be looked up in a HashMap.
     *
     * @param attributeName the name of the attribute to retrieve
     * @param value the new attribute value
     * @throws ReflectionException if a problem occurs while getting the value
     * @throws AttributeNotFoundException if the attribute name is not found in the map
     */
    public void setAttribute(String attributeName, Object value) throws ReflectionException, AttributeNotFoundException {
        GBeanMBeanAttribute attribute = getAttributeByName(attributeName);
        attribute.setValue(value);
    }

    /**
     * Sets an attirubte's value by name.  This set style is generally very inefficient becuse the attribute object
     * is usually constructed first and the target attribute must be looked up in a HashMap.
     *
     * @param attributeValue the attribute object, which contains a name and value
     * @throws ReflectionException if a problem occurs while getting the value
     * @throws AttributeNotFoundException if the attribute name is not found in the map
     */
    public void setAttribute(Attribute attributeValue) throws ReflectionException, AttributeNotFoundException {
        GBeanMBeanAttribute attribute = getAttributeByName(attributeValue.getName());
        attribute.setValue(attributeValue.getValue());
    }

    /**
     * Gets several attirubte values by name.  This set style is very inefficient becuse each attribute implementation
     * must be looked up in a HashMap by name and each value must be wrapped in an Attribute object and that requires
     * lots of object creation.  Further, any exceptions are not seen by the caller.
     *
     * @param attributes the attribute objects, which contains a name and value
     */
    public AttributeList getAttributes(String[] attributes) {
        AttributeList results = new AttributeList(attributes.length);
        for (int i = 0; i < attributes.length; i++) {
            String name = attributes[i];
            try {
                Object value = getAttribute(name);
                results.add(new Attribute(name, value));
            } catch (JMException e) {
                log.warn("Exception while getting attribute " + name, e);
            }
        }
        return results;
    }

    /**
     * Sets several attirubte values by name.  This set style is generally very inefficient becuse each attribute object
     * is usually constructed first and the target attribute must be looked up in a HashMap.  Further
     * any exception are not seen by the caller.
     *
     * @param attributes the attribute objects, which contains a name and value
     */
    public AttributeList setAttributes(AttributeList attributes) {
        AttributeList results = new AttributeList(attributes.size());
        for (Iterator iterator = attributes.iterator(); iterator.hasNext();) {
            Attribute attribute = (Attribute) iterator.next();
            try {
                setAttribute(attribute);
                results.add(attribute);
            } catch (JMException e) {
                log.warn("Exception while setting attribute " + attribute.getName(), e);
            }
        }
        return results;
    }

    private GBeanMBeanAttribute getAttributeByName(String name) throws AttributeNotFoundException {
        Integer index = (Integer) attributeIndex.get(name);
        if (index == null) {
            throw new AttributeNotFoundException("Unknown attribute " + name);
        }
        GBeanMBeanAttribute attribute = attributes[index.intValue()];
        return attribute;
    }

    public Object invoke(int index, Object[] arguments) throws ReflectionException {
        GBeanMBeanOperation operation = operations[index];
        return operation.invoke(arguments);
    }

    /**
     * Invokes an operation on the target gbean by method signature.  This style if invocation is
     * inefficient, because the target method must be looked up in a hashmap using a freshly constructed
     * GOperationSignature object.
     *
     * @param operationName the name of the operation to invoke
     * @param arguments arguments to the operation
     * @param types types of the operation arguemtns
     * @return the result of the operation
     * @throws ReflectionException if a problem occurs while invokeing the operation
     */
    public Object invoke(String operationName, Object[] arguments, String[] types) throws ReflectionException {
        GOperationSignature signature = new GOperationSignature(operationName, types);
        Integer index = (Integer) operationIndex.get(signature);
        if (index == null) {
            throw new ReflectionException(new NoSuchMethodException("Unknown operation " + signature));
        }
        GBeanMBeanOperation operation = operations[index.intValue()];
        return operation.invoke(arguments);
    }

    /**
     * Gets the object name patters for a reference.
     *
     * @param name the reference name
     * @return the object name patterns for the reference
     */
    public Set getReferencePatterns(String name) {
        return getReferenceByName(name).getPatterns();
    }

    /**
     * Sets a single object name pattern for a reference.
     *
     * @param name the reference name
     * @param pattern the new single object name pattern for the reference
     */
    public void setReferencePattern(String name, ObjectName pattern) {
        getReferenceByName(name).setPatterns(Collections.singleton(pattern));
    }

    /**
     * Sets the object name patterns for a reference.
     *
     * @param name the reference name
     * @param patterns the new object name patterns for the reference
     */
    public void setReferencePatterns(String name, Set patterns) {
        getReferenceByName(name).setPatterns(patterns);
    }

    private GBeanMBeanReference getReferenceByName(String name) {
        Integer index = (Integer) referenceIndex.get(name);
        if (index == null) {
            throw new IllegalArgumentException("Unknown reference " + name);
        }
        GBeanMBeanReference reference = references[index.intValue()];
        return reference;
    }

    public MBeanNotificationInfo[] getNotificationInfo() {
        return mbeanInfo.getNotifications();
    }

    private void addManagedObjectAttributes(Map attributesMap) {
        //
        //  Special attributes
        //
        attributesMap.put("objectName",
                new GBeanMBeanAttribute((GBeanMBeanAttribute) attributesMap.get("objectName"),
                        this,
                        "objectName",
                        String.class,
                        new MethodInvoker() {
                            public Object invoke(Object target, Object[] arguments) throws Exception {
                                return getObjectName();
                            }
                        }));

        attributesMap.put("gbeanInfo",
                new GBeanMBeanAttribute((GBeanMBeanAttribute) attributesMap.get("gbeanInfo"),
                        this,
                        "gbeanInfo",
                        GBeanInfo.class,
                        new MethodInvoker() {
                            public Object invoke(Object target, Object[] arguments) throws Exception {
                                return getGBeanInfo();
                            }
                        }));

        attributesMap.put("classLoader",
                new GBeanMBeanAttribute((GBeanMBeanAttribute) attributesMap.get("classLoader"),
                        this,
                        "classLoader",
                        ClassLoader.class,
                        null));

        attributesMap.put("gbeanLifecycleController",
                new GBeanMBeanAttribute((GBeanMBeanAttribute) attributesMap.get("gbeanLifecycleController"),
                        this,
                        "gbeanLifecycleController",
                        GBeanLifecycleController.class,
                        null));

        attributesMap.put("kernel",
                new GBeanMBeanAttribute((GBeanMBeanAttribute) attributesMap.get("kernel"),
                        this,
                        "kernel",
                        Kernel.class,
                        null));

        attributesMap.put("gbeanEnabled",
                new GBeanMBeanAttribute(this,
                        "gbeanEnabled",
                        Boolean.TYPE,
                        new MethodInvoker() {
                            public Object invoke(Object target, Object[] arguments) throws Exception {
                                return new Boolean(isEnabled());
                            }
                        },
                        new MethodInvoker() {
                            public Object invoke(Object target, Object[] arguments) throws Exception {
                                Boolean enabled = (Boolean) arguments[0];
                                setEnabled(enabled.booleanValue());
                                return null;
                            }
                        },
                        true,
                        Boolean.TRUE));

        //
        // Normal attributes
        //
        attributesMap.put("state",
                new GBeanMBeanAttribute(this,
                        "state",
                        Integer.TYPE,
                        new MethodInvoker() {
                            public Object invoke(Object target, Object[] arguments) throws Exception {
                                return new Integer(getState());
                            }
                        },
                        null));

        attributesMap.put("startTime",
                new GBeanMBeanAttribute(this,
                        "startTime",
                        Long.TYPE,
                        new MethodInvoker() {
                            public Object invoke(Object target, Object[] arguments) throws Exception {
                                return new Long(getStartTime());
                            }
                        },
                        null));

        attributesMap.put("stateManageable",
                new GBeanMBeanAttribute(this,
                        "stateManageable",
                        Boolean.TYPE,
                        new MethodInvoker() {
                            public Object invoke(Object target, Object[] arguments) throws Exception {
                                return new Boolean(isStateManageable());
                            }
                        },
                        null));

        attributesMap.put("statisticsProvider",
                new GBeanMBeanAttribute(this,
                        "statisticsProvider",
                        Boolean.TYPE,
                        new MethodInvoker() {
                            public Object invoke(Object target, Object[] arguments) throws Exception {
                                return new Boolean(isStatisticsProvider());
                            }
                        },
                        null));


        attributesMap.put("eventProvider",
                new GBeanMBeanAttribute(this,
                        "eventProvider",
                        Boolean.TYPE,
                        new MethodInvoker() {
                            public Object invoke(Object target, Object[] arguments) throws Exception {
                                return new Boolean(isEventProvider());
                            }
                        },
                        null));
    }

    private void addManagedObjectOperations(Map operationsMap) {
        operationsMap.put(new GOperationSignature("start", Collections.EMPTY_LIST),
                new GBeanMBeanOperation(this,
                "start",
                Collections.EMPTY_LIST,
                Void.TYPE,
                new MethodInvoker() {
                    public Object invoke(Object target, Object[] arguments) throws Exception {
                        start();
                        return null;
                    }
                }));

        operationsMap.put(new GOperationSignature("startRecursive", Collections.EMPTY_LIST),
                new GBeanMBeanOperation(this,
                "startRecursive",
                Collections.EMPTY_LIST,
                Void.TYPE,
                new MethodInvoker() {
                    public Object invoke(Object target, Object[] arguments) throws Exception {
                        startRecursive();
                        return null;
                    }
                }));

        operationsMap.put(new GOperationSignature("stop", Collections.EMPTY_LIST),
                new GBeanMBeanOperation(this,
                "stop",
                Collections.EMPTY_LIST,
                Void.TYPE,
                new MethodInvoker() {
                    public Object invoke(Object target, Object[] arguments) throws Exception {
                        stop();
                        return null;
                    }
                }));
    }
}
TOP

Related Classes of org.apache.geronimo.gbean.jmx.GBeanMBean

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.