001: /*
002: * FindBugs - Find bugs in Java programs
003: * Copyright (C) 2004, University of Maryland
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: */
019:
020: /*
021: * Created on Sep 20, 2004
022: */
023: package edu.umd.cs.findbugs.ba;
024:
025: import java.io.IOException;
026: import java.util.HashMap;
027: import java.util.Map;
028:
029: import org.apache.bcel.classfile.JavaClass;
030: import org.apache.bcel.util.ClassPath;
031: import org.apache.bcel.util.Repository;
032:
033: import edu.umd.cs.findbugs.SystemProperties;
034: import edu.umd.cs.findbugs.annotations.NonNull;
035:
036: /**
037: * BCEL Repository implementation that uses an URLClassPath
038: * to find classes. This class has two specific improvements
039: * over BCEL's SyntheticRepository class:
040: * <ol>
041: * <li> Classpath elements may be added at any time, not
042: * just when the object is created.
043: * <li> Classpath elements can be URLs. This allows repository
044: * lookups to find classes via http URLs, jar URLs, etc.
045: * </ol>
046: * FindBugs requires and uses both of these capabilities.
047: *
048: * @author David Hovemeyer
049: */
050: public class URLClassPathRepository implements Repository {
051: public static final boolean DEBUG = SystemProperties
052: .getBoolean("findbugs.classpath.debug");
053:
054: private static final long serialVersionUID = 1L;
055:
056: private Map<String, JavaClass> nameToClassMap;
057: private URLClassPath urlClassPath;
058:
059: public URLClassPathRepository() {
060: this .nameToClassMap = new HashMap<String, JavaClass>();
061: this .urlClassPath = new URLClassPath();
062: }
063:
064: /**
065: * Clear the repository and close all underlying resources.
066: */
067: public void destroy() {
068: nameToClassMap.clear();
069: urlClassPath.close();
070: if (DEBUG) {
071: System.out.println("Destroying Repository");
072: }
073: }
074:
075: /**
076: * Add a filename or URL to the classpath.
077: * @param fileName filename or URL of classpath entry to add
078: * @throws IOException
079: */
080: public void addURL(String fileName) throws IOException {
081: urlClassPath.addURL(fileName);
082: }
083:
084: /* (non-Javadoc)
085: * @see org.apache.bcel.util.Repository#storeClass(org.apache.bcel.classfile.JavaClass)
086: */
087: public void storeClass(JavaClass javaClass) {
088: if (DEBUG)
089: System.out.println("Storing class "
090: + javaClass.getClassName() + " in repository");
091: JavaClass previous = nameToClassMap.put(javaClass
092: .getClassName(), javaClass);
093: if (DEBUG && previous != null) {
094: System.out.println("\t==> A previous class was evicted!");
095: dumpStack();
096: }
097: Repository tmp = org.apache.bcel.Repository.getRepository();
098: if (tmp != null && tmp != this )
099: throw new IllegalStateException(
100: "Wrong/multiple BCEL repository");
101: if (tmp == null)
102: org.apache.bcel.Repository.setRepository(this );
103: }
104:
105: /* (non-Javadoc)
106: * @see org.apache.bcel.util.Repository#removeClass(org.apache.bcel.classfile.JavaClass)
107: */
108: public void removeClass(JavaClass javaClass) {
109: nameToClassMap.remove(javaClass.getClassName());
110: if (DEBUG) {
111: System.out.println("Removing class "
112: + javaClass.getClassName() + " from Repository");
113: dumpStack();
114: }
115: }
116:
117: private void dumpStack() {
118: new Throwable().printStackTrace(System.out);
119: }
120:
121: /* (non-Javadoc)
122: * @see org.apache.bcel.util.Repository#findClass(java.lang.String)
123: */
124: public JavaClass findClass(@NonNull
125: String className) {
126: // Make sure we handle class names with slashes.
127: // If we don't, we can get into serious trouble: a previously
128: // loaded class will appear to be missing (because we're using the
129: // wrong name to look it up) and be evicted by some other random
130: // version of the class loaded from the classpath.
131: String dottedClassName = className.replace('/', '.');
132:
133: return nameToClassMap.get(dottedClassName);
134: }
135:
136: /* (non-Javadoc)
137: * @see org.apache.bcel.util.Repository#loadClass(java.lang.String)
138: */
139: public JavaClass loadClass(@NonNull
140: String className) throws ClassNotFoundException {
141: if (className == null)
142: throw new IllegalArgumentException("className is null");
143: //if (className.indexOf('/') >= 0) throw new IllegalStateException();
144: JavaClass javaClass = findClass(className);
145: if (javaClass == null) {
146: if (DEBUG) {
147: System.out.println("Looking up " + className
148: + " on classpath");
149: dumpStack();
150: }
151: javaClass = urlClassPath.lookupClass(className);
152: storeClass(javaClass);
153: }
154: return javaClass;
155: }
156:
157: /* (non-Javadoc)
158: * @see org.apache.bcel.util.Repository#loadClass(java.lang.Class)
159: */
160: public JavaClass loadClass(Class clazz)
161: throws ClassNotFoundException {
162: return loadClass(clazz.getName());
163: }
164:
165: /* (non-Javadoc)
166: * @see org.apache.bcel.util.Repository#clear()
167: */
168: public void clear() {
169: if (DEBUG) {
170: System.out.println("Clearing Repository!");
171: dumpStack();
172: }
173: nameToClassMap.clear();
174: }
175:
176: /* (non-Javadoc)
177: * @see org.apache.bcel.util.Repository#getClassPath()
178: */
179: public ClassPath getClassPath() {
180: return new ClassPath(urlClassPath.getClassPath());
181: }
182: }
183:
184: // vim:ts=4
|