package org.glassfish.gmbal.impl ;
import org.glassfish.pfl.tf.timer.spi.ObjectRegistrationManager;
import org.glassfish.gmbal.impl.trace.TraceRegistrationFine;
import org.glassfish.pfl.tf.spi.annotation.InfoMethod;
import org.glassfish.gmbal.impl.trace.TraceRegistration;
import org.glassfish.pfl.basic.algorithm.DelayedObjectToString;
import org.glassfish.pfl.basic.algorithm.DumpIgnore;
import org.glassfish.pfl.basic.algorithm.ObjectUtility;
import org.glassfish.pfl.basic.func.UnaryFunction;
import org.glassfish.pfl.basic.algorithm.Algorithms;
import org.glassfish.pfl.basic.func.UnaryPredicate;
import org.glassfish.pfl.basic.algorithm.ClassAnalyzer;
import org.glassfish.pfl.basic.facet.FacetAccessorImpl;
import org.glassfish.pfl.basic.facet.FacetAccessor;
import org.glassfish.pfl.basic.contain.Pair;
import java.util.ResourceBundle ;
import java.util.Map ;
import java.util.HashMap ;
import java.util.WeakHashMap ;
import java.util.List ;
import java.util.ArrayList ;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.io.IOException ;
import java.io.Serializable;
import java.lang.annotation.Annotation ;
import java.lang.management.ManagementFactory ;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Collection;
import javax.management.MBeanServer ;
import javax.management.JMException ;
import javax.management.ObjectName ;
import javax.management.MBeanAttributeInfo;
import org.glassfish.gmbal.AMXMBeanInterface;
import org.glassfish.gmbal.AMXClient;
import org.glassfish.gmbal.GmbalMBean ;
import org.glassfish.gmbal.ManagedObject ;
import org.glassfish.gmbal.Description ;
import org.glassfish.gmbal.IncludeSubclass ;
import org.glassfish.gmbal.InheritedAttribute ;
import org.glassfish.gmbal.InheritedAttributes ;
import org.glassfish.gmbal.AMXMetadata;
import org.glassfish.gmbal.ManagedAttribute;
import org.glassfish.gmbal.ManagedObjectManager;
import org.glassfish.gmbal.ManagedData;
import org.glassfish.gmbal.typelib.EvaluatedClassAnalyzer;
import org.glassfish.gmbal.typelib.EvaluatedClassDeclaration;
import org.glassfish.gmbal.typelib.EvaluatedDeclaration;
import org.glassfish.gmbal.typelib.EvaluatedFieldDeclaration;
import org.glassfish.gmbal.typelib.EvaluatedMethodDeclaration;
import org.glassfish.gmbal.typelib.EvaluatedType;
import org.glassfish.gmbal.typelib.TypeEvaluator;
import org.glassfish.external.amx.AMX;
import org.glassfish.external.statistics.AverageRangeStatistic ;
import org.glassfish.external.statistics.BoundaryStatistic;
import org.glassfish.external.statistics.BoundedRangeStatistic;
import org.glassfish.external.statistics.CountStatistic;
import org.glassfish.external.statistics.RangeStatistic;
import org.glassfish.external.statistics.Statistic;
import org.glassfish.external.statistics.TimeStatistic;
import org.glassfish.external.statistics.StringStatistic;
import static org.glassfish.pfl.basic.algorithm.Algorithms.* ;
@TraceRegistration
@TraceRegistrationFine
public class ManagedObjectManagerImpl implements ManagedObjectManagerInternal {
@AMXMetadata
static class DefaultAMXMetadataHolder { }
private static final AMXMetadata DEFAULT_AMX_METADATA =
DefaultAMXMetadataHolder.class.getAnnotation(AMXMetadata.class);
private static ObjectUtility myObjectUtil =
new ObjectUtility(true, 0, 4)
.useToString( EvaluatedType.class )
.useToString( ManagedObjectManager.class ) ;
private static final class StringComparator implements Serializable,
Comparator<String> {
private static final long serialVersionUID = 8274851916877850245L;
public int compare(String o1, String o2) {
return - o1.compareTo( o2 ) ;
}
} ;
private static Comparator<String> REV_COMP = new StringComparator() ;
@DumpIgnore
private final String domain ;
private final MBeanTree tree ;
private final Map<EvaluatedClassDeclaration,MBeanSkeleton> skeletonMap ;
private final Map<EvaluatedType,TypeConverter> typeConverterMap ;
private final Map<AnnotatedElement, Map<Class, Annotation>> addedAnnotations ;
private final MBeanSkeleton amxSkeleton ;
private final Set<String> amxAttributeNames ;
private final ObjectRegistrationManager orm ;
private boolean rootCreated ;
private ResourceBundle resourceBundle ;
private MBeanServer server ;
private ManagedObjectManager.RegistrationDebugLevel regDebugLevel ;
private boolean runDebugFlag ;
private boolean jmxRegistrationDebugFlag ;
private final SortedSet<String> typePrefixes = new TreeSet<String>(
REV_COMP ) ;
private boolean stripPackagePrefix = false ;
private ManagedObjectManagerImpl( final String domain,
final ObjectName rootParentName ) {
this.domain = domain ;
this.tree = new MBeanTree( this, domain, rootParentName, AMX.TYPE_KEY ) ;
this.skeletonMap =
new WeakHashMap<EvaluatedClassDeclaration,MBeanSkeleton>() ;
this.typeConverterMap = new WeakHashMap<EvaluatedType,TypeConverter>() ;
this.addedAnnotations =
new HashMap<AnnotatedElement, Map<Class, Annotation>>() ;
final EvaluatedClassDeclaration ecd =
(EvaluatedClassDeclaration)TypeEvaluator.getEvaluatedType(
AMXMBeanInterface.class ) ;
this.amxAttributeNames = new HashSet<String>() ;
this.amxSkeleton = getSkeleton( ecd ) ;
for (MBeanAttributeInfo mbi : amxSkeleton.getMBeanInfo().getAttributes()) {
amxAttributeNames.add( mbi.getName() ) ;
}
orm = new ObjectRegistrationManagerImpl( this ) ;
}
@ManagedData
@Description( "The Statistic model and its sub-models specify the data"
+ " models which are requried to be used to provide the performance data"
+ " described by the specific attributes in the Stats models" )
@InheritedAttributes( {
@InheritedAttribute( methodName="getName",
description = "The name of this Statistic" ),
@InheritedAttribute( methodName="getUnit",
description = "The unit of measurement for this Statistic" ),
@InheritedAttribute( methodName="getDescription",
description = "A human-readable description of the Statistic" ),
@InheritedAttribute( methodName="getStartTime",
description = "The time of the first measurement represented as a long" ),
@InheritedAttribute( methodName="getLastSampleTime",
description = "The time of the first measurement represented as a long")
} )
public interface DummyStatistic { }
@ManagedData
@Description( "Specifies standard timing measurements")
@InheritedAttributes( {
@InheritedAttribute( methodName="getCount",
description = "Number of times the operation was invoked since "
+ "the beginning of this measurement" ),
@InheritedAttribute( methodName="getMaxTime",
description = "The maximum amount of time taken to complete one invocation "
+ "of this operation since the beginning of this measurement" ),
@InheritedAttribute( methodName="getMinTime",
description = "The minimum amount of time taken to complete one invocation "
+ "of this operation since the beginning of this measurement" ),
@InheritedAttribute( methodName="getTotalTime",
description = "The total amount of time taken to complete every invocation "
+ "of this operation since the beginning of this measurement" )
} )
public interface DummyTimeStatistic extends DummyStatistic { }
@ManagedData
@Description( "Specifies standard measurements of the upper and lower "
+ "limits of the value of an attribute" )
@InheritedAttributes( {
@InheritedAttribute( methodName = "getUpperBound",
description = "The upper limit of the value of this attribute" ),
@InheritedAttribute( methodName = "getLowerBound",
description = "The lower limit of the value of this attribute" )
} )
public interface DummyBoundaryStatistic extends DummyStatistic {}
@ManagedData
@Description( "Specifies standard count measurements" )
@InheritedAttributes( {
@InheritedAttribute( methodName = "getCount",
description = "The count since the last reset" )
} )
public interface DummyCountStatistic {}
@ManagedData
@Description( "Specifies standard measurements of the lowest and highest values"
+ " an attribute has held as well as its current value" )
@InheritedAttributes( {
@InheritedAttribute( methodName = "getHighWaterMark",
description = "The highest value this attribute has held since"
+ " the beginninYg of the measurement" ),
@InheritedAttribute( methodName = "getLowWaterMark",
description = "The lowest value this attribute has held since"
+ " the beginninYg of the measurement" ),
@InheritedAttribute( methodName = "getCurrent",
description = "The current value of this attribute" )
} )
public interface DummyRangeStatistic {}
@ManagedData
@Description( "Adds an average to the range statistic")
@InheritedAttributes( {
@InheritedAttribute( methodName = "getAverage",
description =
"The average value of this attribute since its last reset")
})
public interface DummyAverageRangeStatistic {}
@ManagedData
@Description( "Provides standard measurements of a range that has fixed limits" )
public interface DummyBoundedRangeStatistic extends
DummyBoundaryStatistic, DummyRangeStatistic {}
@ManagedData
@Description( "Custom statistic type whose value is a string")
@InheritedAttributes( {
@InheritedAttribute(
methodName="getCurrent",
description="Returns the String value of the statistic" )
} )
public interface DummyStringStatistic extends DummyStatistic { }
List<Pair<Class,Class>> statsData = list(
pair( (Class)DummyStringStatistic.class,
(Class)StringStatistic.class ),
pair( (Class)DummyTimeStatistic.class,
(Class)TimeStatistic.class ),
pair( (Class)DummyStatistic.class,
(Class)Statistic.class ),
pair( (Class)DummyBoundaryStatistic.class,
(Class)BoundaryStatistic.class ),
pair( (Class)DummyBoundedRangeStatistic.class,
(Class)BoundedRangeStatistic.class ),
pair( (Class)DummyCountStatistic.class,
(Class)CountStatistic.class ),
pair( (Class)DummyRangeStatistic.class,
(Class)RangeStatistic.class ),
pair( (Class)DummyAverageRangeStatistic.class,
(Class)AverageRangeStatistic.class )
) ;
private void addAnnotationIfNotNull( AnnotatedElement elemement,
Annotation annotation ) {
if (annotation != null) {
addAnnotation(elemement, annotation);
}
}
private void initializeStatisticsSupport() {
for (Pair<Class,Class> pair : statsData) {
Class dummy = pair.first() ;
Class real = pair.second() ;
addAnnotationIfNotNull( real, dummy.getAnnotation( ManagedData.class ) ) ;
addAnnotationIfNotNull( real, dummy.getAnnotation( Description.class ) ) ;
addAnnotationIfNotNull( real, dummy.getAnnotation( InheritedAttributes.class ) ) ;
}
}
private void init() {
this.server = AccessController.doPrivileged(
new PrivilegedAction<MBeanServer>() {
public MBeanServer run() {
return ManagementFactory.getPlatformMBeanServer() ;
}
} ) ;
rootCreated = false ;
resourceBundle = null ;
regDebugLevel = ManagedObjectManager.RegistrationDebugLevel.NONE ;
runDebugFlag = false ;
jmxRegistrationDebugFlag = false ;
tree.clear() ;
skeletonMap.clear() ;
typeConverterMap.clear() ;
addedAnnotations.clear() ;
initializeStatisticsSupport() ;
TimerAnnotationHelper.registerTimerClasses(this);
}
public ManagedObjectManagerImpl( final String domain ) {
this( domain, null ) ;
init() ;
}
public ManagedObjectManagerImpl( final ObjectName rootParentName ) {
this( rootParentName.getDomain(), rootParentName ) ;
init() ;
}
@TraceRegistration
public void close() throws IOException {
init() ;
}
private synchronized void checkRootNotCreated( String methodName ) {
if (rootCreated) {
throw Exceptions.self.createRootCalled(methodName) ;
}
}
private synchronized void checkRootCreated( String methodName ) {
if (!rootCreated) {
throw Exceptions.self.createRootNotCalled(methodName) ;
}
}
public synchronized void suspendJMXRegistration() {
tree.suspendRegistration() ;
}
public synchronized void resumeJMXRegistration() {
tree.resumeRegistration();
}
public synchronized void stripPackagePrefix() {
checkRootNotCreated("stripPackagePrefix");
stripPackagePrefix = true ;
}
@Override
public String toString( ) {
return "ManagedObjectManagerImpl[domain=" + domain + "]" ;
}
public synchronized ObjectName getRootParentName() {
checkRootCreated("getRootParentName");
return tree.getRootParentName() ;
}
@ManagedObject
@AMXMetadata( type="gmbal-root", isSingleton=true)
@Description( "Dummy class used when no root is specified" )
private static class Root {
@Override
public String toString() {
return "GmbalDefaultRoot" ;
}
}
public synchronized GmbalMBean createRoot() {
return createRoot( new Root() ) ;
}
public synchronized GmbalMBean createRoot(Object root) {
return createRoot( root, null ) ;
}
public synchronized GmbalMBean createRoot(Object root, String name) {
checkRootNotCreated( "createRoot" ) ;
GmbalMBean result ;
try {
rootCreated = true ;
result = tree.setRoot( root, name ) ;
if (result == null) {
rootCreated = false ;
}
} catch (RuntimeException exc) {
rootCreated = false ;
throw exc ;
}
return result ;
}
public synchronized Object getRoot() {
return tree.getRoot() ;
}
@InfoMethod
private void message( String msg ) {}
@InfoMethod
private void describe( String msg, Object data ) {}
@TraceRegistration
private synchronized MBeanSkeleton getSkeleton( EvaluatedClassDeclaration cls ) {
MBeanSkeleton result = skeletonMap.get( cls ) ;
boolean newSkeleton = result == null ;
if (newSkeleton) {
message( "Skeleton not found" ) ;
Pair<EvaluatedClassDeclaration,EvaluatedClassAnalyzer> pair =
getClassAnalyzer( cls, ManagedObject.class ) ;
EvaluatedClassAnalyzer ca = pair.second() ;
EvaluatedClassDeclaration annotatedClass = pair.first() ;
describe( "Annotated class for skeleton", annotatedClass ) ;
if (annotatedClass == null) {
throw Exceptions.self.managedObjectAnnotationNotFound(
cls.name() ) ;
}
MBeanSkeleton skel = new MBeanSkeleton( cls, ca, this ) ;
if (amxSkeleton == null) {
result = skel ;
} else {
result = amxSkeleton.compose( skel ) ;
}
skeletonMap.put( cls, result ) ;
}
if (newSkeleton) {
describe( "Skeleton",
new DelayedObjectToString( result, myObjectUtil ) ) ;
}
return result ;
}
@TraceRegistrationFine
public synchronized TypeConverter getTypeConverter( EvaluatedType type ) {
TypeConverter result = null;
boolean newTypeConverter = false ;
result = typeConverterMap.get( type ) ;
if (result == null) {
message( "Creating new TypeConverter" ) ;
typeConverterMap.put( type,
new TypeConverterImpl.TypeConverterPlaceHolderImpl( type ) ) ;
result = TypeConverterImpl.makeTypeConverter( type, this ) ;
typeConverterMap.put( type, result ) ;
newTypeConverter = true ;
}
if (newTypeConverter) {
describe( "result", myObjectUtil.objectToString( result ) ) ;
}
return result ;
}
private static Field getDeclaredField( final Class<?> cls,
final String name )
throws PrivilegedActionException, NoSuchFieldException {
SecurityManager sman = System.getSecurityManager() ;
if (sman == null) {
return cls.getDeclaredField( name ) ;
} else {
return AccessController.doPrivileged(
new PrivilegedExceptionAction<Field>() {
public Field run() throws Exception {
return cls.getDeclaredField( name ) ;
}
}
) ;
}
}
private String getAMXTypeFromField( Class<?> cls, String fieldName ) {
try {
final Field fld = getDeclaredField(cls, fieldName);
if (Modifier.isFinal(fld.getModifiers())
&& Modifier.isStatic(fld.getModifiers())
&& fld.getType().equals(String.class)) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
fld.setAccessible(true);
return null;
}
});
return (String) fld.get(null);
} else {
return "";
}
} catch (PrivilegedActionException ex) {
return "" ;
} catch (IllegalArgumentException ex) {
return "" ;
} catch (IllegalAccessException ex) {
return "" ;
} catch (NoSuchFieldException ex) {
return "" ;
} catch (SecurityException ex) {
return "" ;
}
}
private boolean goodResult( String str ) {
return str!=null && str.length()>0 ;
}
public synchronized String getTypeName( Class<?> cls, String fieldName,
String nameFromAnnotation ) {
String result = getAMXTypeFromField( cls, fieldName ) ;
if (goodResult( result)) {
return result ;
}
if (goodResult( nameFromAnnotation)) {
return nameFromAnnotation ;
}
String className = cls.getName() ;
for (String str : typePrefixes ) {
if (className.startsWith( str ) ) {
return className.substring( str.length() + 1 ) ;
}
}
if (stripPackagePrefix) {
int lastDot = className.lastIndexOf( '.' ) ;
if (lastDot == -1) {
return className ;
} else {
return className.substring( lastDot + 1 ) ;
}
} else {
return className ;
}
}
public synchronized boolean isManagedObject( Object obj ) {
final EvaluatedClassDeclaration cdecl =
(EvaluatedClassDeclaration)TypeEvaluator.getEvaluatedType(
obj.getClass() ) ;
final ManagedObject mo = getFirstAnnotationOnClass( cdecl,
ManagedObject.class ) ;
return mo != null ;
}
@TraceRegistration
public synchronized MBeanImpl constructMBean( MBeanImpl parentEntity,
Object obj, String name ) {
MBeanImpl result = null ;
String objName = name ;
try {
final Class<?> cls = obj.getClass() ;
final EvaluatedClassDeclaration cdecl =
(EvaluatedClassDeclaration)TypeEvaluator.getEvaluatedType(cls) ;
final MBeanSkeleton skel = getSkeleton( cdecl ) ;
AMXMetadata amd = getFirstAnnotationOnClass( cdecl, AMXMetadata.class ) ;
if (amd == null) {
amd = getDefaultAMXMetadata() ;
}
String type = skel.getType() ;
describe( "Stripped type", type ) ;
result = new MBeanImpl( skel, obj, server, type ) ;
if (objName == null) {
objName = skel.getNameValue( result ) ;
if (objName == null) {
objName = "" ;
}
}
if (objName.length() == 0) {
if (!amd.isSingleton()) {
throw Exceptions.self.nonSingletonRequiresName(
parentEntity, type ) ;
}
} else {
if (amd.isSingleton()) {
throw Exceptions.self.singletonCannotSpecifyName(
parentEntity, type, name ) ;
}
}
describe( "Name value", objName ) ;
result.name( objName ) ;
} catch (JMException exc) {
throw Exceptions.self.errorInConstructingMBean( objName, exc ) ;
}
return result ;
}
@SuppressWarnings("unchecked")
@TraceRegistration
public synchronized GmbalMBean register( final Object parent,
final Object obj, final String name ) {
checkRootCreated("register");
if (obj instanceof String) {
throw Exceptions.self.objStringWrongRegisterCall( (String)obj ) ;
}
try {
MBeanImpl parentEntity = tree.getParentEntity(parent) ;
final MBeanImpl mb = constructMBean( parentEntity, obj, name ) ;
return tree.register( parentEntity, obj, mb) ;
} catch (JMException exc) {
throw Exceptions.self.exceptionInRegister(exc) ;
}
}
public synchronized GmbalMBean register( final Object parent,
final Object obj ) {
return register( parent, obj, null ) ;
}
public synchronized GmbalMBean registerAtRoot(Object obj, String name) {
return register( tree.getRoot(), obj, name ) ;
}
public synchronized GmbalMBean registerAtRoot(Object obj) {
return register( tree.getRoot(), obj, null ) ;
}
@TraceRegistration
public synchronized void unregister( Object obj ) {
checkRootCreated("unregister");
try {
tree.unregister( obj ) ;
} catch (JMException exc) {
throw Exceptions.self.exceptionInUnregister(exc) ;
}
}
@TraceRegistration
public synchronized ObjectName getObjectName( Object obj ) {
checkRootCreated("getObjectName");
if (obj instanceof ObjectName) {
return (ObjectName)obj ;
}
if (obj instanceof AMXClient) {
return ((AMXClient)obj).objectName() ;
}
ObjectName result = tree.getObjectName( obj ) ;
return result ;
}
public AMXClient getAMXClient(Object obj) {
ObjectName oname = getObjectName( obj ) ;
if (oname == null) {
return null ;
}
return new AMXClient( server, oname ) ;
}
@TraceRegistration
public synchronized Object getObject( ObjectName oname ) {
checkRootCreated("getObject");
Object result = tree.getObject( oname ) ;
return result ;
}
public synchronized FacetAccessor getFacetAccessor( Object obj ) {
MBeanImpl mb = tree.getMBeanImpl( obj ) ;
if (mb != null) {
return tree.getFacetAccessor( obj ) ;
} else {
return new FacetAccessorImpl( obj ) ;
}
}
public synchronized String getDomain() {
return domain ;
}
public synchronized void setMBeanServer( MBeanServer server ) {
checkRootNotCreated("setMBeanServer");
this.server = server ;
}
public synchronized MBeanServer getMBeanServer() {
return server ;
}
public synchronized void setResourceBundle( ResourceBundle rb ) {
checkRootNotCreated("setResourceBundle");
this.resourceBundle = rb ;
}
public synchronized ResourceBundle getResourceBundle() {
return resourceBundle ;
}
public synchronized String getDescription( EvaluatedDeclaration element ) {
Description desc ;
if (element instanceof EvaluatedClassDeclaration) {
EvaluatedClassDeclaration ecd = (EvaluatedClassDeclaration)element;
desc = getFirstAnnotationOnClass(ecd, Description.class ) ;
} else {
desc = getAnnotation( element.element(), Description.class ) ;
}
String result = "" ;
if (desc != null) {
result = desc.value() ;
}
if (result.length() == 0) {
result = Exceptions.self.noDescriptionAvailable() ;
} else {
if (resourceBundle != null) {
result = resourceBundle.getString( result ) ;
}
}
return result ;
}
@TraceRegistration
public synchronized void addAnnotation( AnnotatedElement element,
Annotation annotation ) {
checkRootNotCreated("addAnnotation");
if (annotation == null) {
throw Exceptions.self.cannotAddNullAnnotation( element ) ;
}
Map<Class, Annotation> map = addedAnnotations.get( element ) ;
if (map == null) {
message( "Creating new Map<Class,Annotation>" ) ;
map = new HashMap<Class, Annotation>() ;
addedAnnotations.put( element, map ) ;
}
Class<?> annotationType = annotation.annotationType() ;
Annotation ann = map.get( annotationType ) ;
if (ann != null) {
message( "Duplicate annotation") ;
throw Exceptions.self.duplicateAnnotation( element,
annotation.getClass().getName()) ;
}
map.put( annotationType, annotation ) ;
}
@TraceRegistration
public synchronized void addInheritedAnnotations( final Class<?> cls ) {
checkRootNotCreated("addInheritedAnnotation");
}
public <T extends Annotation> T getFirstAnnotationOnClass(
final EvaluatedClassDeclaration element, final Class<T> type ) {
EvaluatedClassAnalyzer eca = new EvaluatedClassAnalyzer( element ) ;
List<EvaluatedClassDeclaration> ecds = eca.findClasses(
forAnnotation(type, EvaluatedClassDeclaration.class) ) ;
if (ecds.size() > 0) {
return getAnnotation( ecds.get(0).element(), type ) ;
} else {
return null ;
}
}
private Map<AnnotatedElement,Map<Class,Annotation>> annotationCache =
new WeakHashMap<AnnotatedElement,Map<Class,Annotation>>() ;
private Map<Class,Annotation> getAllAnnotations( final Class cls ) {
Map<Class,Annotation> result = annotationCache.get( cls ) ;
if (result == null) {
final Map<Class,Annotation> res =
new HashMap<Class,Annotation>() ;
ClassAnalyzer ca = ClassAnalyzer.getClassAnalyzer(cls) ;
ca.findClasses( new UnaryPredicate<Class<?>>() {
public boolean evaluate(Class arg) {
Annotation[] annots = arg.getDeclaredAnnotations() ;
for (Annotation anno : annots) {
putIfNotPresent( res, anno.annotationType(), anno ) ;
}
Map<Class,Annotation> emap = addedAnnotations.get( arg ) ;
if (emap != null) {
for (Map.Entry<Class,Annotation> entry : emap.entrySet()) {
putIfNotPresent( res, entry.getKey(),
entry.getValue()) ;
}
}
return true ;
}
}) ;
annotationCache.put( cls, res ) ;
result = res ;
}
return result ;
}
@SuppressWarnings({"unchecked"})
@TraceRegistrationFine
public synchronized <T extends Annotation> T getAnnotation(
AnnotatedElement element, Class<T> type ) {
if (element instanceof Class) {
Class cls = (Class)element ;
Map<Class,Annotation> annos = getAllAnnotations(cls) ;
return (T)annos.get( type ) ;
} else {
T result = element.getAnnotation( type ) ;
if (result == null) {
message( "No annotation on element: trying addedAnnotations map" ) ;
Map<Class, Annotation> map = addedAnnotations.get(
element );
if (map != null) {
result = (T)map.get( type ) ;
}
}
return result ;
}
}
@TraceRegistrationFine
public synchronized Collection<Annotation> getAnnotations(
AnnotatedElement elem ) {
if (elem instanceof Class) {
Class cls = (Class)elem ;
return getAllAnnotations( cls ).values() ;
} else if (elem instanceof Method) {
return Arrays.asList( elem.getAnnotations() ) ;
} else if (elem instanceof Field) {
return Arrays.asList( elem.getAnnotations() ) ;
} else {
throw Exceptions.self.annotationsNotSupported( elem ) ;
}
}
@TraceRegistration
public synchronized Pair<EvaluatedClassDeclaration,EvaluatedClassAnalyzer>
getClassAnalyzer( final EvaluatedClassDeclaration cls,
final Class<? extends Annotation> annotationClass ) {
final EvaluatedClassAnalyzer clsca = new EvaluatedClassAnalyzer( cls ) ;
final EvaluatedClassDeclaration annotatedClass = Algorithms.getFirst(
clsca.findClasses( forAnnotation( annotationClass,
EvaluatedClassDeclaration.class ) ),
new Runnable() {
public void run() {
throw Exceptions.self.noAnnotationFound(
annotationClass.getName(), cls.name() ) ;
}
} ) ;
describe( "annotatedClass", annotatedClass ) ;
final List<EvaluatedClassDeclaration> classes =
new ArrayList<EvaluatedClassDeclaration>() ;
classes.add( cls ) ;
final IncludeSubclass incsub = getFirstAnnotationOnClass(
cls, IncludeSubclass.class ) ;
if (incsub != null) {
for (Class<?> klass : incsub.value()) {
EvaluatedClassDeclaration ecd =
(EvaluatedClassDeclaration)TypeEvaluator.getEvaluatedType(klass) ;
classes.add( ecd ) ;
describe( "included subclass", klass ) ;
}
}
EvaluatedClassAnalyzer ca = new EvaluatedClassAnalyzer( classes ) ;
return new Pair<EvaluatedClassDeclaration,
EvaluatedClassAnalyzer>( annotatedClass, ca ) ;
}
@TraceRegistration
public synchronized List<InheritedAttribute> getInheritedAttributes(
final EvaluatedClassAnalyzer ca ) {
final UnaryPredicate<EvaluatedClassDeclaration> pred = Algorithms.or(
forAnnotation( InheritedAttribute.class,
EvaluatedClassDeclaration.class ),
forAnnotation( InheritedAttributes.class,
EvaluatedClassDeclaration.class ) ) ;
final List<EvaluatedClassDeclaration> iaClasses =
ca.findClasses( pred ) ;
List<InheritedAttribute> isList = Algorithms.flatten( iaClasses,
new UnaryFunction<EvaluatedClassDeclaration,List<InheritedAttribute>>() {
public List<InheritedAttribute> evaluate( EvaluatedClassDeclaration cls ) {
final InheritedAttribute ia = getFirstAnnotationOnClass(cls,
InheritedAttribute.class);
final InheritedAttributes ias = getFirstAnnotationOnClass(cls,
InheritedAttributes.class);
if ((ia != null) && (ias != null)) {
throw Exceptions.self.badInheritedAttributeAnnotation(cls) ;
}
final List<InheritedAttribute> result =
new ArrayList<InheritedAttribute>() ;
if (ia != null) {
result.add( ia ) ;
} else if (ias != null) {
result.addAll( Arrays.asList( ias.value() )) ;
}
return result ;
}
} ) ;
return isList ;
}
private class ADHolder implements UnaryPredicate<InheritedAttribute> {
private final EvaluatedMethodDeclaration method ;
private final ManagedObjectManagerInternal.AttributeDescriptorType adt ;
private AttributeDescriptor content ;
public ADHolder( final EvaluatedMethodDeclaration method,
ManagedObjectManagerInternal.AttributeDescriptorType adt ) {
this.method = method ;
this.adt = adt ;
}
public boolean evaluate( InheritedAttribute ia ) {
AttributeDescriptor ad = AttributeDescriptor.makeFromInherited(
ManagedObjectManagerImpl.this, method,
ia.id(), ia.methodName(), ia.description(), adt ) ;
boolean result = ad != null ;
if (result) {
content = ad ;
}
return result ;
}
public AttributeDescriptor content() {
return content ;
}
}
private AttributeDescriptor getAttributeDescriptorIfInherited(
final EvaluatedMethodDeclaration method,
final List<InheritedAttribute> ias,
final ManagedObjectManagerInternal.AttributeDescriptorType adt ) {
ADHolder adh = new ADHolder( method, adt ) ;
Algorithms.find( ias, adh ) ;
return adh.content() ;
}
@TraceRegistrationFine
public synchronized <K,V> void putIfNotPresent( final Map<K,V> map,
final K key, final V value ) {
if (!map.containsKey( key )) {
message( "Adding key, value to map" ) ;
map.put( key, value ) ;
} else {
message( "Key,value already in map" ) ;
}
}
static void checkFieldType( EvaluatedFieldDeclaration field ) {
if (!Modifier.isFinal( field.modifiers() ) ||
!field.fieldType().isImmutable()) {
Exceptions.self.illegalAttributeField(field) ;
}
}
public synchronized Pair<Map<String,AttributeDescriptor>,
Map<String,AttributeDescriptor>>
getAttributes(
final EvaluatedClassAnalyzer ca,
final ManagedObjectManagerInternal.AttributeDescriptorType adt ) {
try {
final Map<String,AttributeDescriptor> getters =
new HashMap<String,AttributeDescriptor>() ;
final Map<String,AttributeDescriptor> setters =
new HashMap<String,AttributeDescriptor>() ;
final Pair<Map<String,AttributeDescriptor>,
Map<String,AttributeDescriptor>> result =
new Pair<Map<String,AttributeDescriptor>,
Map<String,AttributeDescriptor>>( getters, setters ) ;
final List<InheritedAttribute> ias = getInheritedAttributes( ca ) ;
ca.findFields( new UnaryPredicate<EvaluatedFieldDeclaration>() {
public boolean evaluate( EvaluatedFieldDeclaration field ) {
ManagedAttribute ma = getAnnotation( field.element(),
ManagedAttribute.class ) ;
if (ma == null) {
return false ;
} else {
checkFieldType( field ) ;
Description desc = getAnnotation( field.element(),
Description.class ) ;
String description ;
if (desc == null) {
description = "No description available for "
+ field.name() ;
} else {
description = desc.value() ;
}
AttributeDescriptor ad =
AttributeDescriptor.makeFromAnnotated(
ManagedObjectManagerImpl.this, field,
ma.id(), description, adt ) ;
putIfNotPresent( getters, ad.id(), ad ) ;
return true ;
}
} } ) ;
ca.findMethods( new UnaryPredicate<EvaluatedMethodDeclaration>() {
public boolean evaluate( EvaluatedMethodDeclaration method ) {
ManagedAttribute ma = getAnnotation( method.element(),
ManagedAttribute.class ) ;
AttributeDescriptor ad ;
if (ma == null) {
ad = getAttributeDescriptorIfInherited( method, ias,
adt ) ;
} else {
Description desc = getAnnotation( method.element(),
Description.class ) ;
String description ;
if (desc == null) {
description = "No description available for "
+ method.name() ;
} else {
description = desc.value() ;
}
ad = AttributeDescriptor.makeFromAnnotated(
ManagedObjectManagerImpl.this,
method, ma.id(), description, adt ) ;
}
if (ad != null) {
if (ad.atype()==AttributeDescriptor.AttributeType.GETTER) {
putIfNotPresent( getters, ad.id(), ad ) ;
} else {
putIfNotPresent( setters, ad.id(), ad ) ;
}
}
return false ;
} } ) ;
return result ;
} finally {
}
}
public synchronized void setRegistrationDebug(
ManagedObjectManager.RegistrationDebugLevel level ) {
regDebugLevel = level ;
}
public synchronized void setJMXRegistrationDebug(boolean flag) {
jmxRegistrationDebugFlag = flag ;
}
public synchronized void setRuntimeDebug( boolean flag ) {
runDebugFlag = flag ;
}
public synchronized void setTypelibDebug( int level ) {
TypeEvaluator.setDebugLevel(level);
}
public synchronized String dumpSkeleton( Object obj ) {
MBeanImpl impl = tree.getMBeanImpl( obj ) ;
if (impl == null) {
return obj + " is not currently registered with mom " + this ;
} else {
MBeanSkeleton skel = impl.skeleton() ;
String skelString = myObjectUtil.objectToString( skel ) ;
return "Skeleton for MBean for object " + obj + ":\n"
+ skelString ;
}
}
public synchronized boolean registrationDebug() {
return regDebugLevel == ManagedObjectManager.RegistrationDebugLevel.NORMAL
|| regDebugLevel == ManagedObjectManager.RegistrationDebugLevel.FINE ;
}
public synchronized boolean registrationFineDebug() {
return regDebugLevel == ManagedObjectManager.RegistrationDebugLevel.FINE ;
}
public synchronized boolean runtimeDebug() {
return runDebugFlag ;
}
public synchronized boolean jmxRegistrationDebug() {
return jmxRegistrationDebugFlag ;
}
public synchronized void stripPrefix( String... args ) {
checkRootNotCreated("stripPrefix" ) ;
for (String str : args) {
typePrefixes.add( str ) ;
}
}
public synchronized <T extends EvaluatedDeclaration> UnaryPredicate<T> forAnnotation(
final Class<? extends Annotation> annotation,
final Class<T> cls ) {
return new UnaryPredicate<T>() {
public boolean evaluate( T elem ) {
return getAnnotation( elem.element(), annotation ) != null ;
}
} ;
}
public AMXMetadata getDefaultAMXMetadata() {
return DEFAULT_AMX_METADATA ;
}
public boolean isAMXAttributeName( String name ) {
return amxAttributeNames.contains( name ) ;
}
public void suppressDuplicateRootReport(boolean suppressReport) {
checkRootNotCreated("suppressDuplicateRootReport");
tree.setSuppressDuplicateSetRootReport( suppressReport ) ;
}
public ObjectRegistrationManager getObjectRegistrationManager() {
return orm ;
}
}