KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > tools > verifier > apiscan > classfile > BCELClassFile


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 /*
25  * Main.java
26  *
27  * Created on August 10, 2004, 9:21 AM
28  */

29
30 package com.sun.enterprise.tools.verifier.apiscan.classfile;
31
32 import java.io.IOException JavaDoc;
33 import java.io.InputStream JavaDoc;
34 import java.util.ArrayList JavaDoc;
35 import java.util.Collection JavaDoc;
36 import java.util.Collections JavaDoc;
37 import java.util.HashSet JavaDoc;
38 import java.util.Iterator JavaDoc;
39 import java.util.List JavaDoc;
40 import java.util.Set JavaDoc;
41 import java.util.logging.Level JavaDoc;
42 import java.util.logging.Logger JavaDoc;
43
44 import com.sun.org.apache.bcel.internal.classfile.ClassParser;
45 import com.sun.org.apache.bcel.internal.classfile.ConstantClass;
46 import com.sun.org.apache.bcel.internal.classfile.DescendingVisitor;
47 import com.sun.org.apache.bcel.internal.classfile.EmptyVisitor;
48 import com.sun.org.apache.bcel.internal.classfile.Field;
49 import com.sun.org.apache.bcel.internal.classfile.JavaClass;
50 import com.sun.org.apache.bcel.internal.classfile.Method;
51
52 /**
53  * This is an implementation of {@link ClassFile} interface. It uses Apache's
54  * BCEL library in its implementation.
55  * This is a thread safe implementation of ClassFile interface.
56  * This is NOT a public class. Access thru' {@link ClassFile} interface.
57  * Use {@link ClassFileLoaderFactory} to create new instances of this class.
58  *
59  * @author Sanjeeb.Sahoo@Sun.COM
60  */

61 class BCELClassFile implements ClassFile {
62
63     private JavaClass jc;
64     private Set JavaDoc<String JavaDoc> classNames;
65     private HashSet JavaDoc<BCELMethod> methods = new HashSet JavaDoc<BCELMethod>();
66     private static Logger JavaDoc logger = Logger.getLogger("apiscan.classfile"); // NOI18N
67
//This is constant used during logging
68
private static final String JavaDoc myClassName = "apiscan.classfile.BCELClassFile"; // NOI18N
69

70     /**
71      * @param is is could be a Zip or Jar InputStream or a regular
72      * InputStream.
73      * @param file_name is the name of the .class file. If is a Zip or Jar Input
74      * stream, then this name should just be the entry path,
75      * because it is used internally in the is.getEntry(file_name)
76      * to locate the .class file. If is is a regular stream,
77      * then file_name should not be really needed, I don't have
78      * a choice as BCEL ClassFile does not have a constructor
79      * that just takes an InputStream. Any way, if is is a
80      * regular stream, then it should either be the internal
81      * name of the class or the path to the actual .class file
82      * that the input stream represents. This constructor does
83      * not check if the ClassFile created here indeed
84      * represents the class that is being requested. That check
85      * should be done by ClassFileLoader.
86      */

87     public BCELClassFile(InputStream JavaDoc is, String JavaDoc file_name) throws IOException JavaDoc {
88         logger.entering(myClassName, "<init>(InputStream, String)", file_name); // NOI18N
89
jc = new ClassParser(is, file_name).parse();
90     }
91     
92     //In contrast to the other constructor, here class_path is the path to the
93
// .class file.
94
/**
95      * @param file_path Absolute path to the .class file.
96      */

97     public BCELClassFile(String JavaDoc file_path) throws IOException JavaDoc {
98         logger.entering(myClassName, "<init>(String)", file_path); // NOI18N
99
jc = new ClassParser(file_path).parse();
100     }
101
102     /* Now the ClassFile interface implementation methods */
103     
104     //See ClassFile interface for description.
105
public synchronized Collection JavaDoc getAllReferencedClassNamesInInternalForm() {
106         if (classNames == null) {
107             classNames = new HashSet JavaDoc<String JavaDoc>();//lazy instantiation
108
logger.logp(Level.FINER, myClassName, "getAllReferencedClassNames", // NOI18N
109
"Starting to visit"); // NOI18N
110
jc.accept(new DescendingVisitor(jc, new Visitor(this)));
111             logger.logp(Level.FINER, myClassName, "getAllReferencedClassNames", // NOI18N
112
"Finished visting"); // NOI18N
113
classNames = Collections.unmodifiableSet(classNames);
114         }
115         return classNames;
116     }
117
118     public synchronized Collection JavaDoc<String JavaDoc> getAllReferencedClassNames() {
119         if (classNames == null) {
120             getAllReferencedClassNamesInInternalForm();
121         }
122         HashSet JavaDoc<String JavaDoc> extClassNames = new HashSet JavaDoc<String JavaDoc>(classNames.size());
123         for (Iterator JavaDoc i = classNames.iterator(); i.hasNext();) {
124             extClassNames.add(Util.convertToExternalClassName((String JavaDoc) i.next()));
125         }
126         return extClassNames;
127     }
128
129     //See ClassFile interface for description.
130
//see getInternalName() as well
131
//IMPORTANT: Does not deal with the case where Goo is an inner class in
132
// Foo$Bar class.
133
//It should return Foo$Bar.Goo, but it returns Foo$Bar$Goo
134
//Irrespective of this, it can be safely used from getInternalName()
135
public String JavaDoc getName() {
136         return jc.getClassName();
137     }
138
139     //See ClassFile interface for description.
140
public String JavaDoc getInternalName() {
141         return Util.convertToInternalClassName(getName());
142     }
143
144     //See ClassFile interface for description.
145
public String JavaDoc getPackageName() {
146         //not necessary as we always use external name for package. .replace('.','/');
147
return jc.getPackageName();
148     }
149
150     public Collection JavaDoc<? extends com.sun.enterprise.tools.verifier.apiscan.classfile.Method>
151             getMethods() {
152         return Collections.unmodifiableSet(methods);
153     }
154
155     public com.sun.enterprise.tools.verifier.apiscan.classfile.Method
156             getMethod(MethodRef methodRef) {
157         throw new UnsupportedOperationException JavaDoc();
158     }
159
160     public String JavaDoc getNameOfSuperClass() {
161         return jc.getSuperclassName();
162     }
163
164     public String JavaDoc getInternalNameOfSuperClass() {
165         return Util.convertToInternalClassName(getNameOfSuperClass());
166     }
167
168     public String JavaDoc[] getNamesOfInterfaces() {
169         return jc.getInterfaceNames();
170     }
171
172     public String JavaDoc[] getInternalNamesOfInterfaces() {
173         String JavaDoc[] result = getNamesOfInterfaces();
174         for(int i = 0; i< result.length; ++i) {
175             result[i] = Util.convertToInternalClassName(result[i]);
176         }
177         return result;
178     }
179
180     public boolean isInterface() {
181         return !jc.isClass();
182     }
183
184     public String JavaDoc toString() {
185         return
186                 "External Name: " + getName() + "\n" + // NOI18N
187
"Internal Name: " + getInternalName() + "\n" + // NOI18N
188
jc.toString()
189                 + "\n------------CONSTANT POOL BEGIN--------------\n" // NOI18N
190
+ jc.getConstantPool()
191                 + "\n------------CONSTANT POOL END--------------"; // NOI18N
192
}
193
194     //returns a list of all the classnames embedded in the given signature string.
195
//This method knows about basic data types, so for them classname is not returned.
196
//e.g. given below are the signature string and class name that would be
197
// returned by this call...
198
// Ljava/lang/Integer; {java/lang/Integer}
199
// [Ljava/lang/Integer; {java/lang/Integer}
200
// [[I {}
201
// I {I}
202
// (F[La/b/P;La/b/Q;[[La/b/P;)I {a/b/P, a/b/Q, a/b/P}
203
// a method like "int foo(float f, a/b/P[] ps, a/b/Q q, a/b/P[][] pss)" will
204
// have above signature.
205
private static List JavaDoc<String JavaDoc> signatureToClassNames(String JavaDoc signature) {
206         logger.entering(myClassName, "signatureToClassNames", signature); // NOI18N
207
List JavaDoc<String JavaDoc> result = new ArrayList JavaDoc<String JavaDoc>();
208         int i = 0;
209         while ((i = signature.indexOf('L', i)) != -1) {
210             int j = signature.indexOf(';', i);
211             if (j > i) {
212                 // get name, minus leading 'L' and trailing ';'
213
String JavaDoc className = signature.substring(i + 1, j);
214                 if (!Util.isPrimitive(className)) result.add(className);
215                 i = j + 1;
216             } else
217                 break;
218         }
219         if (logger.isLoggable(Level.FINE)) {
220             StringBuffer JavaDoc sb = new StringBuffer JavaDoc("Class Names are {"); // NOI18N
221
int size = result.size();
222             for (int k = 0; k < size; k++) {
223                 sb.append((String JavaDoc) result.get(k));
224                 if (k != size - 1) sb.append(", "); // NOI18N
225
}
226             sb.append("}"); // NOI18N
227
logger.finer(sb.toString());
228         }
229         return result;
230     }
231
232     //an inner class
233
private class Visitor extends EmptyVisitor {
234         BCELClassFile cf;
235         public Visitor(BCELClassFile cf) {
236             this.cf = cf;
237         }
238
239         /* Now override the visitor methods of our interest from EmptyVisitor class. */
240         /**
241          */

242         public void visitConstantClass(ConstantClass obj) {
243             logger.entering(myClassName, "visitConstantClass", obj); // NOI18N
244
String JavaDoc className = obj.getBytes(jc.getConstantPool());
245             logger.finer("Class name is " + className); // NOI18N
246
//sometimes we get names like Ljava.lang.Integer; or [I. So we need
247
// to decode the names.
248
//A good test case is java/io/ObjectInputStream.class
249
if (className.indexOf(';') != -1 || className.indexOf('[') != -1) {
250                 classNames.addAll(signatureToClassNames(className));
251             } else {
252                 classNames.add(className);
253             }
254         }
255
256         public void visitField(Field field) {
257             logger.entering(myClassName, "visitField", field); // NOI18N
258
String JavaDoc signature = field.getSignature();
259             logger.finer("Signature is " + signature); // NOI18N
260
//for BCEL 5.1, use field.getType().getSignature() if the above does
261
//not work
262
classNames.addAll(signatureToClassNames(signature));
263         }
264
265         public synchronized void visitMethod(Method method) {
266             logger.entering(myClassName, "visitMethod", method); // NOI18N
267
String JavaDoc signature = method.getSignature();
268             logger.finer("Signature is " + signature); // NOI18N
269
methods.add(new BCELMethod(cf, method));
270             classNames.addAll(signatureToClassNames(signature));
271         }
272     }//class Visitor
273
}
274
Popular Tags