![JAR search and dependency download from the Maven repository](/logo.png)
org.glassfish.pfl.tf.spi.MethodMonitorRegistry Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of webservices-rt Show documentation
Show all versions of webservices-rt Show documentation
This module contains the Metro runtime code.
/*
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0, which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
package org.glassfish.pfl.tf.spi;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;
import org.glassfish.pfl.basic.contain.SynchronizedHolder;
import org.glassfish.pfl.tf.spi.annotation.MethodMonitorGroup;
/** Main class for registering MethodMonitorFactories against particular
* annotation classes that represent method monitor groups. This
*
* @author ken
*/
public class MethodMonitorRegistry {
private static final Set mmAnnotations =
new HashSet() ;
/** Merges the behaviors of the method monitors together.
*
*/
public synchronized static MethodMonitor merge( MethodMonitor[] mms) {
return null ;
}
public synchronized static Set getMMAnnotations() {
return new HashSet( mmAnnotations ) ;
}
public synchronized static void registerAnnotationFile( final String fname ) {
try {
// Read tracing annotation property file into mmAnnotations.
final ResourceBundle rb = ResourceBundle.getBundle( fname ) ;
String obj = rb.getString( "org.glassfish.tf.annotations.size" ) ;
int size = 0 ;
if (obj != null) {
size = Integer.valueOf( obj ) ;
}
for (int ctr=1; ctr<=size; ctr++) {
obj = rb.getString( "org.glassfish.tf.annotation." + ctr ) ;
mmAnnotations.add( obj ) ;
}
} catch (Exception exc) {
System.out.println( "Exception: " + exc ) ;
}
}
// Maps traceables class to the list of TimingPointTypes corresponding to
// the method name (as in classToMNames). The type for all MM names is
// NONE, while the type for info maethods InfoMethods is taken from the
// @InfoMethod annotation.
private static final Map,List> classToTimerTypes =
new HashMap,List>() ;
private static final Map,List> classToTimerNames =
new HashMap,List>() ;
// Maps traceable classes to the list of method names (which is in the order
// used in the generated code, so the index of a method name is the number
// used in the generated code).
private static final Map,List> classToMNames =
new HashMap,List>() ;
// Maps traceable classes to a Map from Annotation class to the
// MethodMonitor Holder, which allows easy and safe updates to the
// MethodMonitor.
private static final Map,
Map,
SynchronizedHolder>> classToAnnoMM =
new HashMap,
Map,
SynchronizedHolder>>() ;
// For each MM Annotation, lists all of the immediate subgroups.
private static final Map,
Set>> subgroups =
new HashMap,
Set>>() ;
// For each MM Annotation, lists all MM annotations reachable via subgroups.
// This is the reflexive, transitive closure of subgroups.
private static final Map,
Set>> subgroupsTC =
new HashMap,
Set>>() ;
// For each MM Annotation, lists all traceable Classes that
// have that annotation.
private static final Map,
Set>> annotationToClasses =
new HashMap,Set>>() ;
// For each MM Annotation, give the registered MethodMonitorFactory (if any)
private static final Map,
MethodMonitorFactory> annotationToMMF =
new HashMap,MethodMonitorFactory>() ;
// For each MM Annotation a, give the set of all MethodMonitorFactory
// instances that are registered to any element of subgroupsTC(a).
private static final Map,
Set> annotationToMMFSets =
new HashMap,Set>() ;
// For each MM Annotation a, give the composition of annotationToMMFSets(a).
private static final Map,
MethodMonitorFactory> annotationToMMFComposition =
new HashMap,MethodMonitorFactory>() ;
private static void updateTracedClass( Class> cls ) {
Map,SynchronizedHolder> map =
classToAnnoMM.get( cls ) ;
for (Map.Entry,
SynchronizedHolder> entry : map.entrySet() ) {
MethodMonitorFactory mmf =
annotationToMMFComposition.get( entry.getKey() ) ;
if (mmf == null) {
entry.getValue().content( null ) ;
} else {
entry.getValue().content( mmf.create( cls )) ;
}
}
}
private static void updateAnnotation( Class extends Annotation> annot ) {
// update annotationToMMFSets from annotationToMMF and subgroupsTC
Set mmfs = new HashSet() ;
annotationToMMFSets.put( annot, mmfs ) ;
final Set> relatedAnnos =
subgroupsTC.get( annot ) ;
for (Class extends Annotation> key : relatedAnnos) {
MethodMonitorFactory mmf = annotationToMMF.get( key ) ;
if (mmf != null) {
mmfs.add( mmf ) ;
}
}
// update annotationsToMMFComposition from annotationToMMFSets
annotationToMMFComposition.put( annot,
MethodMonitorFactoryDefaults.compose( mmfs ) ) ;
// update the classes that are annotated by this annotation.
final Set> classes = annotationToClasses.get(annot) ;
if (classes != null) {
for (Class> cls : classes) {
updateTracedClass( cls ) ;
}
}
}
// Called after the subgroups relation has changed. This forces
// recomputation of annotationToMMFSets and annotationsToMMFComposition,
// and also updates to all registered classes in the
// annotationToClasses map.
private static void doFullUpdate() {
for (Class extends Annotation> annot : annotationToMMF.keySet() ) {
updateAnnotation( annot ) ;
}
for (Class> key : classToAnnoMM.keySet()) {
updateTracedClass( key ) ;
}
}
private static boolean scanClassAnnotations( final Class> cls ) {
boolean updated = false ;
boolean hasMMAnnotation = false ;
for (Annotation anno : cls.getAnnotations()) {
final Class extends Annotation> annoClass =
anno.annotationType() ;
final MethodMonitorGroup mmg =
annoClass.getAnnotation( MethodMonitorGroup.class ) ;
if (mmg != null) {
hasMMAnnotation = true ;
Set> target = annotationToClasses.get( annoClass ) ;
if (target == null) {
target = new HashSet>() ;
annotationToClasses.put( annoClass, target ) ;
}
target.add( cls ) ;
if (scanAnnotation( annoClass, mmg ) ) {
updated = true ;
}
}
}
if (!hasMMAnnotation) {
throw new RuntimeException( "Class " + cls + " is not traceable" ) ;
}
return updated ;
}
private static boolean scanAnnotation(
final Class extends Annotation> annoClass,
final MethodMonitorGroup mmg ) {
boolean updated = false ;
if (!subgroups.containsKey( annoClass )) {
updated = true ;
Set> acs =
new HashSet>( Arrays.asList(
mmg.value() ) ) ;
subgroups.put( annoClass, acs ) ;
computeTransitiveClosure() ;
}
return updated ;
}
private static void computeTransitiveClosure() {
subgroupsTC.clear() ;
for (Class extends Annotation> anno : subgroups.keySet()) {
Set> memset =
new HashSet>() ;
subgroupsTC.put( anno, memset ) ;
}
for (Class extends Annotation> anno : subgroupsTC.keySet()) {
dfs( anno, anno ) ;
}
}
private static void dfs( Class extends Annotation> src,
Class extends Annotation> dest ) {
Set> images = subgroupsTC.get( src ) ;
images.add( dest ) ;
Set> temp = subgroups.get(dest) ;
if (temp != null) {
for (Class extends Annotation> anno : temp) {
if (!images.contains( anno )) {
dfs( src, anno ) ;
}
}
}
}
private static String getExternalName( String name ) {
return name.replace( '/', '.' ) ;
}
private static final MethodMonitorGroup checkAnnotation(
Class extends Annotation> annoClass ) {
final MethodMonitorGroup mmg =
annoClass.getAnnotation( MethodMonitorGroup.class ) ;
if (mmg == null) {
throw new RuntimeException( "Annotation " + annoClass
+ " does not have the MethodMonitorGroup annotation" ) ;
} else {
return mmg ;
}
}
/** Register a class with the tracing facility. The class must be an
* instrumented class that is annotated with an annotation with a
* meta-annotation of @MethodMonitorGroup. Note that this method should
* only be called from the enhanced class, not directly by the user.
*
* @param cls Class to register, which must have 1 or more MM annotations.
* @param methodNames The list of method names used in the enhanced code.
* The index of the name is the value used in the method.
* @param annoMM The MM holders for each MM annotation on the class.
*/
public synchronized static void registerClass( final Class> cls,
final List methodNames,
final Map,
SynchronizedHolder> annoMM ) {
final boolean fullUpdate = scanClassAnnotations( cls ) ;
classToMNames.put( cls, methodNames ) ;
classToAnnoMM.put( cls, annoMM ) ;
if (fullUpdate) {
doFullUpdate() ;
} else {
updateTracedClass( cls ) ;
}
}
/** Register a class with the tracing facility. This form assumes that
* all of the computation for method names and the mapping from annotation
* name to MM holder is done at registration time, rather than in the
* bytecode enhancer. This shortens the generated bytecode noticeably.
* @param cls
*/
public synchronized static void registerClass( final Class> cls ) {
Util util = new Util( false, 0 ) ;
EnhancedClassData ecd = new EnhancedClassDataReflectiveImpl(
util, cls) ;
final boolean fullUpdate = scanClassAnnotations( cls ) ;
classToMNames.put( cls, ecd.getMethodNames() ) ;
classToTimerTypes.put( cls, ecd.getTimingPointTypes() ) ;
classToTimerNames.put( cls, ecd.getTimingPointNames() ) ;
final Map,
SynchronizedHolder> annoMM =
new HashMap,
SynchronizedHolder>() ;
for (Map.Entry entry :
ecd.getAnnotationToHolderName().entrySet() ) {
try {
final String aname = entry.getKey() ; // annotation name
final String fname = entry.getValue() ; // field name
final Field fld = cls.getDeclaredField( fname ) ;
// XXX needs doPrivileged if non-null SecurityManager
fld.setAccessible(true) ;
final SynchronizedHolder sh =
new SynchronizedHolder() ;
fld.set( null, sh) ;
final String axname = getExternalName( aname ) ;
// This assumes that the class and its annotations are all available in
// the same ClassLoader. In OSGi, this means that the class and its
// annotations are in the same OSGi bundle, which is a reasonable
// restriction.
Class extends Annotation> aclass =
(Class extends Annotation>)Class.forName( axname, true,
cls.getClassLoader() ) ;
annoMM.put( aclass, sh ) ;
} catch (Exception exc) {
System.out.println( "Exceptionn MethodMonitorRegistry.registerClass: " + exc ) ;
}
}
classToAnnoMM.put( cls, annoMM ) ;
if (fullUpdate) {
doFullUpdate() ;
} else {
updateTracedClass( cls ) ;
}
}
public synchronized static List getMethodNames( Class> cls ) {
return classToMNames.get( cls ) ;
}
/** Provided so that implementation of the MethodMonitor interface can
* obtain the method name for use in log reports or for other purposes.
*
* @param cls The enhanced class
* @param identifier An Integer representing the method name.
* @return The name of the method corresponding to the identifier.
*/
public synchronized static String getMethodName( Class> cls, int identifier ) {
List names = classToMNames.get( cls ) ;
if (names == null) {
throw new RuntimeException( "Class " + cls + " not found in map" ) ;
}
if (identifier < 0 || identifier >= names.size()) {
throw new RuntimeException( "identifier is out of range" ) ;
}
return names.get( identifier ) ;
}
public synchronized static int getMethodIdentifier( Class> cls, String mname ) {
List names = classToMNames.get( cls ) ;
if (names == null) {
throw new RuntimeException( "Class " + cls + " not found in map" ) ;
}
for (int ctr=0; ctr annot,
MethodMonitorFactory mmf ) {
final boolean fullUpdate = scanAnnotation( annot,
checkAnnotation( annot ) );
annotationToMMF.put( annot, mmf ) ;
if (fullUpdate) {
doFullUpdate() ;
} else {
updateAnnotation( annot ) ;
}
}
/** Remove the MethodMonitorFactory (if any) that is associated with annot.
*
* @param annot
*/
public synchronized static void clear( Class extends Annotation> annot ) {
final boolean fullUpdate = scanAnnotation( annot,
checkAnnotation( annot ) );
annotationToMMF.remove( annot ) ;
if (fullUpdate) {
doFullUpdate() ;
} else {
updateAnnotation( annot ) ;
}
}
/** Return the MethodMonitorFactory registered against the annotation, or
* null if nothing is registered.
*
* @param annot A class representing an annotation, which must itself
* have a MethodMonitorGroup meta-annotation.
* @return The MethodMonitorFactory for annot.
*/
public synchronized static MethodMonitorFactory registeredFactory(
Class extends Annotation> annot ) {
final boolean fullUpdate = scanAnnotation( annot,
checkAnnotation( annot ) );
if (fullUpdate) {
doFullUpdate() ;
}
return annotationToMMF.get( annot ) ;
}
/** Return the current MethodMonitor in use for the given cls and annot.
* Returns null if no MethodMonitor is in use. Throws an exception if
* either cls is not a traced class, or annot is not a tracing annotation
* on cls.
*
* @param cls The Traced class.
* @param annot A trace annotation on cls.
* @return The MethodMonitor, if any.
*/
public synchronized static MethodMonitor getMethodMonitorForClass( final Class> cls,
final Class extends Annotation> annot ) {
Map,SynchronizedHolder> map =
classToAnnoMM.get( cls ) ;
if (map == null) {
throw new RuntimeException( "Class "
+ cls + " is not a traced class.") ;
}
SynchronizedHolder holder = map.get( annot ) ;
if (holder == null) {
throw new RuntimeException( "Annotation " + annot
+ " is not a tracing annotation defined on class " + cls ) ;
}
return holder.content() ;
}
/** Return a list of all timer types defined for cls. This is in the same
* order as classToMNames.get(cls).
* @param cls The monitored class to use.
* @return A list of timer types in the same order as the method names.
*/
public synchronized static List getTimerTypes( final Class> cls ) {
return classToTimerTypes.get( cls ) ;
}
public synchronized static List getTimerNames( final Class> cls ) {
return classToTimerNames.get( cls ) ;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy