if (attrInfo == null) throw new AttributeNotFoundException("Cannot find ModelMBeanAttributeInfo for attribute " + attribute);
if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Attribute info is: " + attrInfo);
if (!attrInfo.isReadable()) throw new AttributeNotFoundException("Attribute " + attribute + " is not readable");
// This returns a clone of the mbean descriptor, we use it read only
Descriptor mbeanDescriptor = info.getMBeanDescriptor();
if (mbeanDescriptor == null) throw new AttributeNotFoundException("MBean descriptor cannot be null");
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("Attribute descriptor for attribute " + attribute + " cannot be null");
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, new Long(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