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.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
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.InvalidAttributeValueException;
import javax.management.JMException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanConstructorInfo;
import javax.management.MBeanException;
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.GBean;
import org.apache.geronimo.gbean.GBeanInfo;
import org.apache.geronimo.gbean.GConstructorInfo;
import org.apache.geronimo.gbean.GOperationInfo;
import org.apache.geronimo.gbean.GReferenceInfo;
import org.apache.geronimo.gbean.InvalidConfigurationException;
import org.apache.geronimo.kernel.jmx.MBeanOperationSignature;
import org.apache.geronimo.kernel.management.NotificationType;

import net.sf.cglib.reflect.FastClass;

/**
* 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 $Revision: 1.14 $ $Date: 2004/03/13 23:48:56 $
*/
public class GBeanMBean extends AbstractManagedObject implements DynamicMBean {
    public static final FastClass fastClass = FastClass.create(GBeanMBean.class);
    private static final Log log = LogFactory.getLog(GBeanMBean.class);

    /**
     * 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 = ClassLoader.getSystemClassLoader();
        }
        return classLoader;
    }

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

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

    /**
     * Operations supported by this GBeanMBean by (MBeanOperationSignature) name.
     */
    private final Map operationMap = 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;

    private final GBeanInfo gbeanInfo;
    private final MBeanInfo mbeanInfo;
    private final String name;
    private final Class type;

    private boolean offline = true;
    private Object target;

