001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tcspring;
005:
006: import org.apache.commons.logging.Log;
007: import org.apache.commons.logging.LogFactory;
008:
009: import com.tc.asm.signature.SignatureReader;
010: import com.tc.asm.signature.SignatureVisitor;
011: import com.tc.aspectwerkz.reflect.ClassInfo;
012: import com.tc.aspectwerkz.reflect.FieldInfo;
013: import com.tc.aspectwerkz.reflect.impl.asm.AsmClassInfo;
014: import com.tc.object.bytecode.hook.DSOContext;
015:
016: import java.lang.reflect.Modifier;
017: import java.util.HashSet;
018: import java.util.LinkedList;
019: import java.util.Set;
020:
021: public class ClassHierarchyWalker {
022: private final transient Log logger = LogFactory.getLog(getClass());
023:
024: private final String id;
025: private final DSOContext dsoContext;
026:
027: private final LinkedList queue = new LinkedList();
028: private final Set processed = new HashSet(); // collection of class names
029:
030: public ClassHierarchyWalker(String id, DSOContext dsoContext) {
031: this .id = id;
032: this .dsoContext = dsoContext;
033: }
034:
035: public void walkClass(ClassInfo classInfo) {
036: addClassIfNeeded(classInfo);
037: walkThroughClassHierarchy();
038: }
039:
040: public void walkClass(String className, ClassLoader loader) {
041: try {
042: walkClass(AsmClassInfo.getClassInfo(className, loader));
043: } catch (Exception e) {
044: // System.err.println("### ClassHierarchyWalker.walkClass() "+e.getException());
045: logger.warn("Unable to read class " + className, e);
046: }
047: }
048:
049: private void walkThroughClassHierarchy() {
050: while (queue.size() > 0) {
051: ClassInfo classInfo = (ClassInfo) queue.removeFirst();
052: processed.add(classInfo.getName());
053:
054: addClassGenerics(classInfo.getGenericsSignature(),
055: classInfo.getClassLoader());
056:
057: String className = classInfo.getName();
058: logger.info(this .id + " registering include for "
059: + className);
060: // TODO add matching for subclasses
061: dsoContext.addInclude(className, true, "* " + className
062: + ".*(..)", classInfo);
063:
064: // TODO should we continue walking class hierarchy if include had been ignored?
065:
066: addClassIfNeeded(classInfo.getSuperclass());
067:
068: FieldInfo[] fields = classInfo.getFields();
069: for (int i = 0; i < fields.length; i++) {
070: FieldInfo fieldInfo = fields[i];
071: int modifiers = fieldInfo.getModifiers();
072: if ((modifiers & (Modifier.TRANSIENT | Modifier.STATIC)) == 0) {
073: ClassInfo fieldType = fieldInfo.getType();
074: while (fieldType.isArray()) {
075: fieldType = fieldType.getComponentType();
076: }
077: addClassIfNeeded(fieldType);
078:
079: addFieldGenerics(fieldInfo.getGenericsSignature(),
080: fieldType.getClassLoader());
081: }
082: }
083: }
084: }
085:
086: private void addClassIfNeeded(String name, ClassLoader loader) {
087: addClassIfNeeded(AsmClassInfo.getClassInfo(name, loader));
088: }
089:
090: private void addClassIfNeeded(ClassInfo classInfo) {
091: if (classInfo == null) {
092: return;
093: }
094: String className = classInfo.getName();
095: if (!classInfo.isInterface()
096: && !classInfo.isPrimitive()
097: && !"org.springframework.context.ApplicationEvent"
098: .equals(className) // XXX this must not be here
099: && !"java.lang.Object".equals(className)) {
100: if (!processed.contains(className)
101: && !queue.contains(classInfo)) {
102: queue.add(classInfo);
103: }
104: }
105: }
106:
107: private void addClassGenerics(String signature, ClassLoader loader) {
108: if (signature != null) {
109: SignatureReader signatureReader = new SignatureReader(
110: signature);
111: signatureReader.accept(new GenericsCollector(loader));
112: }
113: }
114:
115: private void addFieldGenerics(String signature, ClassLoader loader) {
116: if (signature != null) {
117: SignatureReader signatureReader = new SignatureReader(
118: signature);
119: signatureReader.accept(new GenericsCollector(loader));
120: }
121: }
122:
123: private final class GenericsCollector implements SignatureVisitor {
124: private final ClassLoader loader;
125:
126: public GenericsCollector(ClassLoader loader) {
127: this .loader = loader;
128: }
129:
130: public void visitClassType(String name) {
131: addClassIfNeeded(name, loader);
132: }
133:
134: public void visitInnerClassType(String name) {
135: addClassIfNeeded(name, loader);
136: }
137:
138: public void visitFormalTypeParameter(String name) {
139: //
140: }
141:
142: public void visitTypeVariable(String name) {
143: //
144: }
145:
146: public SignatureVisitor visitArrayType() {
147: return this ;
148: }
149:
150: public SignatureVisitor visitClassBound() {
151: return this ;
152: }
153:
154: public SignatureVisitor visitExceptionType() {
155: return this ;
156: }
157:
158: public SignatureVisitor visitInterface() {
159: return this ;
160: }
161:
162: public SignatureVisitor visitInterfaceBound() {
163: return this ;
164: }
165:
166: public SignatureVisitor visitParameterType() {
167: return this ;
168: }
169:
170: public SignatureVisitor visitReturnType() {
171: return this ;
172: }
173:
174: public SignatureVisitor visitSuperclass() {
175: return this ;
176: }
177:
178: public SignatureVisitor visitTypeArgument(char wildcard) {
179: return this ;
180: }
181:
182: public void visitBaseType(char descriptor) {
183: //
184: }
185:
186: public void visitTypeArgument() {
187: //
188: }
189:
190: public void visitEnd() {
191: //
192: }
193: }
194:
195: }
|