001: /*
002: * Copyright 2001-2007 Geert Bevin <gbevin[remove] at uwyn dot com>
003: * Distributed under the terms of either:
004: * - the common development and distribution license (CDDL), v1.0; or
005: * - the GNU Lesser General Public License, v2.1 or later
006: * $Id: ConstrainedDetector.java 3811 2007-06-25 15:06:16Z gbevin $
007: */
008: package com.uwyn.rife.site.instrument;
009:
010: import com.uwyn.rife.asm.*;
011:
012: import com.uwyn.rife.instrument.exceptions.ClassBytesNotFoundException;
013: import com.uwyn.rife.instrument.exceptions.VisitInterruptionException;
014: import com.uwyn.rife.tools.ClassBytesLoader;
015:
016: /**
017: * Detects whether class implements the {@code Constrainted} interface or not,
018: * by analyzing its bytecode.
019: *
020: * @author Geert Bevin (gbevin[remove] at uwyn dot com)
021: * @version $Revision: 3811 $
022: * @since 1.6
023: */
024: public class ConstrainedDetector {
025: private final String CONSTRAINED_INTERNAL_NAME = "com/uwyn/rife/site/Constrained";
026: private final String CONSTRAINED_NAME = "com.uwyn.rife.site.Constrained";
027: private final String OBJECT_INTERNAL_NAME = "java/lang/Object";
028:
029: private ClassBytesLoader mBytesLoader = null;
030:
031: /**
032: * Creates new instance by providing a loader that is able to retrieve the
033: * bytes of any parent classes that are extended by the class that is
034: * being analyzed.
035: *
036: * @param bytesLoader the loader that will be used to retrieve the bytes
037: * of the additional classes
038: * @since 1.6
039: */
040: public ConstrainedDetector(ClassBytesLoader bytesLoader) {
041: mBytesLoader = bytesLoader;
042: }
043:
044: /**
045: * Verifies if the Constrained interface is implemented by the class that
046: * is defined by the bytes that are provided.
047: *
048: * @param internedClassname the class name as the previously interned
049: * string
050: * @param bytes the array of bytes that defines the class that needs to be
051: * analyzed
052: * @return {@code true} if the analyzed class implements the constrained
053: * interface; or
054: * <p>{@code false} otherwise
055: * @exception ClassBytesNotFoundException when the bytes of a parent class
056: * can be found
057: * @since 1.6
058: */
059: public boolean isConstrained(String internedClassname, byte[] bytes)
060: throws ClassBytesNotFoundException {
061: if (CONSTRAINED_NAME == internedClassname) {
062: return false;
063: }
064:
065: ConstrainedDetectionClassVisitor visitor = new ConstrainedDetectionClassVisitor();
066: ClassReader detection_reader = null;
067:
068: while (!visitor.isConstrained()) {
069: detection_reader = new ClassReader(bytes);
070: try {
071: detection_reader.accept(visitor, true);
072: } catch (VisitInterruptionException e) {
073: // do nothing
074: }
075:
076: if (null == visitor.getSuperNameInternal()
077: || OBJECT_INTERNAL_NAME == visitor
078: .getSuperNameInternal()) {
079: break;
080: }
081:
082: // get the parent's class' bytecode
083: if (!visitor.isConstrained()) {
084: String filename = visitor.getSuperNameInternal()
085: + ".class";
086: try {
087: bytes = mBytesLoader.getClassBytes(filename);
088: } catch (ClassNotFoundException e) {
089: throw new ClassBytesNotFoundException(filename, e);
090: }
091: }
092: }
093:
094: return visitor.isConstrained();
095: }
096:
097: private class ConstrainedDetectionClassVisitor implements
098: ClassVisitor {
099: private boolean mIsConstrained = false;
100: private String mSuperNameInternal = null;
101:
102: private boolean isConstrained() {
103: return mIsConstrained;
104: }
105:
106: private String getSuperNameInternal() {
107: return mSuperNameInternal;
108: }
109:
110: public void visit(int version, int access, String name,
111: String signature, String super Name, String[] interfaces) {
112: for (String interface_name : interfaces) {
113: if (CONSTRAINED_INTERNAL_NAME == interface_name
114: .intern()) {
115: mIsConstrained = true;
116: break;
117: }
118: }
119:
120: if (null == super Name) {
121: mSuperNameInternal = null;
122: } else {
123: mSuperNameInternal = super Name.intern();
124: }
125:
126: throw new VisitInterruptionException();
127: }
128:
129: public MethodVisitor visitMethod(int access, String name,
130: String desc, String signature, String[] exceptions) {
131: return null;
132: }
133:
134: public void visitInnerClass(String name, String outerName,
135: String innerName, int access) {
136: }
137:
138: public void visitOuterClass(String owner, String name,
139: String desc) {
140: }
141:
142: public FieldVisitor visitField(int access, String name,
143: String desc, String signature, Object value) {
144: return null;
145: }
146:
147: public void visitSource(String source, String debug) {
148: }
149:
150: public AnnotationVisitor visitAnnotation(String desc,
151: boolean visible) {
152: return null;
153: }
154:
155: public void visitAttribute(Attribute attr) {
156: }
157:
158: public void visitEnd() {
159: }
160: }
161: }
|