001: /*
002: * Copyright 2000-2004 The Apache Software Foundation
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: *
016: */
017: package org.apache.bcel.verifier;
018:
019: import java.util.ArrayList;
020: import java.util.HashMap;
021: import java.util.Iterator;
022: import java.util.Map;
023: import org.apache.bcel.classfile.JavaClass;
024: import org.apache.bcel.verifier.statics.Pass1Verifier;
025: import org.apache.bcel.verifier.statics.Pass2Verifier;
026: import org.apache.bcel.verifier.statics.Pass3aVerifier;
027: import org.apache.bcel.verifier.structurals.Pass3bVerifier;
028:
029: /**
030: * A Verifier instance is there to verify a class file according to The Java Virtual
031: * Machine Specification, 2nd Edition.
032: *
033: * Pass-3b-verification includes pass-3a-verification;
034: * pass-3a-verification includes pass-2-verification;
035: * pass-2-verification includes pass-1-verification.
036: *
037: * A Verifier creates PassVerifier instances to perform the actual verification.
038: * Verifier instances are usually generated by the VerifierFactory.
039: *
040: * @version $Id: Verifier.java 386056 2006-03-15 11:31:56Z tcurdt $
041: * @author Enver Haase
042: * @see org.apache.bcel.verifier.VerifierFactory
043: * @see org.apache.bcel.verifier.PassVerifier
044: */
045: public class Verifier {
046:
047: /**
048: * The name of the class this verifier operates on.
049: */
050: private final String classname;
051: /** A Pass1Verifier for this Verifier instance. */
052: private Pass1Verifier p1v;
053: /** A Pass2Verifier for this Verifier instance. */
054: private Pass2Verifier p2v;
055: /** The Pass3aVerifiers for this Verifier instance. Key: Interned string specifying the method number. */
056: private Map p3avs = new HashMap();
057: /** The Pass3bVerifiers for this Verifier instance. Key: Interned string specifying the method number. */
058: private Map p3bvs = new HashMap();
059:
060: /** Returns the VerificationResult for the given pass. */
061: public VerificationResult doPass1() {
062: if (p1v == null) {
063: p1v = new Pass1Verifier(this );
064: }
065: return p1v.verify();
066: }
067:
068: /** Returns the VerificationResult for the given pass. */
069: public VerificationResult doPass2() {
070: if (p2v == null) {
071: p2v = new Pass2Verifier(this );
072: }
073: return p2v.verify();
074: }
075:
076: /** Returns the VerificationResult for the given pass. */
077: public VerificationResult doPass3a(int method_no) {
078: String key = Integer.toString(method_no);
079: Pass3aVerifier p3av;
080: p3av = (Pass3aVerifier) (p3avs.get(key));
081: if (p3avs.get(key) == null) {
082: p3av = new Pass3aVerifier(this , method_no);
083: p3avs.put(key, p3av);
084: }
085: return p3av.verify();
086: }
087:
088: /** Returns the VerificationResult for the given pass. */
089: public VerificationResult doPass3b(int method_no) {
090: String key = Integer.toString(method_no);
091: Pass3bVerifier p3bv;
092: p3bv = (Pass3bVerifier) (p3bvs.get(key));
093: if (p3bvs.get(key) == null) {
094: p3bv = new Pass3bVerifier(this , method_no);
095: p3bvs.put(key, p3bv);
096: }
097: return p3bv.verify();
098: }
099:
100: /**
101: * Instantiation is done by the VerifierFactory.
102: *
103: * @see VerifierFactory
104: */
105: Verifier(String fully_qualified_classname) {
106: classname = fully_qualified_classname;
107: flush();
108: }
109:
110: /**
111: * Returns the name of the class this verifier operates on.
112: * This is particularly interesting when this verifier was created
113: * recursively by another Verifier and you got a reference to this
114: * Verifier by the getVerifiers() method of the VerifierFactory.
115: * @see VerifierFactory
116: */
117: public final String getClassName() {
118: return classname;
119: }
120:
121: /**
122: * Forget everything known about the class file; that means, really
123: * start a new verification of a possibly different class file from
124: * BCEL's repository.
125: *
126: */
127: public void flush() {
128: p1v = null;
129: p2v = null;
130: p3avs.clear();
131: p3bvs.clear();
132: }
133:
134: /**
135: * This returns all the (warning) messages collected during verification.
136: * A prefix shows from which verifying pass a message originates.
137: */
138: public String[] getMessages() throws ClassNotFoundException {
139: ArrayList messages = new ArrayList();
140: if (p1v != null) {
141: String[] p1m = p1v.getMessages();
142: for (int i = 0; i < p1m.length; i++) {
143: messages.add("Pass 1: " + p1m[i]);
144: }
145: }
146: if (p2v != null) {
147: String[] p2m = p2v.getMessages();
148: for (int i = 0; i < p2m.length; i++) {
149: messages.add("Pass 2: " + p2m[i]);
150: }
151: }
152: Iterator p3as = p3avs.values().iterator();
153: while (p3as.hasNext()) {
154: Pass3aVerifier pv = (Pass3aVerifier) p3as.next();
155: String[] p3am = pv.getMessages();
156: int meth = pv.getMethodNo();
157: for (int i = 0; i < p3am.length; i++) {
158: messages.add("Pass 3a, method "
159: + meth
160: + " ('"
161: + org.apache.bcel.Repository.lookupClass(
162: classname).getMethods()[meth] + "'): "
163: + p3am[i]);
164: }
165: }
166: Iterator p3bs = p3bvs.values().iterator();
167: while (p3bs.hasNext()) {
168: Pass3bVerifier pv = (Pass3bVerifier) p3bs.next();
169: String[] p3bm = pv.getMessages();
170: int meth = pv.getMethodNo();
171: for (int i = 0; i < p3bm.length; i++) {
172: messages.add("Pass 3b, method "
173: + meth
174: + " ('"
175: + org.apache.bcel.Repository.lookupClass(
176: classname).getMethods()[meth] + "'): "
177: + p3bm[i]);
178: }
179: }
180: String[] ret = new String[messages.size()];
181: for (int i = 0; i < messages.size(); i++) {
182: ret[i] = (String) messages.get(i);
183: }
184: return ret;
185: }
186:
187: /**
188: * Verifies class files.
189: * This is a simple demonstration of how the API of BCEL's
190: * class file verifier "JustIce" may be used.
191: * You should supply command-line arguments which are
192: * fully qualified namea of the classes to verify. These class files
193: * must be somewhere in your CLASSPATH (refer to Sun's
194: * documentation for questions about this) or you must have put the classes
195: * into the BCEL Repository yourself (via 'addClass(JavaClass)').
196: */
197: public static void main(String[] args) {
198: System.out
199: .println("JustIce by Enver Haase, (C) 2001-2002.\n<http://bcel.sourceforge.net>\n<http://jakarta.apache.org/bcel>\n");
200: for (int k = 0; k < args.length; k++) {
201: try {
202: if (args[k].endsWith(".class")) {
203: int dotclasspos = args[k].lastIndexOf(".class");
204: if (dotclasspos != -1) {
205: args[k] = args[k].substring(0, dotclasspos);
206: }
207: }
208: args[k] = args[k].replace('/', '.');
209: System.out.println("Now verifying: " + args[k] + "\n");
210: Verifier v = VerifierFactory.getVerifier(args[k]);
211: VerificationResult vr;
212: vr = v.doPass1();
213: System.out.println("Pass 1:\n" + vr);
214: vr = v.doPass2();
215: System.out.println("Pass 2:\n" + vr);
216: if (vr == VerificationResult.VR_OK) {
217: JavaClass jc = org.apache.bcel.Repository
218: .lookupClass(args[k]);
219: for (int i = 0; i < jc.getMethods().length; i++) {
220: vr = v.doPass3a(i);
221: System.out.println("Pass 3a, method number "
222: + i + " ['" + jc.getMethods()[i]
223: + "']:\n" + vr);
224: vr = v.doPass3b(i);
225: System.out.println("Pass 3b, method number "
226: + i + " ['" + jc.getMethods()[i]
227: + "']:\n" + vr);
228: }
229: }
230: System.out.println("Warnings:");
231: String[] warnings = v.getMessages();
232: if (warnings.length == 0) {
233: System.out.println("<none>");
234: }
235: for (int j = 0; j < warnings.length; j++) {
236: System.out.println(warnings[j]);
237: }
238: System.out.println("\n");
239: // avoid swapping.
240: v.flush();
241: org.apache.bcel.Repository.clearCache();
242: System.gc();
243: } catch (ClassNotFoundException e) {
244: e.printStackTrace();
245: }
246: }
247: }
248: }
|