You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by kl...@apache.org on 2016/10/26 22:11:30 UTC
[08/42] incubator-geode git commit: GEODE-288: move admin package to
internal
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/096b622d/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/MX4JModelMBean.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/MX4JModelMBean.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/MX4JModelMBean.java
new file mode 100755
index 0000000..cb2152a
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/MX4JModelMBean.java
@@ -0,0 +1,1239 @@
+/*
+ * Copyright (C) MX4J.
+ * All rights reserved.
+ *
+ * This software is distributed under the terms of the MX4J License version 1.0.
+ * See the terms of the MX4J License in the documentation provided with this software.
+ */
+
+package org.apache.geode.internal.admin.api.jmx.impl;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Date;
+import java.util.Iterator;
+
+import javax.management.Attribute;
+import javax.management.AttributeChangeNotification;
+import javax.management.AttributeChangeNotificationFilter;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.Descriptor;
+import javax.management.InstanceNotFoundException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanNotificationInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanRegistration;
+import javax.management.MBeanRegistrationException;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationEmitter;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+import javax.management.RuntimeErrorException;
+import javax.management.RuntimeOperationsException;
+import javax.management.ServiceNotFoundException;
+import javax.management.loading.ClassLoaderRepository;
+import javax.management.modelmbean.InvalidTargetObjectTypeException;
+import javax.management.modelmbean.ModelMBean;
+import javax.management.modelmbean.ModelMBeanAttributeInfo;
+import javax.management.modelmbean.ModelMBeanInfo;
+import javax.management.modelmbean.ModelMBeanOperationInfo;
+
+import mx4j.ImplementationException;
+import mx4j.log.FileLogger;
+import mx4j.log.Log;
+import mx4j.log.Logger;
+import mx4j.log.MBeanLogger;
+import mx4j.persist.FilePersister;
+import mx4j.persist.MBeanPersister;
+import mx4j.persist.PersisterMBean;
+import mx4j.util.Utils;
+
+import org.apache.geode.internal.i18n.LocalizedStrings;
+
+/**
+ * @author <a href="mailto:biorn_steedom@users.sourceforge.net">Simone Bordet</a>
+ * @version $Revision: 1.14 $
+ */
+public class MX4JModelMBean implements ModelMBean, MBeanRegistration, NotificationEmitter
+{
+ private static final String OBJECT_RESOURCE_TYPE = "ObjectReference";
+
+ private static final int ALWAYS_STALE = 1;
+ private static final int NEVER_STALE = 2;
+ private static final int STALE = 3;
+ private static final int NOT_STALE = 4;
+
+ private static final int PERSIST_NEVER = -1;
+ private static final int PERSIST_ON_TIMER = -2;
+ private static final int PERSIST_ON_UPDATE = -3;
+ private static final int PERSIST_NO_MORE_OFTEN_THAN = -4;
+
+ private MBeanServer m_mbeanServer;
+ private Object m_managedResource;
+ private boolean m_canBeRegistered;
+ private ModelMBeanInfo m_modelMBeanInfo;
+ private NotificationBroadcasterSupport m_attributeChangeBroadcaster = new NotificationBroadcasterSupport();
+ private NotificationBroadcasterSupport m_generalBroadcaster = new NotificationBroadcasterSupport();
+
+ public MX4JModelMBean() throws MBeanException, RuntimeOperationsException
+ {
+ try
+ {
+ load();
+ }
+ catch (Exception x)
+ {
+ Logger logger = getLogger();
+ logger.warn(LocalizedStrings.MX4JModelMBean_CANNOT_RESTORE_PREVIOUSLY_SAVED_STATUS.toLocalizedString(), x);
+ }
+ }
+
+ public MX4JModelMBean(ModelMBeanInfo info) throws MBeanException, RuntimeOperationsException
+ {
+ if (info == null)
+ throw new RuntimeOperationsException(new IllegalArgumentException(LocalizedStrings.MX4JModelMBean_MODELMBEANINFO_PARAMETER_CANT_BE_NULL.toLocalizedString()));
+ else
+ setModelMBeanInfo(info);
+ }
+
+ private Logger getLogger()
+ {
+ return Log.getLogger(getClass().getName());
+ }
+
+ public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception
+ {
+ if (m_canBeRegistered)
+ {
+ m_mbeanServer = server;
+ return name;
+ }
+ else
+ {
+ throw new MBeanRegistrationException(new IllegalStateException(LocalizedStrings.MX4JModelMBean_MODELMBEAN_CANNOT_BE_REGISTERED_UNTIL_SETMODELMBEANINFO_HAS_BEEN_CALLED.toLocalizedString()));
+ }
+ }
+
+ public void postRegister(Boolean registrationDone)
+ {
+ if (!registrationDone.booleanValue()) clear();
+ }
+
+ public void preDeregister() throws Exception
+ {
+ }
+
+ public void postDeregister()
+ {
+ clear();
+ }
+
+ private void clear()
+ {
+ m_mbeanServer = null;
+ m_managedResource = null;
+ m_modelMBeanInfo = null;
+ m_generalBroadcaster = null;
+ m_attributeChangeBroadcaster = null;
+ // PENDING: also remove generic listeners, attribute change listeners, log4j appenders...
+ }
+
+ public void setModelMBeanInfo(ModelMBeanInfo modelMBeanInfo) throws MBeanException, RuntimeOperationsException
+ {
+ if (modelMBeanInfo == null) throw new RuntimeOperationsException(new IllegalArgumentException(LocalizedStrings.MX4JModelMBean_MODELMBEANINFO_CANNOT_BE_NULL.toLocalizedString()));
+ if (!isModelMBeanInfoValid(modelMBeanInfo)) throw new RuntimeOperationsException(new IllegalArgumentException(LocalizedStrings.MX4JModelMBean_MODELMBEANINFO_IS_INVALID.toLocalizedString()));
+
+ m_modelMBeanInfo = (ModelMBeanInfo)modelMBeanInfo.clone();
+
+ Logger logger = getLogger();
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("ModelMBeanInfo successfully set to: " + m_modelMBeanInfo);
+ // Only now the MBean can be registered in the MBeanServer
+ m_canBeRegistered = true;
+ }
+
+ private boolean isModelMBeanInfoValid(ModelMBeanInfo info)
+ {
+ if (info == null || info.getClassName() == null) return false;
+ // PENDING: maybe more checks are needed
+ return true;
+ }
+
+ public void setManagedResource(Object resource, String resourceType) throws MBeanException, RuntimeOperationsException, InstanceNotFoundException, InvalidTargetObjectTypeException
+ {
+ if (resource == null) throw new RuntimeOperationsException(new IllegalArgumentException(LocalizedStrings.MX4JModelMBean_MANAGED_RESOURCE_CANNOT_BE_NULL.toLocalizedString()));
+ if (!isResourceTypeSupported(resourceType)) throw new InvalidTargetObjectTypeException(resourceType);
+
+ Logger logger = getLogger();
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Setting managed resource to be: " + resource);
+ m_managedResource = resource;
+ }
+
+ private boolean isResourceTypeSupported(String resourceType)
+ {
+ // For now only object reference is supported
+ return OBJECT_RESOURCE_TYPE.equals(resourceType);
+ }
+
+ private Object getManagedResource()
+ {
+ return m_managedResource;
+ }
+
+ public MBeanInfo getMBeanInfo()
+ {
+ return m_modelMBeanInfo == null ? null : (MBeanInfo)m_modelMBeanInfo.clone();
+ }
+
+ public void addAttributeChangeNotificationListener(NotificationListener listener, String attributeName, Object handback) throws MBeanException, RuntimeOperationsException, IllegalArgumentException
+ {
+ if (listener == null) throw new RuntimeOperationsException(new IllegalArgumentException(LocalizedStrings.MX4JModelMBean_LISTENER_CANNOT_BE_NULL.toLocalizedString()));
+ AttributeChangeNotificationFilter filter = new AttributeChangeNotificationFilter();
+ if (attributeName != null)
+ {
+ filter.enableAttribute(attributeName);
+ }
+ else
+ {
+ MBeanAttributeInfo[] ai = m_modelMBeanInfo.getAttributes();
+ for (int i = 0; i < ai.length; i++)
+ {
+ Descriptor d = ((ModelMBeanAttributeInfo)ai[i]).getDescriptor();
+ filter.enableAttribute((String)d.getFieldValue("name"));
+ }
+ }
+
+ getAttributeChangeBroadcaster().addNotificationListener(listener, filter, handback);
+
+ Logger logger = getLogger();
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Listener " + listener + " for attribute " + attributeName + " added successfully, handback is " + handback);
+ }
+
+ public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws IllegalArgumentException
+ {
+ m_generalBroadcaster.addNotificationListener(listener, filter, handback);
+ }
+
+ public MBeanNotificationInfo[] getNotificationInfo()
+ {
+ return m_modelMBeanInfo.getNotifications();
+ }
+
+ public void removeAttributeChangeNotificationListener(NotificationListener listener, String attributeName) throws RuntimeOperationsException, ListenerNotFoundException
+ {
+ try
+ {
+ removeAttributeChangeNotificationListener(listener, attributeName, null);
+ }
+ catch (MBeanException e)
+ {
+ throw new RuntimeOperationsException(new RuntimeException(e.getMessage()));
+ }
+ }
+
+ // Not in the spec but needed
+ private void removeAttributeChangeNotificationListener(NotificationListener listener, String attributeName, Object handback) throws MBeanException, RuntimeOperationsException, ListenerNotFoundException
+ {
+ if (listener == null) throw new RuntimeOperationsException(new IllegalArgumentException(LocalizedStrings.MX4JModelMBean_LISTENER_CANNOT_BE_NULL.toLocalizedString()));
+ AttributeChangeNotificationFilter filter = new AttributeChangeNotificationFilter();
+ if (attributeName != null)
+ {
+ filter.enableAttribute(attributeName);
+ }
+ else
+ {
+ MBeanAttributeInfo[] ai = m_modelMBeanInfo.getAttributes();
+ for (int i = 0; i < ai.length; i++)
+ {
+ Descriptor d = ((ModelMBeanAttributeInfo)ai[i]).getDescriptor();
+ filter.enableAttribute((String)d.getFieldValue("name"));
+ }
+ }
+
+ getAttributeChangeBroadcaster().removeNotificationListener(listener, filter, handback);
+
+ Logger logger = getLogger();
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Listener " + listener + " for attribute " + attributeName + " removed successfully, handback is " + handback);
+ }
+
+ public void removeNotificationListener(NotificationListener listener) throws RuntimeOperationsException, ListenerNotFoundException
+ {
+ m_generalBroadcaster.removeNotificationListener(listener);
+ }
+
+ public void removeNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws RuntimeOperationsException, ListenerNotFoundException
+ {
+ m_generalBroadcaster.removeNotificationListener(listener, filter, handback);
+ }
+
+ public void sendAttributeChangeNotification(Attribute oldAttribute, Attribute newAttribute) throws MBeanException, RuntimeOperationsException
+ {
+ if (oldAttribute == null || newAttribute == null) throw new RuntimeOperationsException(new IllegalArgumentException(LocalizedStrings.MX4JModelMBean_ATTRIBUTE_CANNOT_BE_NULL.toLocalizedString()));
+ if (!oldAttribute.getName().equals(newAttribute.getName())) throw new RuntimeOperationsException(new IllegalArgumentException(LocalizedStrings.MX4JModelMBean_ATTRIBUTE_NAMES_CANNOT_BE_DIFFERENT.toLocalizedString()));
+
+ // TODO: the source must be the object name of the MBean if the listener was registered through MBeanServer
+ Object oldValue = oldAttribute.getValue();
+ AttributeChangeNotification n = new AttributeChangeNotification(this,
+ 1,
+ System.currentTimeMillis(),
+ "Attribute value changed",
+ oldAttribute.getName(),
+ oldValue == null ? null : oldValue.getClass().getName(),
+ oldValue,
+ newAttribute.getValue());
+ sendAttributeChangeNotification(n);
+ }
+
+ public void sendAttributeChangeNotification(AttributeChangeNotification notification) throws MBeanException, RuntimeOperationsException
+ {
+ if (notification == null) throw new RuntimeOperationsException(new IllegalArgumentException(LocalizedStrings.MX4JModelMBean_NOTIFICATION_CANNOT_BE_NULL.toLocalizedString()));
+
+ getAttributeChangeBroadcaster().sendNotification(notification);
+
+ Logger modelMBeanLogger = getModelMBeanLogger(notification.getType());
+ if (modelMBeanLogger != null) if (modelMBeanLogger.isEnabledFor(Logger.DEBUG)) modelMBeanLogger.debug("ModelMBean log: " + new Date() + " - " + notification);
+
+ Logger logger = getLogger();
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Attribute change notification " + notification + " sent");
+ }
+
+ public void sendNotification(String message) throws MBeanException, RuntimeOperationsException
+ {
+ Notification notification = new Notification("jmx.modelmbean.general", this, 1, message);
+ sendNotification(notification);
+ }
+
+ public void sendNotification(Notification notification) throws MBeanException, RuntimeOperationsException
+ {
+ if (m_generalBroadcaster != null) {
+ m_generalBroadcaster.sendNotification(notification);
+ }
+ }
+
+ public AttributeList getAttributes(String[] attributes)
+ {
+ if (attributes == null) throw new RuntimeOperationsException(new IllegalArgumentException(LocalizedStrings.MX4JModelMBean_ATTRIBUTE_NAMES_CANNOT_BE_NULL.toLocalizedString()));
+
+ Logger logger = getLogger();
+
+ AttributeList list = new AttributeList();
+ for (int i = 0; i < attributes.length; ++i)
+ {
+ String attrName = attributes[i];
+ Attribute attribute = null;
+ try
+ {
+ Object value = getAttribute(attrName);
+ attribute = new Attribute(attrName, value);
+ list.add(attribute);
+ }
+ catch (Exception x)
+ {
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("getAttribute for attribute " + attrName + " failed", x);
+ // And go on with the next attribute
+ }
+ }
+ return list;
+ }
+
+ public Object getAttribute(String attribute) throws AttributeNotFoundException, MBeanException, ReflectionException
+ {
+ if (attribute == null) throw new RuntimeOperationsException(new IllegalArgumentException(LocalizedStrings.MX4JModelMBean_ATTRIBUTE_NAME_CANNOT_BE_NULL.toLocalizedString()));
+
+ Logger logger = getLogger();
+
+ // I want the real info, not its clone
+ ModelMBeanInfo info = getModelMBeanInfo();
+ if (info == null) throw new AttributeNotFoundException(LocalizedStrings.MX4JModelMBean_MODELMBEANINFO_IS_NULL.toLocalizedString());
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("ModelMBeanInfo is: " + info);
+
+ // This is a clone, we use it read only
+ ModelMBeanAttributeInfo attrInfo = info.getAttribute(attribute);
+ if (attrInfo == null) throw new AttributeNotFoundException(LocalizedStrings.MX4JModelMBean_CANNOT_FIND_MODELMBEANATTRIBUTEINFO_FOR_ATTRIBUTE_0.toLocalizedString(attribute));
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Attribute info is: " + attrInfo);
+ if (!attrInfo.isReadable()) throw new AttributeNotFoundException(LocalizedStrings.MX4JModelMBean_ATTRIBUTE_0_IS_NOT_READABLE.toLocalizedString(attribute));
+
+ // This returns a clone of the mbean descriptor, we use it read only
+ Descriptor mbeanDescriptor = info.getMBeanDescriptor();
+ if (mbeanDescriptor == null) throw new AttributeNotFoundException(LocalizedStrings.MX4JModelMBean_MBEAN_DESCRIPTOR_CANNOT_BE_NULL.toLocalizedString());
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("MBean descriptor is: " + mbeanDescriptor);
+
+ // This descriptor is a clone
+ Descriptor attributeDescriptor = attrInfo.getDescriptor();
+ if (attributeDescriptor == null) throw new AttributeNotFoundException(LocalizedStrings.MX4JModelMBean_ATTRIBUTE_DESCRIPTOR_FOR_ATTRIBUTE_0_CANNOT_BE_NULL.toLocalizedString(attribute));
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Attribute descriptor is: " + attributeDescriptor);
+
+ Object returnValue = null;
+
+ String lastUpdateField = "lastUpdatedTimeStamp";
+
+ int staleness = getStaleness(attributeDescriptor, mbeanDescriptor, lastUpdateField);
+
+ if (staleness == ALWAYS_STALE || staleness == STALE)
+ {
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Value is stale");
+
+ String getter = (String)attributeDescriptor.getFieldValue("getMethod");
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("getMethod field is: " + getter);
+ if (getter == null)
+ {
+ // No getter, use default value
+ returnValue = attributeDescriptor.getFieldValue("default");
+
+ if (returnValue != null)
+ {
+ // Check if the return type is of the same type
+ // As an extension allow covariant return type
+ Class returned = returnValue.getClass();
+ Class declared = loadClassWithContextClassLoader(attrInfo.getType());
+
+ checkAssignability(returned, declared);
+ }
+
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("getAttribute for attribute " + attribute + " returns default value: " + returnValue);
+ }
+ else
+ {
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Invoking attribute getter...");
+ // As an extension, allow attributes to be called on target objects also
+ Object target = resolveTargetObject(attributeDescriptor);
+ returnValue = invokeMethod(target, getter, new Class[0], new Object[0]);
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Returned value is: " + returnValue);
+
+ if (returnValue != null)
+ {
+ // Check if the return type is of the same type
+ // As an extension allow covariant return type
+ Class returned = returnValue.getClass();
+ Class declared = loadClassWithContextClassLoader(attrInfo.getType());
+
+ checkAssignability(returned, declared);
+ }
+
+ // Cache the new value only if caching is needed
+ if (staleness != ALWAYS_STALE)
+ {
+ attributeDescriptor.setField("value", returnValue);
+ attributeDescriptor.setField(lastUpdateField, Long.valueOf(System.currentTimeMillis()));
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Returned value has been cached");
+
+ // And now replace the descriptor with the updated clone
+ info.setDescriptor(attributeDescriptor, "attribute");
+ }
+
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("getAttribute for attribute " + attribute + " returns invoked value: " + returnValue);
+ }
+ }
+ else
+ {
+ // Return cached value
+ returnValue = attributeDescriptor.getFieldValue("value");
+
+ if (returnValue != null)
+ {
+ // Check if the return type is of the same type
+ // As an extension allow covariant return type
+ Class returned = returnValue.getClass();
+ Class declared = loadClassWithContextClassLoader(attrInfo.getType());
+
+ checkAssignability(returned, declared);
+ }
+
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("getAttribute for attribute " + attribute + " returns cached value: " + returnValue);
+ }
+
+ // Puff, everything went ok
+ return returnValue;
+ }
+
+ public AttributeList setAttributes(AttributeList attributes)
+ {
+ if (attributes == null) throw new RuntimeOperationsException(new IllegalArgumentException(LocalizedStrings.MX4JModelMBean_ATTRIBUTE_LIST_CANNOT_BE_NULL.toLocalizedString()));
+
+ Logger logger = getLogger();
+
+ AttributeList list = new AttributeList();
+ for (Iterator i = attributes.iterator(); i.hasNext();)
+ {
+ Attribute attribute = (Attribute)i.next();
+ String name = attribute.getName();
+ try
+ {
+ setAttribute(attribute);
+ list.add(attribute);
+ }
+ catch (Exception x)
+ {
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("setAttribute for attribute " + name + " failed", x);
+ // And go on with the next one
+ }
+ }
+ return list;
+ }
+
+ public void setAttribute(Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException
+ {
+ if (attribute == null) throw new RuntimeOperationsException(new IllegalArgumentException(LocalizedStrings.MX4JModelMBean_ATTRIBUTE_CANNOT_BE_NULL.toLocalizedString()));
+
+ Logger logger = getLogger();
+
+ // No need to synchronize: I work mostly on clones
+ // I want the real info, not its clone
+ ModelMBeanInfo info = getModelMBeanInfo();
+ if (info == null) throw new AttributeNotFoundException(LocalizedStrings.MX4JModelMBean_MODELMBEANINFO_IS_NULL.toLocalizedString());
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("ModelMBeanInfo is: " + info);
+
+ String attrName = attribute.getName();
+ Object attrValue = attribute.getValue();
+
+ // This is a clone, we use it read only
+ ModelMBeanAttributeInfo attrInfo = info.getAttribute(attrName);
+ if (attrInfo == null) throw new AttributeNotFoundException(LocalizedStrings.MX4JModelMBean_CANNOT_FIND_MODELMBEANATTRIBUTEINFO_FOR_ATTRIBUTE_0.toLocalizedString(attrName));
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Attribute info is: " + attrInfo);
+
+ if (!attrInfo.isWritable()) throw new AttributeNotFoundException(LocalizedStrings.MX4JModelMBean_ATTRIBUTE_0_IS_NOT_WRITABLE.toLocalizedString(attrName));
+
+ // This returns a clone of the mbean descriptor, we use it read only
+ Descriptor mbeanDescriptor = info.getMBeanDescriptor();
+ if (mbeanDescriptor == null) throw new AttributeNotFoundException(LocalizedStrings.MX4JModelMBean_MBEAN_DESCRIPTOR_CANNOT_BE_NULL.toLocalizedString());
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("MBean descriptor is: " + mbeanDescriptor);
+
+ // This descriptor is a clone
+ Descriptor attributeDescriptor = attrInfo.getDescriptor();
+ if (attributeDescriptor == null) throw new AttributeNotFoundException(LocalizedStrings.MX4JModelMBean_ATTRIBUTE_DESCRIPTOR_FOR_ATTRIBUTE_0_CANNOT_BE_NULL.toLocalizedString(attrName));
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Attribute descriptor is: " + attributeDescriptor);
+
+ String lastUpdateField = "lastUpdatedTimeStamp";
+
+ Object oldValue = null;
+ try
+ {
+ oldValue = getAttribute(attrName);
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Previous value of attribute " + attrName + ": " + oldValue);
+ }
+ catch (Exception x)
+ {
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Cannot get previous value of attribute " + attrName, x);
+ }
+
+ // Check if setMethod is present
+ String method = (String)attributeDescriptor.getFieldValue("setMethod");
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("setMethod field is: " + method);
+ if (method != null)
+ {
+ Class declared = loadClassWithContextClassLoader(attrInfo.getType());
+ if (attrValue != null)
+ {
+ Class parameter = attrValue.getClass();
+ checkAssignability(parameter, declared);
+ }
+
+ // As an extension, allow attributes to be called on target objects also
+ Object target = resolveTargetObject(attributeDescriptor);
+ invokeMethod(target, method, new Class[]{declared}, new Object[]{attrValue});
+
+ // Cache the value only if currencyTimeLimit is not 0, ie it is not always stale
+ int staleness = getStaleness(attributeDescriptor, mbeanDescriptor, lastUpdateField);
+ if (staleness != ALWAYS_STALE)
+ {
+ attributeDescriptor.setField("value", attrValue);
+ attributeDescriptor.setField(lastUpdateField, Long.valueOf(System.currentTimeMillis()));
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Attribute's value has been cached");
+ }
+ else
+ {
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Always stale, avoiding to cache attribute's value");
+ }
+ }
+ else
+ {
+ if (attrValue != null)
+ {
+ Class parameter = attrValue.getClass();
+ Class declared = loadClassWithContextClassLoader(attrInfo.getType());
+
+ checkAssignability(parameter, declared);
+ }
+
+ // Always store the value in the descriptor: no setMethod
+ attributeDescriptor.setField("value", attrValue);
+ }
+
+ // And now replace the descriptor with the updated clone
+ info.setDescriptor(attributeDescriptor, "attribute");
+
+ // Send notifications to listeners
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Sending attribute change notifications");
+ sendAttributeChangeNotification(new Attribute(attrName, oldValue), attribute);
+
+ // Persist this ModelMBean
+ boolean persistNow = shouldPersistNow(attributeDescriptor, mbeanDescriptor, lastUpdateField);
+ if (persistNow)
+ {
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Persisting this ModelMBean...");
+ try
+ {
+ store();
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("ModelMBean persisted successfully");
+ }
+ catch (Exception x)
+ {
+ logger.error(LocalizedStrings.MX4JModelMBean_CANNOT_STORE_MODELMBEAN_AFTER_SETATTRIBUTE, x);
+ if (x instanceof MBeanException)
+ throw (MBeanException)x;
+ else
+ throw new MBeanException(x);
+ }
+ }
+ }
+
+ public Object invoke(String method, Object[] arguments, String[] params) throws MBeanException, ReflectionException
+ {
+ if (method == null) throw new RuntimeOperationsException(new IllegalArgumentException(LocalizedStrings.MX4JModelMBean_METHOD_NAME_CANNOT_BE_NULL.toLocalizedString()));
+ if (arguments == null) arguments = new Object[0];
+ if (params == null) params = new String[0];
+
+ Logger logger = getLogger();
+
+ // Find operation descriptor
+ ModelMBeanInfo info = getModelMBeanInfo();
+ if (info == null) throw new MBeanException(new ServiceNotFoundException(LocalizedStrings.MX4JModelMBean_MODELMBEANINFO_IS_NULL.toLocalizedString()));
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("ModelMBeanInfo is: " + info);
+
+ // This is a clone, we use it read only
+ ModelMBeanOperationInfo operInfo = info.getOperation(method);
+ if (operInfo == null) throw new MBeanException(new ServiceNotFoundException(LocalizedStrings.MX4JModelMBean_CANNOT_FIND_MODELMBEANOPERATIONINFO_FOR_OPERATION_0.toLocalizedString(method)));
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Operation info is: " + operInfo);
+
+ // This descriptor is a clone
+ Descriptor operationDescriptor = operInfo.getDescriptor();
+ if (operationDescriptor == null) throw new MBeanException(new ServiceNotFoundException(LocalizedStrings.MX4JModelMBean_OPERATION_DESCRIPTOR_FOR_OPERATION_0_CANNOT_BE_NULL.toLocalizedString(method)));
+ String role = (String)operationDescriptor.getFieldValue("role");
+ if (role == null || !role.equals("operation")) throw new MBeanException(new ServiceNotFoundException(LocalizedStrings.MX4JModelMBean_OPERATION_DESCRIPTOR_FIELD_ROLE_MUST_BE_OPERATION_NOT_0.toLocalizedString(role)));
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Operation descriptor is: " + operationDescriptor);
+
+ // This returns a clone of the mbean descriptor, we use it read only
+ Descriptor mbeanDescriptor = info.getMBeanDescriptor();
+ if (mbeanDescriptor == null) throw new MBeanException(new ServiceNotFoundException(LocalizedStrings.MX4JModelMBean_MBEAN_DESCRIPTOR_CANNOT_BE_NULL.toLocalizedString()));
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("MBean descriptor is: " + mbeanDescriptor);
+
+ Object returnValue = null;
+
+ String lastUpdateField = "lastReturnedTimeStamp";
+
+ // Check if the method should be invoked given the cache settings
+ int staleness = getStaleness(operationDescriptor, mbeanDescriptor, lastUpdateField);
+
+ if (staleness == ALWAYS_STALE || staleness == STALE)
+ {
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Value is stale");
+
+ // Find parameters classes
+ Class[] parameters = null;
+ try
+ {
+ parameters = Utils.loadClasses(Thread.currentThread().getContextClassLoader(), params);
+ }
+ catch (ClassNotFoundException x)
+ {
+ logger.error(LocalizedStrings.MX4JModelMBean_CANNOT_FIND_OPERATIONS_PARAMETER_CLASSES, x);
+ throw new ReflectionException(x);
+ }
+
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Invoking operation...");
+
+ // Find target object
+ Object target = resolveTargetObject(operationDescriptor);
+ returnValue = invokeMethod(target, method, parameters, arguments);
+
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Returned value is: " + returnValue);
+
+ if (returnValue != null)
+ {
+ Class parameter = returnValue.getClass();
+ Class declared = loadClassWithContextClassLoader(operInfo.getReturnType());
+
+ checkAssignability(parameter, declared);
+ }
+
+ // Cache the new value only if caching is needed
+ if (staleness != ALWAYS_STALE)
+ {
+ operationDescriptor.setField("lastReturnedValue", returnValue);
+ operationDescriptor.setField(lastUpdateField, Long.valueOf(System.currentTimeMillis()));
+ if (logger.isEnabledFor(Logger.TRACE))
+ {
+ logger.trace("Returned value has been cached");
+ }
+
+ // And now replace the descriptor with the updated clone
+ info.setDescriptor(operationDescriptor, "operation");
+ }
+
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("invoke for operation " + method + " returns invoked value: " + returnValue);
+ }
+ else
+ {
+ // Return cached value
+ returnValue = operationDescriptor.getFieldValue("lastReturnedValue");
+
+ if (returnValue != null)
+ {
+ Class parameter = returnValue.getClass();
+ Class declared = loadClassWithContextClassLoader(operInfo.getReturnType());
+
+ checkAssignability(parameter, declared);
+ }
+
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("invoke for operation " + method + " returns cached value: " + returnValue);
+ }
+
+ // As an extension, persist this model mbean also after operation invocation, but using only
+ // settings provided in the operation descriptor, without falling back to defaults set in
+ // the MBean descriptor
+ boolean persistNow = shouldPersistNow(operationDescriptor, null, lastUpdateField);
+ int impact = operInfo.getImpact();
+ if (persistNow && impact != MBeanOperationInfo.INFO)
+ {
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Persisting this ModelMBean...");
+ try
+ {
+ store();
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("ModelMBean persisted successfully");
+ }
+ catch (Exception x)
+ {
+ logger.error(LocalizedStrings.MX4JModelMBean_CANNOT_STORE_MODELMBEAN_AFTER_OPERATION_INVOCATION, x);
+ if (x instanceof MBeanException)
+ throw (MBeanException)x;
+ else
+ throw new MBeanException(x);
+ }
+ }
+
+ return returnValue;
+ }
+
+ private Object resolveTargetObject(Descriptor descriptor) throws MBeanException
+ {
+ Logger logger = getLogger();
+ Object target = descriptor.getFieldValue("targetObject");
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("targetObject is: " + target);
+ if (target == null)
+ {
+ target = getManagedResource();
+ }
+ else
+ {
+ String targetObjectType = (String)descriptor.getFieldValue("targetObjectType");
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("targetObjectType is: " + targetObjectType);
+ if (targetObjectType == null)
+ {
+ // Not defined, assume object reference
+ targetObjectType = OBJECT_RESOURCE_TYPE;
+ }
+
+ if (!isResourceTypeSupported(targetObjectType)) throw new MBeanException(new InvalidTargetObjectTypeException(targetObjectType));
+ }
+ return target;
+ }
+
+ public void load() throws MBeanException, RuntimeOperationsException, InstanceNotFoundException
+ {
+ PersisterMBean persister = findPersister();
+ if (persister != null)
+ {
+ ModelMBeanInfo info = (ModelMBeanInfo)persister.load();
+ setModelMBeanInfo(info);
+ }
+ }
+
+ public void store() throws MBeanException, RuntimeOperationsException, InstanceNotFoundException
+ {
+ PersisterMBean persister = findPersister();
+ if (persister != null)
+ {
+ // Take a clone to avoid synchronization problems
+ ModelMBeanInfo info = (ModelMBeanInfo)getMBeanInfo();
+ persister.store(info);
+ }
+ }
+
+ protected ClassLoaderRepository getClassLoaderRepository()
+ {
+ if (m_mbeanServer != null)
+ return m_mbeanServer.getClassLoaderRepository();
+ else
+ return null;
+ }
+
+
+ private boolean shouldPersistNow(Descriptor attribute, Descriptor mbean, String lastUpdateField)
+ {
+ int persist = getPersistPolicy(attribute, mbean);
+ if (persist == PERSIST_NO_MORE_OFTEN_THAN)
+ {
+ Long period = getFieldTimeValue(attribute, mbean, "persistPeriod");
+ long now = System.currentTimeMillis();
+ Long lastUpdate = (Long)attribute.getFieldValue(lastUpdateField);
+ if (now - lastUpdate.longValue() < period.longValue())
+ return false;
+ else
+ return true;
+ }
+ else if (persist == PERSIST_NEVER)
+ {
+ return false;
+ }
+ else if (persist == PERSIST_ON_TIMER)
+ {
+ return false;
+ }
+ else if (persist == PERSIST_ON_UPDATE)
+ {
+ return true;
+ }
+ else
+ {
+ throw new ImplementationException(LocalizedStrings.MX4JModelMBean_INVALID_PERSIST_VALUE.toLocalizedString());
+ }
+ }
+
+ private int getPersistPolicy(Descriptor descriptor, Descriptor mbean)
+ {
+ Logger logger = getLogger();
+
+ String persist = (String)descriptor.getFieldValue("persistPolicy");
+ if (persist == null && mbean != null) persist = (String)mbean.getFieldValue("persistPolicy");
+ if (persist == null)
+ {
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("No persist policy defined, assuming Never");
+ return PERSIST_NEVER;
+ }
+ else
+ {
+ if (persist.equals("Never"))
+ {
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Persist never");
+ return PERSIST_NEVER;
+ }
+ else if (persist.equals("OnUpdate"))
+ {
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Persist on update");
+ return PERSIST_ON_UPDATE;
+ }
+ else if (persist.equals("OnTimer"))
+ {
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Persist on update");
+ return PERSIST_ON_TIMER;
+ }
+ else if (persist.equals("NoMoreOftenThan"))
+ {
+ if (logger.isEnabledFor(Logger.TRACE))
+ {
+ Long period = getFieldTimeValue(descriptor, mbean, "persistPeriod");
+ logger.trace("Persist no more often than " + period);
+ }
+ return PERSIST_NO_MORE_OFTEN_THAN;
+ }
+ else
+ {
+ // Garbage, assuming Never
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Invalid persist policy, assuming persist never");
+ return PERSIST_NEVER;
+ }
+ }
+ }
+
+ private int getStaleness(Descriptor attribute, Descriptor mbean, String lastUpdateField)
+ {
+ Logger logger = getLogger();
+
+ Long currencyTimeLimit = getFieldTimeValue(attribute, mbean, "currencyTimeLimit");
+ if (currencyTimeLimit == null)
+ {
+ // No time limit defined
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("No currencyTimeLimit defined, assuming always stale");
+ return ALWAYS_STALE;
+ }
+ else
+ {
+ long ctl = currencyTimeLimit.longValue() * 1000;
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("currencyTimeLimit is (ms): " + ctl);
+
+ if (ctl == 0)
+ {
+ // Never stale
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Never stale");
+ return NEVER_STALE;
+ }
+ else if (ctl < 0) // this should be == -1 but the other cases are in the air
+ {
+ // Always stale
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Always stale");
+ return ALWAYS_STALE;
+ }
+ else
+ {
+ Long timestamp = (Long)attribute.getFieldValue(lastUpdateField);
+ long luts = 0;
+
+ if (timestamp != null) luts = timestamp.longValue();
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug(lastUpdateField + " is: " + luts);
+
+ long now = System.currentTimeMillis();
+ if (now < luts + ctl)
+ {
+ // Seems to be not stale, but has been set at least once ?
+ if (timestamp == null)
+ {
+ // Return stale to call it the first time
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Stale since was never set");
+ return STALE;
+ }
+ else
+ {
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Not stale");
+ return NOT_STALE;
+ }
+ }
+ else
+ {
+ // Stale
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Stale");
+ return STALE;
+ }
+ }
+ }
+ }
+
+ private Long getFieldTimeValue(Descriptor descriptor, Descriptor mbean, String field)
+ {
+ Logger logger = getLogger();
+
+ Object value = descriptor.getFieldValue(field);
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Descriptor's " + field + " field: " + value);
+
+ if (value == null && mbean != null)
+ {
+ value = mbean.getFieldValue(field);
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("MBean's " + field + " field: " + value);
+ if (value == null) return null;
+ }
+
+ if (value instanceof Number) return Long.valueOf(((Number)value).longValue());
+
+ if (value instanceof String)
+ {
+ try
+ {
+ long ctl = Long.parseLong((String)value);
+ return Long.valueOf(ctl);
+ }
+ catch (NumberFormatException x)
+ {
+ return Long.valueOf(0);
+ }
+ }
+ return Long.valueOf(0);
+ }
+
+ private Object invokeMethod(Object target, String methodName, Class[] params, Object[] args) throws MBeanException, ReflectionException
+ {
+ // First try on this instance, then on the target
+ Object realTarget = null;
+ Method method = null;
+ try
+ {
+ realTarget = this;
+ method = realTarget.getClass().getMethod(methodName, params);
+ }
+ catch (NoSuchMethodException x)
+ {
+ realTarget = target;
+ }
+
+ if (realTarget == null) throw new MBeanException(new ServiceNotFoundException(LocalizedStrings.MX4JModelMBean_COULD_NOT_FIND_TARGET.toLocalizedString()));
+
+ if (method == null)
+ {
+ try
+ {
+ method = realTarget.getClass().getMethod(methodName, params);
+ }
+ catch (NoSuchMethodException x)
+ {
+ throw new ReflectionException(x);
+ }
+ }
+
+ try
+ {
+ Object value = method.invoke(realTarget, args);
+ Logger logger = getLogger();
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Method invocation returned value: " + value);
+ return value;
+ }
+ catch (IllegalAccessException x)
+ {
+ throw new ReflectionException(x);
+ }
+ catch (IllegalArgumentException x)
+ {
+ throw new MBeanException(x);
+ }
+ catch (InvocationTargetException x)
+ {
+ Throwable t = x.getTargetException();
+ if (t instanceof Error)
+ throw new MBeanException(new RuntimeErrorException((Error)t));
+ else
+ throw new MBeanException((Exception)t);
+ }
+ }
+
+ private Logger getModelMBeanLogger(String notificationType) throws MBeanException
+ {
+ // Get a copy to avoid synchronization
+ ModelMBeanInfo info = getModelMBeanInfo();
+
+ // First look if there is a suitable notification descriptor, otherwise use MBean descriptor
+ Descriptor descriptor = null;
+ Logger modelMBeanLogger = null;
+ if (notificationType != null)
+ {
+ descriptor = info.getDescriptor(notificationType, "notification");
+ modelMBeanLogger = findLogger(descriptor);
+ }
+
+ if (modelMBeanLogger == null)
+ {
+ descriptor = info.getMBeanDescriptor();
+ modelMBeanLogger = findLogger(descriptor);
+ if (modelMBeanLogger != null) return modelMBeanLogger;
+ }
+
+ return null;
+ }
+
+ private Logger findLogger(Descriptor descriptor)
+ {
+ Logger logger = getLogger();
+
+ if (descriptor == null)
+ {
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Can't find MBean logger, descriptor is null");
+ return null;
+ }
+
+ String log = (String)descriptor.getFieldValue("log");
+ String location = (String)descriptor.getFieldValue("logFile");
+
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Log fields: log=" + log + ", file=" + location);
+
+ if (log == null || !Boolean.valueOf(log).booleanValue())
+ {
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Logging is not supported by this ModelMBean");
+ return null;
+ }
+ // Logger is supported, where log to ?
+ if (location == null)
+ {
+ // As an extension, see if the field logMBean has been defined
+ location = (String)descriptor.getFieldValue("logMBean");
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Log fields: mbean=" + location);
+
+ if (location == null)
+ {
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Logging is not supported by this ModelMBean");
+ return null;
+ }
+
+ // It seems that the user wants to delegate a registered mbean to log
+ try
+ {
+ ObjectName objectName = new ObjectName(location);
+ MBeanServer server = getMBeanServer();
+ if (server == null) throw new MBeanException(new IllegalStateException(LocalizedStrings.MX4JModelMBean_MX4JMODELMBEAN_IS_NOT_REGISTERED.toLocalizedString()));
+ if (server.isRegistered(objectName))
+ {
+ MBeanLogger l = new MBeanLogger(server, objectName);
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("ModelMBean log supported by delegating to this MBean: " + objectName);
+ return l;
+ }
+
+ return null;
+ }
+ catch (MalformedObjectNameException x)
+ {
+ // Ah, was not a correct object name
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Specified logMBean field does not contain a valid ObjectName: " + location);
+ return null;
+ }
+ catch (MBeanException x)
+ {
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("logMBean field does not specify an MBean that supports logging delegation", x);
+ return null;
+ }
+ }
+ else
+ {
+ // User decided to log to a file
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("ModelMBean log supported on file system");
+ return new FileLogger(location);
+ }
+ }
+
+ private NotificationBroadcasterSupport getAttributeChangeBroadcaster()
+ {
+ return m_attributeChangeBroadcaster;
+ }
+
+ private MBeanServer getMBeanServer()
+ {
+ return m_mbeanServer;
+ }
+
+ private ModelMBeanInfo getModelMBeanInfo()
+ {
+ // No cloning performed
+ return m_modelMBeanInfo;
+ }
+
+ private PersisterMBean findPersister() throws MBeanException, InstanceNotFoundException
+ {
+ Logger logger = getLogger();
+
+ ModelMBeanInfo info = getModelMBeanInfo();
+ if (info == null)
+ {
+ // Not yet initialized
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Can't find persister, ModelMBeanInfo is null");
+ return null;
+ }
+ Descriptor mbeanDescriptor = info.getMBeanDescriptor();
+ if (mbeanDescriptor == null)
+ {
+ // This is normally should not happen if ModelMBeanInfoSupport is used
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Can't find persister, MBean descriptor is null");
+ return null;
+ }
+
+ String location = (String)mbeanDescriptor.getFieldValue("persistLocation");
+ String name = (String)mbeanDescriptor.getFieldValue("persistName");
+ String mbeanName = (String)mbeanDescriptor.getFieldValue("name");
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Persistence fields: location=" + location + ", name=" + name);
+
+ if (mbeanName == null && name == null)
+ {
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Persistence is not supported by this ModelMBean");
+ return null;
+ }
+
+ // Try to see if this mbean should delegate to another mbean
+ if (name != null)
+ {
+ try
+ {
+ ObjectName objectName = new ObjectName(name.trim());
+ // OK, a valid object name
+ MBeanServer server = getMBeanServer();
+ if (server == null) throw new MBeanException(new IllegalStateException(LocalizedStrings.MX4JModelMBean_MX4JMODELMBEAN_IS_NOT_REGISTERED.toLocalizedString()));
+
+ if (server.isRegistered(objectName) && server.isInstanceOf(objectName, PersisterMBean.class.getName()))
+ {
+ // OK, the given mbean is registered with this mbean server
+ PersisterMBean persister = new MBeanPersister(server, objectName);
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Persistence is delegated to this MBean: " + objectName);
+ return persister;
+ }
+ else
+ {
+ throw new InstanceNotFoundException(objectName.toString());
+ }
+ }
+ catch (MalformedObjectNameException ignored)
+ {
+ // It does not delegates to another mbean, use default
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Persistence is not delegated to another MBean");
+ }
+
+ // Default is serialization to file
+ FilePersister persister = new FilePersister(location, name);
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Persistence is realized through file system in " + persister.getFileName());
+ return persister;
+ }
+ else
+ {
+ // Only location given, use MBean name
+ FilePersister persister = new FilePersister(location, mbeanName);
+ if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Persistence is realized through file system in " + persister.getFileName());
+ return persister;
+ }
+ }
+
+ private Class loadClassWithContextClassLoader(String name)
+ {
+ try
+ {
+ return Utils.loadClass(Thread.currentThread().getContextClassLoader(), name);
+ }
+ catch (ClassNotFoundException x)
+ {
+ Logger logger = getLogger();
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Cannot find attribute's declared return class", x);
+ return null;
+ }
+ }
+
+ private void checkAssignability(Class parameter, Class declared) throws MBeanException
+ {
+ Logger logger = getLogger();
+
+ if (logger.isEnabledFor(Logger.DEBUG))
+ {
+ logger.debug("The class of the parameter is: " + parameter);
+ if (parameter != null) logger.debug("The classloder of the parameter's class is: " + parameter.getClassLoader());
+ logger.debug("The class declared as type of the attribute is: " + declared);
+ if (declared != null) logger.debug("The classloader of the declared parameter's class is: " + declared.getClassLoader());
+ }
+
+ boolean assignable = false;
+
+ if (declared == null || parameter == null)
+ assignable = false;
+ else if (declared == boolean.class && parameter == Boolean.class)
+ assignable = true;
+ else if (declared == byte.class && parameter == Byte.class)
+ assignable = true;
+ else if (declared == char.class && parameter == Character.class)
+ assignable = true;
+ else if (declared == short.class && parameter == Short.class)
+ assignable = true;
+ else if (declared == int.class && parameter == Integer.class)
+ assignable = true;
+ else if (declared == long.class && parameter == Long.class)
+ assignable = true;
+ else if (declared == float.class && parameter == Float.class)
+ assignable = true;
+ else if (declared == double.class && parameter == Double.class)
+ assignable = true;
+ else
+ assignable = declared.isAssignableFrom(parameter);
+
+ if (!assignable)
+ {
+ if (logger.isEnabledFor(Logger.TRACE)) logger.trace("Parameter value's class and attribute's declared return class are not assignable");
+ throw new MBeanException(new InvalidAttributeValueException(LocalizedStrings.MX4JModelMBean_RETURNED_TYPE_AND_DECLARED_TYPE_ARE_NOT_ASSIGNABLE.toLocalizedString()));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/096b622d/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/MX4JServerSocketFactory.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/MX4JServerSocketFactory.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/MX4JServerSocketFactory.java
new file mode 100644
index 0000000..15a0c27
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/MX4JServerSocketFactory.java
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.geode.internal.admin.api.jmx.impl;
+
+import org.apache.geode.internal.admin.api.DistributedSystemConfig;
+import org.apache.geode.internal.admin.api.impl.InetAddressUtil;
+import org.apache.geode.distributed.internal.DistributionConfig;
+import org.apache.geode.internal.net.SocketCreator;
+import org.apache.geode.internal.logging.LogService;
+import org.apache.geode.internal.net.SocketCreatorFactory;
+
+import org.apache.logging.log4j.Logger;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.util.Properties;
+
+/**
+ * Creates <code>ServerSockets</code> for JMX adaptors.
+ * <p>
+ * The interface {@link mx4j.tools.adaptor.AdaptorServerSocketFactory} is
+ * implemented in order to support securing of {@link
+ * mx4j.tools.adaptor.http.HttpAdaptor}.
+ * <p>
+ * The interface {@link java.rmi.server.RMIServerSocketFactory} is implemented
+ * to support the securing of {@link
+ * javax.management.remote.JMXConnectorServer}. See {@link
+ * javax.management.remote.rmi.RMIConnectorServer} for the actual subclass that
+ * is used for the JMX RMI adaptor.
+ * <p>
+ * Complete info on JSSE, including debugging, can be found at
+ * <a href="http://java.sun.com/j2se/1.4.2/docs/guide/security/jsse/JSSERefGuide.html">
+ * http://java.sun.com/j2se/1.4.2/docs/guide/security/jsse/JSSERefGuide.html</a>
+ *
+ * @since GemFire 3.5 (old name was SSLAdaptorServerSocketFactory)
+ */
+public class MX4JServerSocketFactory
+implements mx4j.tools.adaptor.AdaptorServerSocketFactory,
+ java.rmi.server.RMIServerSocketFactory {
+
+ private static final Logger logger = LogService.getLogger();
+
+ private static final int DEFAULT_BACKLOG = 50;
+
+ private final SocketCreator socketCreator;
+ private String bindAddress = DistributedSystemConfig.DEFAULT_BIND_ADDRESS;
+ private int backlog = DEFAULT_BACKLOG;
+
+ /**
+ * Constructs new instance of MX4JServerSocketFactory.
+ *
+ * @param useSSL
+ * true if ssl is to be enabled
+ * @param needClientAuth
+ * true if client authentication is required
+ * @param protocols
+ * space-delimited list of ssl protocols to use
+ * @param ciphers
+ * space-delimited list of ssl ciphers to use
+ * @param gfsecurityProps
+ * vendor properties passed in through gfsecurity.properties
+ */
+ public MX4JServerSocketFactory(boolean useSSL,
+ boolean needClientAuth,
+ String protocols,
+ String ciphers,
+ Properties gfsecurityProps) {
+ if (protocols == null || protocols.length() == 0) {
+ protocols = DistributionConfig.DEFAULT_SSL_PROTOCOLS;
+ }
+ if (ciphers == null || ciphers.length() == 0) {
+ ciphers = DistributionConfig.DEFAULT_SSL_CIPHERS;
+ }
+ this.socketCreator = SocketCreatorFactory.createNonDefaultInstance(
+ useSSL, needClientAuth, protocols, ciphers, gfsecurityProps);
+ }
+
+ /**
+ * Constructs new instance of MX4JServerSocketFactory.
+ *
+ * @param useSSL
+ * true if ssl is to be enabled
+ * @param needClientAuth
+ * true if client authentication is required
+ * @param protocols
+ * space-delimited list of ssl protocols to use
+ * @param ciphers
+ * space-delimited list of ssl ciphers to use
+ * @param bindAddress
+ * host or address to bind to (bind-address)
+ * @param backlog
+ * how many connections are queued
+ * @param gfsecurityProps
+ * vendor properties passed in through gfsecurity.properties
+ */
+ public MX4JServerSocketFactory(boolean useSSL,
+ boolean needClientAuth,
+ String protocols,
+ String ciphers,
+ String bindAddress, // optional for RMI impl
+ int backlog, // optional for RMI impl
+ Properties gfsecurityProps) {
+ this(useSSL, needClientAuth, protocols, ciphers, gfsecurityProps);
+ this.bindAddress = bindAddress;
+ this.backlog = backlog;
+ }
+
+ // -------------------------------------------------------------------------
+ // mx4j.tools.adaptor.AdaptorServerSocketFactory impl...
+ // -------------------------------------------------------------------------
+
+ public ServerSocket createServerSocket(int port,
+ int backlog,
+ String bindAddress) throws IOException {
+ if ("".equals(bindAddress)) {
+ return socketCreator.createServerSocket(
+ port, backlog);
+
+ } else {
+ return socketCreator.createServerSocket(
+ port, backlog, InetAddressUtil.toInetAddress(bindAddress));
+ }
+ }
+
+ // -------------------------------------------------------------------------
+ // java.rmi.server.RMIServerSocketFactory impl...
+ // -------------------------------------------------------------------------
+
+ public ServerSocket createServerSocket(int port) throws IOException {
+ ServerSocket sock = null;
+ if ("".equals(bindAddress)) {
+ sock = socketCreator.createServerSocket(port, this.backlog);
+ } else {
+ sock = socketCreator.createServerSocket(
+ port, this.backlog, InetAddressUtil.toInetAddress(this.bindAddress));
+ }
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("MX4JServerSocketFactory RMIServerSocketFactory, INetAddress {}, LocalPort {}, LocalSocketAddress {}",
+ sock.getInetAddress(), sock.getLocalPort(), sock.getLocalSocketAddress());
+ }
+ return sock;
+ }
+
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/096b622d/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/MailManager.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/MailManager.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/MailManager.java
new file mode 100755
index 0000000..93b19bd
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/MailManager.java
@@ -0,0 +1,331 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.geode.internal.admin.api.jmx.impl;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Properties;
+
+import javax.mail.Message;
+import javax.mail.Session;
+import javax.mail.Transport;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeMessage;
+
+import org.apache.logging.log4j.Logger;
+
+import org.apache.geode.SystemFailure;
+import org.apache.geode.internal.i18n.LocalizedStrings;
+import org.apache.geode.internal.logging.LogService;
+import org.apache.geode.internal.logging.log4j.LocalizedMessage;
+
+/**
+ * Provides the ways to send emails to all the registered email id It also
+ * provides the way to add/remove email ids. Can be used to send email in case
+ * of any alerts raised / warning / failure in gemfire.
+ *
+ * @since GemFire 5.1
+ */
+public class MailManager {
+
+ private static final Logger logger = LogService.getLogger();
+
+ public MailManager() {
+ }
+
+ public MailManager(Properties mailProperties) {
+ setMailProperties(mailProperties);
+ }
+
+ public MailManager(File mailPropertiesFile) throws IOException {
+ Properties prop = new Properties();
+ FileInputStream fio = new FileInputStream(mailPropertiesFile);
+ try {
+ prop.load(fio);
+ }
+ finally {
+ fio.close();
+ }
+ setMailProperties(prop);
+ }
+
+ public MailManager(String mailHost, String mailFrom) {
+ this.mailHost = mailHost;
+ this.mailFrom = mailFrom;
+ }
+
+ /**
+ * Send email to all the registered email id with given subject and message
+ */
+ public void sendEmail(String subject, String message) {
+ processEmail(new EmailData(subject, message));
+ }
+
+ /**
+ * Send Emails to all the registered email id
+ *
+ * @param emailData
+ * Instance of EmailData
+ */
+ // Why a separate method & class EmailData needed???
+ private void processEmail(EmailData emailData) {
+ if (logger.isTraceEnabled()) {
+ logger.trace("Entered MailManager:processEmail");
+ }
+
+ if (mailHost == null || mailHost.length() == 0
+ || emailData == null || mailToAddresses.length == 0) {
+ logger.error(LocalizedMessage.create(LocalizedStrings.MailManager_REQUIRED_MAILSERVER_CONFIGURATION_NOT_SPECIFIED));
+ if (logger.isDebugEnabled()) {
+ logger.debug("Exited MailManager:processEmail: Not sending email as conditions not met");
+ }
+ return;
+ }
+
+ Session session = Session.getDefaultInstance(getMailHostConfiguration());
+ MimeMessage mimeMessage = new MimeMessage(session);
+ String subject = emailData.subject;
+ String message = emailData.message;
+ String mailToList = getMailToAddressesAsString();
+
+ try {
+ for (int i = 0; i < mailToAddresses.length; i++) {
+ mimeMessage.addRecipient(Message.RecipientType.TO, new InternetAddress(
+ mailToAddresses[i]));
+ }
+
+ if (subject == null) {
+ subject = LocalizedStrings.MailManager_ALERT_MAIL_SUBJECT.toLocalizedString();
+ }
+ mimeMessage.setSubject(subject);
+
+ if (message == null) {
+ message = "";
+ }
+ mimeMessage.setText(message);
+
+ Transport.send(mimeMessage);
+ logger.info(LocalizedMessage.create(
+ LocalizedStrings.MailManager_EMAIL_ALERT_HAS_BEEN_SENT_0_1_2,
+ new Object[] { mailToList, subject, message }));
+ } catch (VirtualMachineError err) {
+ SystemFailure.initiateFailure(err);
+ // If this ever returns, rethrow the error. We're poisoned
+ // now, so don't let this thread continue.
+ throw err;
+ } catch (Throwable ex) {
+ // Whenever you catch Error or Throwable, you must also
+ // catch VirtualMachineError (see above). However, there is
+ // _still_ a possibility that you are dealing with a cascading
+ // error condition, so you also need to check to see if the JVM
+ // is still usable:
+ SystemFailure.checkFailure();
+ StringBuilder buf = new StringBuilder();
+ buf.append(LocalizedStrings.MailManager_AN_EXCEPTION_OCCURRED_WHILE_SENDING_EMAIL.toLocalizedString());
+ buf.append(LocalizedStrings.MailManager_UNABLE_TO_SEND_EMAIL_PLEASE_CHECK_YOUR_EMAIL_SETTINGS_AND_LOG_FILE.toLocalizedString());
+ buf.append("\n\n").append(LocalizedStrings.MailManager_EXCEPTION_MESSAGE_0.toLocalizedString(ex.getMessage()));
+ buf.append("\n\n").append(LocalizedStrings.MailManager_FOLLOWING_EMAIL_WAS_NOT_DELIVERED.toLocalizedString());
+ buf.append("\n\t").append(LocalizedStrings.MailManager_MAIL_HOST_0.toLocalizedString(mailHost));
+ buf.append("\n\t").append(LocalizedStrings.MailManager_FROM_0.toLocalizedString(mailFrom));
+ buf.append("\n\t").append(LocalizedStrings.MailManager_TO_0.toLocalizedString(mailToList));
+ buf.append("\n\t").append(LocalizedStrings.MailManager_SUBJECT_0.toLocalizedString(subject));
+ buf.append("\n\t").append(LocalizedStrings.MailManager_CONTENT_0.toLocalizedString(message));
+
+ logger.error(buf.toString(), ex);
+ }
+ if (logger.isTraceEnabled()) {
+ logger.trace("Exited MailManager:processEmail");
+ }
+ }
+
+ /**
+ * Not yet implemented
+ */
+ public void close() {
+ }
+
+ /**
+ * @return All the registered email id as string
+ */
+ private String getMailToAddressesAsString() {
+ StringBuffer mailToList = new StringBuffer();
+ for (int i = 0; i < mailToAddresses.length; i++) {
+ mailToList.append(mailToAddresses[i]);
+ mailToList.append(", ");
+ }
+ return mailToList.toString();
+ }
+
+ /**
+ *
+ * @return Properties consisting mailHost and mailFrom property
+ */
+ private Properties getMailHostConfiguration() {
+ Properties result = new Properties();
+ if (mailHost == null) {
+ mailHost = "";
+ }
+ if (mailFrom == null) {
+ mailFrom = "";
+ }
+ result.setProperty("mail.host", mailHost);
+ result.put("mail.from", mailFrom);
+ return result;
+ }
+
+ /**
+ *
+ * @param host
+ * mail host server name
+ */
+ public void setMailHost(String host) {
+ this.mailHost = host;
+ }
+
+ /**
+ *
+ * @return mail host server name
+ */
+ public String getMailHost() {
+ return this.mailHost;
+ }
+
+ /**
+ *
+ * @param fromAddress
+ * mailFrom email id
+ */
+ public void setMailFromAddress(String fromAddress) {
+ mailFrom = fromAddress;
+ }
+
+ /**
+ *
+ * @return mailFrom email id
+ */
+ public String getMailFromAddress() {
+ return mailFrom;
+ }
+
+ /**
+ * add new mail id to ToList
+ */
+ public void addMailToAddress(String toAddress) {
+ mailToSet.add(toAddress);
+ mailToAddresses = getAllToAddresses();
+ }
+
+ /**
+ * remove given mail id from ToList
+ */
+ public void removeMailToAddress(String toAddress) {
+ mailToSet.remove(toAddress);
+ mailToAddresses = getAllToAddresses();
+ }
+
+ /**
+ * @return list all the registered email id
+ */
+ public String[] getAllToAddresses() {
+ return (String[])mailToSet.toArray(new String[0]);
+ }
+
+ /**
+ * remove all the registered email ids from ToList
+ */
+ public void removeAllMailToAddresses() {
+ mailToSet.clear();
+ mailToAddresses = new String[0];
+ }
+
+ /**
+ * Set the mail properties, e.g mail host, mailFrom, MailTo etc
+ */
+ public void setMailProperties(Properties mailProperties) {
+ mailHost = mailProperties.getProperty(PROPERTY_MAIL_HOST);
+ mailFrom = mailProperties.getProperty(PROPERTY_MAIL_FROM);
+ String mailList = mailProperties.getProperty(PROPERTY_MAIL_TO_LIST, "");
+ String split[] = mailList.split(",");
+ removeAllMailToAddresses();
+ for (int i = 0; i < split.length; i++) {
+ addMailToAddress(split[i].trim());
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer buffer = new StringBuffer(200);
+ buffer.append("[Mail Host: ");
+ buffer.append(getMailHost());
+ buffer.append("]");
+ buffer.append(" [Mail From: ");
+ buffer.append(getMailFromAddress());
+ buffer.append("]");
+ buffer.append(" [Mail To: ");
+ if (mailToAddresses.length > 0) {
+
+ for (int i = 0; i < mailToAddresses.length; i++) {
+ buffer.append(mailToAddresses[i]);
+ buffer.append(", ");
+ }
+ buffer.replace(buffer.length() - 2, buffer.length(), "");
+ }
+ else {
+ buffer.append(" Undefined");
+ }
+ buffer.append("]");
+ return buffer.toString();
+ }
+
+ private HashSet mailToSet = new HashSet();
+
+ private String mailToAddresses[] = new String[0];
+
+ protected String mailHost;
+
+ protected String mailFrom;
+
+ public final static String PROPERTY_MAIL_HOST = "mail.host";
+
+ public final static String PROPERTY_MAIL_FROM = "mail.from";
+
+ public final static String PROPERTY_MAIL_TO_LIST = "mail.toList";
+
+ /**
+ * Incorporating subject and message of email
+ *
+ *
+ */
+ static private class EmailData {
+ String subject;
+
+ String message;
+
+ EmailData(String subject, String message) {
+ this.subject = subject;
+ this.message = message;
+ }
+ }
+
+ public static void main(String args[]) {
+ MailManager mailManager = new MailManager("mailsrv1.gemstone.com",
+ "hkhanna@gemstone.com");
+ mailManager.sendEmail("Alert!", "Test");
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/096b622d/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/ManagedResource.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/ManagedResource.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/ManagedResource.java
new file mode 100755
index 0000000..61e76de
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/ManagedResource.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.geode.internal.admin.api.jmx.impl;
+
+import javax.management.ObjectName;
+import javax.management.modelmbean.ModelMBean;
+
+/**
+ * Represents a component or resource that is managed by a
+ * {@link javax.management.modelmbean.ModelMBean}.
+ *
+ * @since GemFire 3.5
+ *
+ */
+public interface ManagedResource {
+
+ /**
+ * The prefix of MBean names. Note: this is NOT used by Members, Stats, or
+ * any other MBean that has it's own domain.
+ *
+ * @see #getMBeanName
+ */
+ public static final String MBEAN_NAME_PREFIX = "GemFire:type=";
+
+ /**
+ * Returns the name of the ModelMBean that will manage this
+ * resource. They [some] are of the form
+ *
+ * <PRE>
+ * MBEAN_NAME_PREFIX + typeName + ",id=" + id
+ * </PRE>
+ *
+ * @see #MBEAN_NAME_PREFIX
+ */
+ public String getMBeanName();
+
+ /** Returns the ModelMBean that is configured to manage this resource */
+ public ModelMBean getModelMBean();
+
+ /** Sets the ModelMBean that is configured to manage this resource */
+ public void setModelMBean(ModelMBean modelMBean);
+
+ /**
+ * Returns the enumerated ManagedResourceType of this resource.
+ *
+ * @see ManagedResourceType
+ */
+ public ManagedResourceType getManagedResourceType();
+
+ /**
+ * Returns the JMX <code>ObjectName</code> of this managed resource.
+ *
+ * @see #getMBeanName
+ */
+ public ObjectName getObjectName();
+
+ /**
+ * Perform any cleanup necessary before stopping management of this resource.
+ */
+ public void cleanupResource();
+
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/096b622d/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/ManagedResourceType.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/ManagedResourceType.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/ManagedResourceType.java
new file mode 100755
index 0000000..b70cade
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/ManagedResourceType.java
@@ -0,0 +1,222 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.geode.internal.admin.api.jmx.impl;
+
+import org.apache.commons.lang.StringUtils;
+
+import org.apache.geode.internal.admin.api.AdminDistributedSystem;
+import org.apache.geode.internal.admin.api.CacheVm;
+import org.apache.geode.internal.admin.api.DistributedSystemHealthConfig;
+import org.apache.geode.internal.admin.api.DistributionLocator;
+import org.apache.geode.internal.admin.api.GemFireHealth;
+import org.apache.geode.internal.admin.api.GemFireHealthConfig;
+import org.apache.geode.internal.admin.api.StatisticResource;
+import org.apache.geode.internal.admin.api.SystemMember;
+import org.apache.geode.internal.admin.api.SystemMemberCache;
+import org.apache.geode.internal.admin.api.SystemMemberCacheServer;
+import org.apache.geode.internal.admin.api.SystemMemberRegion;
+import org.apache.geode.internal.admin.api.jmx.Agent;
+
+/**
+ * Type-safe definition for ModelMBean managed resources. The class type
+ * ({@link #getClassTypeName}) must match the fully qualified class name listed
+ * in the type descriptor in mbeans-descriptors.xml.
+ *
+ * @since GemFire 3.5
+ *
+ */
+public class ManagedResourceType implements java.io.Serializable {
+ private static final long serialVersionUID = 3752874768667480449L;
+
+ /** Agent managed resource type */
+ public static final ManagedResourceType AGENT =
+ new ManagedResourceType("Agent", Agent.class);
+
+ /** DistributedSystem managed resource type */
+ public static final ManagedResourceType DISTRIBUTED_SYSTEM =
+ new ManagedResourceType("AdminDistributedSystem", AdminDistributedSystem.class);
+
+ /** SystemMember managed resource type */
+ public static final ManagedResourceType SYSTEM_MEMBER =
+ new ManagedResourceType("SystemMember", SystemMember.class);
+
+ /** SystemMemberCache managed resource type */
+ public static final ManagedResourceType SYSTEM_MEMBER_CACHE =
+ new ManagedResourceType("SystemMemberCache", SystemMemberCache.class);
+
+ /** SystemMemberCache managed resource type */
+ public static final ManagedResourceType SYSTEM_MEMBER_REGION =
+ new ManagedResourceType("SystemMemberRegion", SystemMemberRegion.class);
+
+ /** SystemMemberCacheServer managed resource type */
+ public static final ManagedResourceType SYSTEM_MEMBER_CACHE_SERVER =
+ new ManagedResourceType("SystemMemberCacheServer", SystemMemberCacheServer.class);
+
+ /** CacheVm managed resource type */
+ public static final ManagedResourceType CACHE_VM =
+ new ManagedResourceType("CacheVm", CacheVm.class);
+
+ /** StatisticResource managed resource type */
+ public static final ManagedResourceType STATISTIC_RESOURCE =
+ new ManagedResourceType("StatisticResource", StatisticResource.class);
+
+ public static final ManagedResourceType GEMFIRE_HEALTH =
+ new ManagedResourceType("GemFireHealth", GemFireHealth.class);
+
+ public static final ManagedResourceType DISTRIBUTED_SYSTEM_HEALTH_CONFIG =
+ new ManagedResourceType("DistributedSystemHealthConfig", DistributedSystemHealthConfig.class);
+
+ public static final ManagedResourceType GEMFIRE_HEALTH_CONFIG =
+ new ManagedResourceType("GemFireHealthConfig", GemFireHealthConfig.class);
+
+ public static final ManagedResourceType DISTRIBUTION_LOCATOR =
+ new ManagedResourceType("DistributionLocator", DistributionLocator.class);
+
+ //////////////////// Instance Fields ////////////////////
+
+ /** The display-friendly name of this managed resource type. */
+ private final transient String name;
+
+ /**
+ * The interface/class used to externally represent this type. Note: this must
+ * match the mbean type descriptor in mbeans-descriptors.xml.
+ */
+ private final transient Class clazz;
+
+ // The 4 declarations below are necessary for serialization
+ /** int used as ordinal to represent this Scope */
+ public final int ordinal = nextOrdinal++;
+
+ private static int nextOrdinal = 0;
+
+ private static final ManagedResourceType[] VALUES =
+ { AGENT, DISTRIBUTED_SYSTEM, SYSTEM_MEMBER,
+ SYSTEM_MEMBER_CACHE, SYSTEM_MEMBER_REGION,
+ SYSTEM_MEMBER_CACHE_SERVER, CACHE_VM,
+ STATISTIC_RESOURCE, GEMFIRE_HEALTH, DISTRIBUTED_SYSTEM_HEALTH_CONFIG,
+ GEMFIRE_HEALTH_CONFIG, DISTRIBUTION_LOCATOR
+ };
+
+ private Object readResolve() throws java.io.ObjectStreamException {
+ return VALUES[ordinal]; // Canonicalize
+ }
+
+ /** Creates a new instance of ManagedResourceType. */
+ private ManagedResourceType(String name, Class clazz) {
+ this.name = name;
+ this.clazz = clazz;
+ }
+
+ /** Returns the ManagedResourceType represented by specified ordinal */
+ public static ManagedResourceType fromOrdinal(int ordinal) {
+ return VALUES[ordinal];
+ }
+
+ /** Returns the display-friendly name of this managed resource type */
+ public String getName() {
+ return this.name;
+ }
+
+ /** Returns the interface/class used to externally represent this type */
+ public Class getClassType() {
+ return this.clazz;
+ }
+
+ /**
+ * Returns the fully qualified name of the interface/class used to externally
+ * represent this type
+ */
+ public String getClassTypeName() {
+ return this.clazz.getName();
+ }
+
+ /** Returns true if this is <code>AGENT</code>. */
+ public boolean isAgent() {
+ return this.equals(AGENT);
+ }
+
+ /** Returns true if this is <code>DISTRIBUTED_SYSTEM</code>. */
+ public boolean isDistributedSystem() {
+ return this.equals(DISTRIBUTED_SYSTEM);
+ }
+
+ /** Returns true if this is <code>SYSTEM_MEMBER</code>. */
+ public boolean isSystemMember() {
+ return this.equals(SYSTEM_MEMBER);
+ }
+
+ /** Returns whether this is <code>STATISTIC_RESOURCE</code>. */
+ public boolean isStatisticResource() {
+ return this.equals(STATISTIC_RESOURCE);
+ }
+
+ /** Return whether this is <code>GEMFIRE_HEALTH</code>. */
+ public boolean isGemFireHealth() {
+ return this.equals(GEMFIRE_HEALTH);
+ }
+
+ /**
+ * Returns a string representation for this type.
+ */
+ @Override
+ public String toString() {
+ return this.name;
+ }
+
+ /**
+ * Indicates whether some other object is "equal to" this one.
+ *
+ * @param other the reference object with which to compare.
+ * @return true if this object is the same as the obj argument;
+ * false otherwise.
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) return true;
+ if (other == null) return false;
+ if (!(other instanceof ManagedResourceType)) return false;
+ final ManagedResourceType that = (ManagedResourceType) other;
+
+ if (!StringUtils.equals(this.name, that.name)) return false;
+ if (this.clazz != that.clazz &&
+ !(this.clazz != null &&
+ this.clazz.equals(that.clazz))) return false;
+
+ return true;
+ }
+
+ /**
+ * Returns a hash code for the object. This method is supported for the
+ * benefit of hashtables such as those provided by java.util.Hashtable.
+ *
+ * @return the integer 0 if description is null; otherwise a unique integer.
+ */
+ @Override
+ public int hashCode() {
+ int result = 17;
+ final int mult = 37;
+
+ result = mult * result +
+ (this.name == null ? 0 : this.name.hashCode());
+ result = mult * result +
+ (this.clazz == null ? 0 : this.clazz.hashCode());
+
+ return result;
+ }
+
+}
+