package org.glassfish.pfl.tf.spi;
import org.glassfish.pfl.tf.spi.annotation.MethodMonitorGroup;
import org.glassfish.pfl.tf.spi.annotation.InfoMethod;
import org.glassfish.pfl.tf.spi.annotation.Description;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.glassfish.pfl.objectweb.asm.Type;
public class EnhancedClassDataReflectiveImpl extends EnhancedClassDataBase {
private final Class<?> currentClass ;
private boolean isMMAnnotation( Annotation an ) {
return an.annotationType().isAnnotationPresent(
MethodMonitorGroup.class ) ;
}
private void processClassAnnotations() {
final Annotation[] classAnnotations =
currentClass.getAnnotations() ;
if (classAnnotations != null) {
for (Annotation an : classAnnotations) {
final String aname = Type.getInternalName( an.annotationType() ) ;
if (isMMAnnotation(an)) {
annoNamesForClass.add( aname ) ;
}
}
List<String> acnames = new ArrayList( annoNamesForClass ) ;
Collections.sort( acnames ) ;
int ctr=0 ;
for (String aname : acnames ) {
annoToHolderName.put( aname, "__$mm$__" + ctr ) ;
ctr++ ;
}
if (util.getDebug()) {
util.msg( "Enhancing class " + currentClass.getName() ) ;
util.msg( "\tannoNamesForClass = " + annoNamesForClass ) ;
util.msg( "\tannoToHolderName = " + annoToHolderName ) ;
}
}
}
private void scanMethods() {
final Method[] methods = currentClass.getDeclaredMethods() ;
Map<String,String> mmnToDescriptions =
new HashMap<String,String>() ;
Map<String,TimingPointType> mmnToTPT =
new HashMap<String,TimingPointType>() ;
Map<String,String> mmnToTPN =
new HashMap<String,String>() ;
Map<String,String> mmnToAnnotationName =
new HashMap<String,String>() ;
for (Method mn : methods) {
final String mname = mn.getName() ;
final String mdesc = util.getFullMethodDescriptor( mn ) ;
String monitoredMethodMMAnno = null ;
String shortClassName = className ;
int index = shortClassName.lastIndexOf( '/' ) ;
if (index >= 0) {
shortClassName = className.substring( index + 1 ) ;
}
String description = "Timer for method " + mname
+ " in class " + shortClassName ;
TimingPointType tpt = TimingPointType.BOTH ;
String tpName = mname ;
boolean hasMethodInfoAnno = false ;
final Annotation[] annotations = mn.getDeclaredAnnotations() ;
if (annotations != null) {
for (Annotation an : annotations) {
final String aname = Type.getInternalName(
an.annotationType() ) ;
if (aname.equals( DESCRIPTION_NAME )) {
Description desc = (Description)an ;
if (desc.value().length() > 0) {
description = desc.value() ;
}
} else if (aname.equals( INFO_METHOD_NAME)) {
tpt = TimingPointType.NONE ;
if (!util.hasAccess( mn.getModifiers(),
Modifier.PRIVATE )) {
util.error( "Method " + mdesc
+ " for Class " + currentClass.getName()
+ " is a non-private @InfoMethod,"
+ " which is not allowed" ) ;
}
hasMethodInfoAnno = true ;
InfoMethod im = (InfoMethod)an ;
tpt = im.tpType() ;
if (tpt != TimingPointType.NONE) {
String tpn = im.tpName() ;
if (tpn.length() == 0) {
util.error( "Method " + mdesc
+ " for Class " + currentClass.getName()
+ " is an info method with timing point type "
+ tpt + " but no tpName was specified" ) ;
} else {
tpName = tpn ;
}
}
} else if (annoNamesForClass.contains( aname)) {
if (monitoredMethodMMAnno == null) {
monitoredMethodMMAnno = aname ;
} else {
util.error( "Method " + mdesc
+ " for Class " + currentClass.getName()
+ "has multiple MM annotations" ) ;
}
} else if (isMMAnnotation( an )) {
util.error( "Method " + mdesc
+ " for Class " + currentClass.getName()
+ " has an MM annotation " + an + " which "
+ "is not present on its class" ) ;
}
}
if (hasMethodInfoAnno && monitoredMethodMMAnno != null) {
util.error( "Method " + mdesc
+ " for Class " + currentClass.getName()
+ " has both @InfoMethod annotation and"
+ " a MM annotation" ) ;
}
final boolean isStatic = util.hasAccess( mn.getModifiers(),
Modifier.STATIC ) ;
if (hasMethodInfoAnno && isStatic) {
util.error( "Method " + mdesc
+ " for Class " + currentClass.getName()
+ " is a static method, but must not be" ) ;
}
if (mname.equals( "<init>" )) {
if (hasMethodInfoAnno) {
util.error( "Constructors must not have an "
+ "@InfoMethod annotations") ;
} else if (monitoredMethodMMAnno != null) {
util.error( "Constructors must not have an "
+ "MM annotation") ;
}
}
mmnToAnnotationName.put(mname, monitoredMethodMMAnno ) ;
if (hasMethodInfoAnno || (monitoredMethodMMAnno != null)) {
methodNames.add( mname ) ;
mmnToDescriptions.put( mname, description ) ;
mmnToTPT.put( mname, tpt ) ;
mmnToTPN.put( mname, tpName ) ;
if (hasMethodInfoAnno) {
infoMethodDescs.add( mdesc ) ;
} else {
mmMethodDescs.add( mdesc ) ;
methodToAnno.put( mdesc, monitoredMethodMMAnno ) ;
}
}
}
}
Collections.sort( methodNames ) ;
for (String str : methodNames ) {
methodDescriptions.add( mmnToDescriptions.get( str ) ) ;
methodTPTs.add( mmnToTPT.get( str ) ) ;
methodTPNames.add( mmnToTPN.get( str ) ) ;
methodAnnoList.add( mmnToAnnotationName.get( str ) ) ;
}
if (util.getDebug()) {
util.msg( "\tinfoMethodSignature = " + infoMethodDescs ) ;
util.msg( "\tmmMethodSignature = " + mmMethodDescs ) ;
util.msg( "\tmethodNames = " + methodNames ) ;
util.msg( "\tmethodToAnno = " + methodToAnno ) ;
util.msg( "\tmethodDescriptions = " + methodDescriptions ) ;
util.msg( "\tmethodTPTs = " + methodTPTs ) ;
util.msg( "\tmethodTPTs = " + methodTPNames ) ;
}
}
public EnhancedClassDataReflectiveImpl( Util util,
Class<?> cn ) {
super( util, null ) ;
currentClass = cn ;
className = cn.getName() ;
processClassAnnotations() ;
scanMethods();
}
}