    public GBeanMBean(GBeanInfo beanInfo, ClassLoader classLoader) throws InvalidConfigurationException {
        this.gbeanInfo = beanInfo;
        this.classLoader = classLoader;
        try {
            type = classLoader.loadClass(beanInfo.getClassName());
        } catch (ClassNotFoundException e) {
            throw new InvalidConfigurationException("Could not load GBeanInfo class from classloader: " +
                    " className=" + beanInfo.getClassName());
        }

        name = beanInfo.getName();

        // attributes
        Map constructorTypes = gbeanInfo.getConstructor().getAttributeTypeMap();
        for (Iterator iterator = beanInfo.getAttributes().iterator(); iterator.hasNext();) {
            GAttributeInfo attributeInfo = (GAttributeInfo) iterator.next();
            addAttribute(new GBeanMBeanAttribute(this, attributeInfo, (Class) constructorTypes.get(attributeInfo.getName())));
        }

        // references
        for (Iterator iterator = beanInfo.getReferences().iterator(); iterator.hasNext();) {
            GReferenceInfo referenceInfo = (GReferenceInfo) iterator.next();
            addReference(new GBeanMBeanReference(this, referenceInfo, (Class) constructorTypes.get(referenceInfo.getName())));
        }

        // operations
        for (Iterator iterator = beanInfo.getOperations().iterator(); iterator.hasNext();) {
            GOperationInfo operationInfo = (GOperationInfo) iterator.next();
            addOperation(new GBeanMBeanOperation(this, operationInfo));
        }

        // add all attributes and operations from the ManagedObject interface
        addManagedObjectInterface();

        int idx;
        idx = 0;
        MBeanAttributeInfo[] mbeanAttrs = new MBeanAttributeInfo[attributeMap.size()];
        for (Iterator i = attributeMap.values().iterator(); i.hasNext();) {
            GBeanMBeanAttribute attr = (GBeanMBeanAttribute) i.next();
            mbeanAttrs[idx++] = attr.getMBeanAttributeInfo();
        }

        idx = 0;
        MBeanOperationInfo[] mbeanOps = new MBeanOperationInfo[operationMap.size()];
        for (Iterator i = operationMap.values().iterator(); i.hasNext();) {
            GBeanMBeanOperation op = (GBeanMBeanOperation) i.next();
            mbeanOps[idx++] = op.getMbeanOperationInfo();
        }

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

    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());
    }

    public String getName() {
        return name;
    }

    public ClassLoader getClassLoader() {
        return classLoader;
    }

    public boolean isOffline() {
        return offline;
    }

    public Class getType() {
        return type;
    }

    public Object getTarget() {
        return target;
    }

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


        // get the constructor
        GConstructorInfo constructorInfo = gbeanInfo.getConstructor();
        Class[] parameterTypes = (Class[]) constructorInfo.getTypes().toArray(new Class[constructorInfo.getTypes().size()]);
        Constructor constructor = type.getConstructor(parameterTypes);

        // create the instance
        Object[] parameters = new Object[parameterTypes.length];
        Iterator names = constructorInfo.getAttributeNames().iterator();
        Iterator assertedTypes = constructorInfo.getTypes().iterator();
        for (int i = 0; i < parameters.length; i++) {
            String name = (String) names.next();
            if (attributeMap.containsKey(name)) {
                parameters[i] = getAttribute(name);
            } else if (referenceMap.containsKey(name)) {
                GBeanMBeanReference reference = (GBeanMBeanReference) referenceMap.get(name);
                reference.online();
                parameters[i] = reference.getProxy();
            } else {
                throw new InvalidConfigurationException("Unknown attribute or reference name in constructor: name=" + name);
            }
            Class assertedType = (Class) assertedTypes.next();
            assert parameters[i] == null || assertedType.isPrimitive() || assertedType.isAssignableFrom(parameters[i].getClass()):
                    "Attempting to construct " + objectName + " of type " + gbeanInfo.getClassName()
                    + ". Constructor parameter " + i + " should be " + assertedType.getName()
                    + " but is " + parameters[i].getClass().getName();
        }
        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
        for (Iterator iterator = attributeMap.values().iterator(); iterator.hasNext();) {
            GBeanMBeanAttribute attribute = (GBeanMBeanAttribute) iterator.next();
            attribute.online();
        }

        // bring any reference not used in the constructor online
        // @todo this code sucks, but works
        for (Iterator iterator = referenceMap.values().iterator(); iterator.hasNext();) {
            GBeanMBeanReference reference = (GBeanMBeanReference) iterator.next();
            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
            if (target instanceof GBean) {
                GBean gbean = (GBean) target;
                gbean.setGBeanContext(new GBeanMBeanContext(server, this, objectName));
            }
            offline = false;
        } else {
            // we need to bring the reference back off line
            for (Iterator iterator = referenceMap.values().iterator(); iterator.hasNext();) {
                GBeanMBeanReference reference = (GBeanMBeanReference) iterator.next();
                reference.offline();
            }

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

    public void postDeregister() {
        // take all of the attributes offline
        for (Iterator iterator = attributeMap.values().iterator(); iterator.hasNext();) {
            GBeanMBeanAttribute attribute = (GBeanMBeanAttribute) iterator.next();
            attribute.offline();
        }

        // take all of the reference offline
        for (Iterator iterator = referenceMap.values().iterator(); iterator.hasNext();) {
            GBeanMBeanReference reference = (GBeanMBeanReference) iterator.next();
            reference.offline();
        }

        if (target instanceof GBean) {
            GBean gbean = (GBean) target;
            gbean.setGBeanContext(null);
        }

        offline = true;
        target = null;

        super.postDeregister();
    }

    public GBeanInfo getGBeanInfo() {
        return gbeanInfo;
    }

    public MBeanInfo getMBeanInfo() {
        return mbeanInfo;
    }

    protected void doStart() throws Exception {
        // start all of the references
        for (Iterator iterator = referenceMap.values().iterator(); iterator.hasNext();) {
            GBeanMBeanReference reference = (GBeanMBeanReference) iterator.next();
            reference.start();
        }

        ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
        Thread.currentThread().setContextClassLoader(classLoader);
        try {
            if (target instanceof GBean) {
                ((GBean) target).doStart();
            }
        } finally {
            Thread.currentThread().setContextClassLoader(oldClassLoader);
        }
    }

    protected void doStop() throws Exception {
        ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
        Thread.currentThread().setContextClassLoader(classLoader);
        try {
            if (target instanceof GBean) {
                ((GBean) target).doStop();
            }
        } finally {
            Thread.currentThread().setContextClassLoader(oldClassLoader);
        }

        // stop all of the references
        for (Iterator iterator = referenceMap.values().iterator(); iterator.hasNext();) {
            GBeanMBeanReference reference = (GBeanMBeanReference) iterator.next();
            reference.stop();
        }
    }

    protected void doFail() {
        ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
        Thread.currentThread().setContextClassLoader(classLoader);
        try {
            if (target instanceof GBean) {
                ((GBean) target).doFail();
            }
        } finally {
            Thread.currentThread().setContextClassLoader(oldClassLoader);
        }

        // stop all of the references
        for (Iterator iterator = referenceMap.values().iterator(); iterator.hasNext();) {
            GBeanMBeanReference reference = (GBeanMBeanReference) iterator.next();
            reference.stop();
        }
    }

    public Object getAttribute(String attributeName) throws AttributeNotFoundException, MBeanException, ReflectionException {
        GBeanMBeanAttribute attribute = (GBeanMBeanAttribute) attributeMap.get(attributeName);
        if (attribute == null) {
            throw new AttributeNotFoundException("Unknown attribute " + attributeName);
        }

        return attribute.getValue();
    }

    public void setAttribute(Attribute attributeValue) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException {
        GBeanMBeanAttribute attribute = (GBeanMBeanAttribute) attributeMap.get(attributeValue.getName());
        if (attribute == null) {
            throw new AttributeNotFoundException("Unknown attribute " + attributeValue.getName());
        }

        attribute.setValue(attributeValue.getValue());
    }

    public void setAttribute(String name, Object value) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException {
        GBeanMBeanAttribute attribute = (GBeanMBeanAttribute) attributeMap.get(name);
        if (attribute == null) {
            throw new AttributeNotFoundException("Unknown attribute " + name);
        }

        attribute.setValue(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;
    }

    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;
    }

    public Object invoke(String methodName, Object[] arguments, String[] types) throws MBeanException, ReflectionException {
        MBeanOperationSignature key = new MBeanOperationSignature(methodName, types);
        Object operation = operationMap.get(key);
        if (operation == null) {
            throw new ReflectionException(new NoSuchMethodException("Unknown operation " + key));
        }


        // If this is an attribute accessor get call the getAttibute or setAttribute method
        if (operation instanceof GBeanMBeanAttribute) {
            if (arguments == null || arguments.length == 0) {
                return ((GBeanMBeanAttribute) operation).getValue();
            } else {
                ((GBeanMBeanAttribute) operation).setValue(arguments[0]);
                return null;
            }
        }

        return ((GBeanMBeanOperation) operation).invoke(arguments);
    }

    public Set getReferencePatterns(String name) {
        GBeanMBeanReference reference = (GBeanMBeanReference) referenceMap.get(name);
        if (reference == null) {
            throw new IllegalArgumentException("Unknown reference " + name);
        }
        return reference.getPatterns();
    }

    public void setReferencePatterns(String name, Set patterns) {
        GBeanMBeanReference reference = (GBeanMBeanReference) referenceMap.get(name);
        if (reference == null) {
            throw new IllegalArgumentException("Unknown reference " + name);
        }
        reference.setPatterns(patterns);
    }

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

    private void addAttribute(GBeanMBeanAttribute mbeanAttribute) {
        String attributeName = mbeanAttribute.getName();

        // add to attribute map
        attributeMap.put(attributeName, mbeanAttribute);
    }

    private void addReference(GBeanMBeanReference mbeanReference) {
        String referenceName = mbeanReference.getName();

        // add to reference map
        referenceMap.put(referenceName, mbeanReference);
    }

    private void addOperation(GBeanMBeanOperation mbeanOperation) {
        MBeanOperationSignature signature = new MBeanOperationSignature(mbeanOperation.getName(), mbeanOperation.getParameterTypes());
        operationMap.put(signature, mbeanOperation);
    }

    private void addManagedObjectInterface() {
        addAttribute(new GBeanMBeanAttribute(
                this,
                "state",
                Integer.TYPE,
                new MethodInvoker() {
                    public Object invoke(Object target, Object[] arguments) throws Exception {
                        return new Integer(getState());
                    }
                },
                null));

        addAttribute(new GBeanMBeanAttribute(
                this,
                "objectName",
                String.class,
                new MethodInvoker() {
                    public Object invoke(Object target, Object[] arguments) throws Exception {
                        return getObjectName();
                    }
                },
                null));

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

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

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


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

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

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

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

        notifications.add(new MBeanNotificationInfo(
                NotificationType.TYPES,
                "javax.management.Notification",
                "J2EE Notifications"));
    }
}
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.