All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jolokia.support.jmx.JolokiaMBeanServerHandler Maven / Gradle / Ivy

There is a newer version: 2.1.1
Show newest version
package org.jolokia.support.jmx;

/*
 * Copyright 2009-2013 Roland Huss
 *
 * 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.
 */

import java.lang.management.ManagementFactory;
import java.lang.reflect.*;
import java.util.HashSet;
import java.util.Set;

import javax.management.*;
import javax.management.modelmbean.ModelMBean;

import org.jolokia.server.core.service.serializer.*;

/**
 * Dedicate MBeanServer for registering Jolokia-only MBeans
 *
 * @author roland
 * @since 11.01.13
 */
class JolokiaMBeanServerHandler implements InvocationHandler {

    private final MBeanServer mBeanServer;
    // MBeanServer to delegate to for JsonMBeans
    private MBeanServer     delegateServer;
    private Set delegatedMBeans;

    private Serializer serializer;

    /**
     * Create a private MBean server
     */
    public JolokiaMBeanServerHandler(Serializer pSerializer) {
        mBeanServer = MBeanServerFactory.newMBeanServer();
        delegatedMBeans = new HashSet();
        delegateServer = ManagementFactory.getPlatformMBeanServer();
        serializer = pSerializer;
    }

    /** {@inheritDoc} */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String name = method.getName();
        if ("registerMBean".equals(name)) {
            return registerMBean(args[0], (ObjectName) args[1]);
        } else if ("unregisterMBean".equals(name)) {
            unregisterMBean((ObjectName) args[0]);
            return null;
        } else {
            try {
                return method.invoke(mBeanServer,args);
            } catch (InvocationTargetException exp) {
                throw exp.getCause();
            }
        }
    }

    private ObjectInstance registerMBean(Object object, ObjectName name)
            throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException {
        // Register MBean first on this MBean Server
        ObjectInstance ret = mBeanServer.registerMBean(object, name);

        // Check, whether it is annotated with @JsonMBean. Only the outermost class of an inheritance chain is
        // considered.
        JsonMBean anno = extractJsonMBeanAnnotation(object);
        if (anno != null) {
            // The real name can be different than the given one in case the default
            // domain was omitted and/or the MBean implements MBeanRegistration
            ObjectName realName = ret.getObjectName();

            try {
                // Fetch real MBeanInfo and create a dynamic MBean with modified signature
                MBeanInfo info = mBeanServer.getMBeanInfo(realName);
                JsonDynamicMBeanImpl mbean = new JsonDynamicMBeanImpl(mBeanServer,realName,info,serializer,
                                                                      getJsonConverterOptions(anno));

                // Register MBean on delegate MBeanServer
                delegatedMBeans.add(realName);
                delegateServer.registerMBean(mbean,realName);
            } catch (InstanceNotFoundException e) {
                throw new MBeanRegistrationException(e,"Cannot obtain MBeanInfo from Jolokia-Server for " + realName);
            } catch (IntrospectionException e) {
                throw new MBeanRegistrationException(e,"Cannot obtain MBeanInfo from Jolokia-Server for " + realName);
            } catch (ReflectionException e) {
                throw new MBeanRegistrationException(e,"Cannot obtain MBeanInfo from Jolokia-Server for " + realName);
            }
        }
        return ret;
    }

    private void unregisterMBean(ObjectName name) throws InstanceNotFoundException, MBeanRegistrationException {
        mBeanServer.unregisterMBean(name);
        if (delegatedMBeans.contains(name)) {
            delegatedMBeans.remove(name);
            delegateServer.unregisterMBean(name);
        }
    }

    // Lookup a JsonMBean annotation
    private JsonMBean extractJsonMBeanAnnotation(Object object) {
        // Try directly
        Class clazz = object.getClass();
        JsonMBean anno =  clazz.getAnnotation(JsonMBean.class);
        if (anno == null && ModelMBean.class.isAssignableFrom(object.getClass())) {
            // For ModelMBean we try some heuristic to get to the managed resource
            // This works for all subclasses of RequiredModelMBean as provided by the JDK
            // but maybe for other ModelMBean classes as well
            Boolean isAccessible = null;
            Field field = null;
            try {
                field = findField(clazz, "managedResource");
                if (field != null) {
                    isAccessible = field.isAccessible();
                    field.setAccessible(true);
                    Object managedResource = field.get(object);
                    anno = managedResource.getClass().getAnnotation(JsonMBean.class);
                }
            } catch (IllegalAccessException e) {
                // Ignored silently, but we tried it at least
            } finally {
                if (isAccessible != null) {
                    field.setAccessible(isAccessible);
                }
            }
        }
        return anno;
    }

    // Find a field in an inheritance hierarchy
    private Field findField(Class pClazz, String pField) {
        Class c = pClazz;
        do {
            try {
                return c.getDeclaredField(pField);
            } catch (NoSuchFieldException e) {
                c = pClazz.getSuperclass();
            }
        } while (c != null);
        return null;
    }

    // Extract convert options from annotation
    private SerializeOptions getJsonConverterOptions(JsonMBean pAnno) {
        // Extract conversion options from the annotation
        if (pAnno == null) {
            return SerializeOptions.DEFAULT;
        } else {
            ValueFaultHandler faultHandler =
                    pAnno.faultHandling() == JsonMBean.FaultHandler.IGNORE_ERRORS ?
                            ValueFaultHandler.IGNORING_VALUE_FAULT_HANDLER :
                            ValueFaultHandler.THROWING_VALUE_FAULT_HANDLER;
            return new SerializeOptions.Builder()
                    .maxCollectionSize(pAnno.maxCollectionSize())
                    .maxDepth(pAnno.maxDepth())
                    .maxObjects(pAnno.maxObjects())
                    .faultHandler(faultHandler)
                    .build();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy