org.glassfish.pfl.basic.algorithm.ClassAnalyzer Maven / Gradle / Ivy
/*
* Copyright (c) 2007, 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.basic.algorithm ;
import java.util.Collections ;
import java.util.List ;
import java.util.ArrayList ;
import java.lang.reflect.Method ;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Arrays;
import java.util.Map;
import java.util.WeakHashMap;
import org.glassfish.pfl.basic.func.UnaryPredicate;
/** Analyzes class inheritance hiearchy and provides methods for searching for
* classes and methods.
*/
public class ClassAnalyzer {
// General purpose class analyzer
//
// The basic problem is to determine for any class its linearized inheritance
// sequence. This is an old problem in OOP. For my purpose, I want the following
// to be true:
//
// Let C be a class, let C.super be C's superclass, and let C.inter be the list of
// C's implemented interfaces (C may be an interface, abstract, or concrete class).
// Define ILIST(C) to be a sequence that satisfies the following properties:
//
// 1. ILIST(C) starts with C.
// 2. If X is in ILIST(C), then so is X.super and each element of X.inter.
// 3. For any class X in ILIST(C):
// 2a. X appears before X.super in ILIST(C)
// 2b. X appears before any X.inter in ILIST(C)
// 4. No class appears more than once in ILIST(C)
//
// Note that the order can change when new classes are analyzed, so each class must be
// analyzed independently
//
// We need to elaborate on this idea to handle several issues:
//
// 1. We start with needing to determine whether a particular class C is ManagedData (mapped
// to composite data, and used for attribute and operation values in an Open MBean) or
// ManagedObject (mapped to an MBean with an ObjectName). We will require that the super
// class graph of any object contain at most one class annotated with @ManagedObject or
// @ManagedData (and not both). This means that for any class C, there is a class MC
// (which may be C) which is the unique class that is a superclass of C and is annotated
// with either @ManagedData or @ManagedObject.
// 2. The MC class may also contain InheritedAttribute and IncludeSubclass annotations.
// InheritedAttribute is handled by searching in the superclasses for getter and setters
// conforming to the InheritedAttribute id. IncludeSubclass extends the set of classes
// to scan for @ManagedAttribute and @ManagedOperation by the union of MC's superclasses,
// and the superclasses of all classes specified by IncludeSubclass.
// 3. What we require here is that ALL classes that share the same MC class translate to the
// SAME kind of MBean or CompositeData.
private static final Graph.Finder> finder = new Graph.Finder>() {
@Override
public List> evaluate( Class> arg ) {
List> result = new ArrayList>() ;
Class> sclass = arg.getSuperclass() ;
if (sclass != null) {
result.add( sclass ) ;
}
for (Class> cls : arg.getInterfaces() ) {
result.add( cls ) ;
}
return result ;
}
} ;
private static Map,ClassAnalyzer> caMap =
new WeakHashMap,ClassAnalyzer>() ;
public static synchronized ClassAnalyzer getClassAnalyzer( Class> cls ) {
ClassAnalyzer result = caMap.get( cls ) ;
if (result == null) {
result = new ClassAnalyzer(cls) ;
caMap.put( cls, result ) ;
}
return result ;
}
private List> classInheritance ;
private String contents = null ;
private ClassAnalyzer( Graph> gr ) {
List> result = new ArrayList>(
gr.getPostorderList() ) ;
Collections.reverse( result ) ;
classInheritance = result ;
}
private ClassAnalyzer( final Class> cls ) {
this( new Graph>( cls, finder ) ) ;
}
public List> findClasses( UnaryPredicate> pred ) {
final List> result = new ArrayList>() ;
for (Class> c : classInheritance) {
if (pred.evaluate( c )) {
result.add( c ) ;
}
}
return result ;
}
private static List getDeclaredMethods( final Class> cls ) {
SecurityManager sman = System.getSecurityManager() ;
if (sman == null) {
return Arrays.asList( cls.getDeclaredMethods() ) ;
} else {
return AccessController.doPrivileged(
new PrivilegedAction>() {
@Override
public List run() {
return Arrays.asList( cls.getDeclaredMethods() ) ;
}
}
) ;
}
}
// Tested by testFindMethod
// Tested by testGetAnnotatedMethods
public List findMethods( UnaryPredicate pred ) {
final List result = new ArrayList() ;
for (Class> c : classInheritance) {
for (Method m : getDeclaredMethods( c )) {
if (pred.evaluate( m )) {
result.add( m ) ;
}
}
}
return result ;
}
@Override
public synchronized String toString() {
if (contents == null) {
StringBuilder sb = new StringBuilder() ;
boolean first = true ;
sb.append( "ClassAnalyzer[" ) ;
for (Class> cls : classInheritance) {
if (first) {
first = false ;
} else {
sb.append( " " ) ;
}
sb.append( cls.getSimpleName() ) ;
}
sb.append( "]" ) ;
contents = sb.toString() ;
}
return contents ;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy