blob: 5c502ea644308018de9fad0a77d7eb8c889fd3c3 [file] [log] [blame]
package org.apache.bcel;
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2001 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" and
* "Apache BCEL" must not be used to endorse or promote products
* derived from this software without prior written permission. For
* written permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* "Apache BCEL", nor may "Apache" appear in their name, without
* prior written permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
import org.apache.bcel.classfile.*;
import org.apache.bcel.util.*;
import java.util.HashMap;
import java.io.*;
/**
* Repository maintains informations about class interdependencies, e.g.
* whether a class is a sub-class of another. JavaClass objects are put
* into a cache which can be purged with clearCache().
*
* All JavaClass objects used as arguments must have been obtained via
* the repository or been added with addClass() manually. This is
* because we have to check for object identity (==).
*
* @version $Id$
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A
*/
public abstract class Repository {
private static ClassPath class_path = new ClassPath();
private static HashMap classes;
private static JavaClass OBJECT; // should be final ...
static { clearCache(); }
/** @return class object for given fully qualified class name.
*/
public static JavaClass lookupClass(String class_name) {
if(class_name == null || class_name.equals(""))
throw new RuntimeException("Invalid class name");
class_name = class_name.replace('/', '.');
JavaClass clazz = (JavaClass)classes.get(class_name);
if(clazz == null) {
try {
InputStream is = class_path.getInputStream(class_name);
clazz = new ClassParser(is, class_name).parse();
class_name = clazz.getClassName();
} catch(IOException e) { return null; }
classes.put(class_name, clazz);
}
return clazz;
}
/** @return class file object for given Java class.
*/
public static ClassPath.ClassFile lookupClassFile(String class_name) {
try {
return class_path.getClassFile(class_name);
} catch(IOException e) { return null; }
}
/** Clear the repository.
*/
public static void clearCache() {
classes = new HashMap();
OBJECT = lookupClass("java.lang.Object");
if(OBJECT == null)
System.err.println("Warning: java.lang.Object not found on CLASSPATH!");
else
classes.put("java.lang.Object", OBJECT);
}
/**
* Add clazz to repository if there isn't an equally named class already in there.
*
* @return old entry in repository
*/
public static JavaClass addClass(JavaClass clazz) {
String name = clazz.getClassName();
JavaClass cl = (JavaClass)classes.get(name);
if(cl == null)
classes.put(name, cl = clazz);
return cl;
}
/**
* Remove class with given (fully qualifid) name from repository.
*/
public static void removeClass(String clazz) {
classes.remove(clazz);
}
/**
* Remove given class from repository.
*/
public static void removeClass(JavaClass clazz) {
removeClass(clazz.getClassName());
}
private static final JavaClass getSuperClass(JavaClass clazz) {
if(clazz == OBJECT)
return null;
return lookupClass(clazz.getSuperclassName());
}
/**
* @return list of super classes of clazz in ascending order, i.e.,
* Object is always the last element
*/
public static JavaClass[] getSuperClasses(JavaClass clazz) {
ClassVector vec = new ClassVector();
for(clazz = getSuperClass(clazz); clazz != null; clazz = getSuperClass(clazz))
vec.addElement(clazz);
return vec.toArray();
}
/**
* @return list of super classes of clazz in ascending order, i.e.,
* Object is always the last element. "null", if clazz cannot be found.
*/
public static JavaClass[] getSuperClasses(String class_name) {
JavaClass jc = lookupClass(class_name);
return (jc == null? null : getSuperClasses(jc));
}
/**
* @return all interfaces implemented by class and its super
* classes and the interfaces that those interfaces extend, and so on
*/
public static JavaClass[] getInterfaces(JavaClass clazz) {
ClassVector vec = new ClassVector();
ClassQueue queue = new ClassQueue();
queue.enqueue(clazz);
while(!queue.empty()) {
clazz = queue.dequeue();
String s = clazz.getSuperclassName();
String[] interfaces = clazz.getInterfaceNames();
if(clazz.isInterface())
vec.addElement(clazz);
else if(!s.equals("java.lang.Object"))
queue.enqueue(lookupClass(s));
for(int i=0; i < interfaces.length; i++)
queue.enqueue(lookupClass(interfaces[i]));
}
return vec.toArray();
}
/**
* @return all interfaces implemented by class and its super
* classes and the interfaces that extend those interfaces, and so on
*/
public static JavaClass[] getInterfaces(String class_name) {
return getInterfaces(lookupClass(class_name));
}
/**
* @return true, if clazz is an instance of super_class
*/
public static boolean instanceOf(JavaClass clazz, JavaClass super_class) {
if(clazz == super_class)
return true;
JavaClass[] super_classes = getSuperClasses(clazz);
for(int i=0; i < super_classes.length; i++)
if(super_classes[i] == super_class)
return true;
if(super_class.isInterface())
return implementationOf(clazz, super_class);
return false;
}
/**
* @return true, if clazz is an instance of super_class
*/
public static boolean instanceOf(String clazz, String super_class) {
return instanceOf(lookupClass(clazz), lookupClass(super_class));
}
/**
* @return true, if clazz is an instance of super_class
*/
public static boolean instanceOf(JavaClass clazz, String super_class) {
return instanceOf(clazz, lookupClass(super_class));
}
/**
* @return true, if clazz is an instance of super_class
*/
public static boolean instanceOf(String clazz, JavaClass super_class) {
return instanceOf(lookupClass(clazz), super_class);
}
/**
* @return true, if clazz is an implementation of interface inter
*/
public static boolean implementationOf(JavaClass clazz, JavaClass inter) {
if(clazz == inter)
return true;
JavaClass[] super_interfaces = getInterfaces(clazz);
for(int i=0; i < super_interfaces.length; i++)
if(super_interfaces[i] == inter)
return true;
return false;
}
/**
* @return true, if clazz is an implementation of interface inter
*/
public static boolean implementationOf(String clazz, String inter) {
return implementationOf(lookupClass(clazz), lookupClass(inter));
}
/**
* @return true, if clazz is an implementation of interface inter
*/
public static boolean implementationOf(JavaClass clazz, String inter) {
return implementationOf(clazz, lookupClass(inter));
}
/**
* @return true, if clazz is an implementation of interface inter
*/
public static boolean implementationOf(String clazz, JavaClass inter) {
return implementationOf(lookupClass(clazz), inter);
}
}