001: package jsint;
002:
003: /**
004: Class importing.
005:
006: @author Ken R. Anderson, Copyright 2000, kanderso@bbn.com, <a href="license.txt">license</a>
007: subsequently modified by Jscheme project members
008: licensed under zlib licence (see license.txt)
009:
010: <p>Import provides support for Scheme's <tt>(import)</tt>
011: procedure. It is <i>roughly</i> like Java's import statement, with
012: important differences described below.
013:
014: <p><tt>(import)</tt> can be used to import a single class, such as:
015: <pre>
016: (import "java.util.Date")
017: </pre>
018:
019: Or all the classes of a package using the wildcard "*":
020:
021: <pre>
022: (import "java.util.*")
023: </pre>
024:
025: <p> <b>However</b>, using wildcard imports is not recommend
026: (deprecated) for the following reasons:
027:
028: <ul>
029:
030: <li>Class name lookup using wildcards requires generating class names
031: that do not exits. While this is fast for an application, it can
032: take about a second for each lookup in an applet.
033:
034: <li>Conflicts between imports are identified at (import) time,
035: rather than later in runtime.
036: </ul>
037:
038: **/
039: import java.util.Hashtable;
040: import java.util.Vector;
041: import java.util.Enumeration;
042:
043: public class Import {
044:
045: private static ClassLoader CLASSLOADER = Import.class
046: .getClassLoader();
047: static {
048: try {
049: Thread.currentThread().setContextClassLoader(
050: Import.class.getClassLoader());
051: } catch (Exception e) {
052: ;
053: }
054: }
055:
056: /** Get the ClassLoader used to look up classes. **/
057: public static synchronized ClassLoader getClassLoader() {
058: return CLASSLOADER;
059: }
060:
061: /** Set the ClassLoader used to look up classes. **/
062: public static synchronized void setClassLoader(ClassLoader cl) {
063: CLASSLOADER = cl;
064: Thread.currentThread().setContextClassLoader(cl);
065: }
066:
067: /**
068: Fields singles and wilds should be HashSets which won't exist
069: until JDK 1.2. So we simulate them with Vectors, which existed
070: since JDK 1.0.
071: **/
072: public static final Vector singles = new Vector(50);
073: public static final Vector wilds = new Vector(50);
074: public static final Hashtable table = new Hashtable(200);
075:
076: // KRA 17AUG01: Eventually add these as singles and wilds.
077: static {
078: addImport("java.lang.Object");
079: addImport("java.lang.*");
080: addImport("java.lang.reflect.*");
081: addImport("java.util.*");
082: addImport("jsint.*");
083: }
084:
085: /** Add an import, clearing the cache if it's wild. **/
086: public static synchronized void addImport(String name) {
087: // System.out.println("addImport: " + name);
088: if (name.endsWith("*")) {
089: addNew(wilds, new WildImporter(name));
090: table.clear();
091: } else
092: addNew(singles, new SingleImporter(name));
093: }
094:
095: /* Use Vector to simulate a HashSet. */
096: private static void addNew(Vector v, Object x) {
097: if (x != null && !v.contains(x))
098: v.addElement(x);
099: }
100:
101: /**
102: Find a Class named <tt>name</tt> either relative to imports, or
103: absolute, or error. Names of the form <tt>$name</tt> are
104: interpreted as absolute specifications for package-less classes
105: for historical reasons.
106: **/
107: public static Class classNamed(String name) {
108: Class c = maybeClassNamed(name);
109: return (c == null) ? (Class) E
110: .error("Can't find class " + name) : c;
111: }
112:
113: /** Returns a class or return null. **/
114: public static synchronized Class maybeClassNamed(String name) {
115: Class c = ((Class) table.get(name)); // Cached?
116: if (c != null)
117: return c;
118: c = classNamedLookup(name);
119: if (c != null)
120: table.put(name, c);
121: return c;
122: }
123:
124: private static Class classNamedLookup(String name) {
125: if (name.endsWith("[]"))
126: return classNamedArray(name.substring(0, name.length()
127: - "[]".length()));
128: Class c = classNamedImported(name);
129: if (c != null)
130: return c;
131: return primitiveClassNamed(name);
132: }
133:
134: /**
135: Search for class named <tt>name</tt> looking in singles.
136: Search packageless classes and wilds only if necessary.
137: **/
138: private static Class classNamedImported(String name) {
139: Vector classes = find(singles, name, new Vector(5));
140: if (name.lastIndexOf(".") == -1) { // No package prefix.
141: if (classes.size() == 0)
142: classes = classNamedNoPackage(name, classes);
143: if (classes.size() == 0)
144: classes = find(wilds, name, classes);
145: } else
146: addNew(classes, Import.forName(name));
147: return returnClass(name, classes);
148: }
149:
150: private static Class returnClass(String name, Vector classes) {
151: int L = classes.size();
152: if (L == 0)
153: return null;
154: if (L == 1)
155: return ((Class) classes.elementAt(0));
156: else
157: return ((Class) E.warn("Class " + name + " is ambiguous "
158: + classes + " choosing "
159: + ((Class) classes.elementAt(0))));
160: }
161:
162: private static Vector classNamedNoPackage(String name,
163: Vector classes) {
164: addNew(classes, Import.forName((name.startsWith("$")) ? name
165: .substring(1, name.length()) : name));
166: return classes;
167: }
168:
169: public static Vector find(Vector imports, String name,
170: Vector classes) {
171: Enumeration is = imports.elements();
172: while (is.hasMoreElements())
173: addNew(classes, ((Importer) is.nextElement())
174: .classNamed(name));
175: return classes;
176: }
177:
178: /** name is the name of the component class. **/
179: private static Class classNamedArray(String name) {
180: Class c = classNamed(name);
181: if (c.isPrimitive())
182: return classNamedArrayPrimitive(c);
183: if (c.isArray())
184: return Import.forName("[" + c.getName());
185: else
186: return Import.forName("[L" + c.getName() + ";");
187: }
188:
189: /** Ask the ClassLoader for a class given its full name. **/
190: public static Class forName(String name) {
191: ClassLoader loader = getClassLoader();
192: if (loader == null)
193: try {
194: return Class.forName(name);
195: } catch (ClassNotFoundException e) {
196: return null;
197: }
198: else
199: try {
200: return loader.loadClass(name);
201: } catch (ClassNotFoundException e) {
202: return null;
203: }
204: // KRA 28JUN00: Renu found this!
205: catch (NoClassDefFoundError e) {
206: return null;
207: }
208: }
209:
210: /** Class.forName() doesn't work for primitive types. **/
211: private static Class primitiveClassNamed(String name) {
212: return name.equals("void") ? Void.TYPE
213: : name.equals("boolean") ? Boolean.TYPE : name
214: .equals("byte") ? Byte.TYPE : name
215: .equals("char") ? Character.TYPE : name
216: .equals("short") ? Short.TYPE : name
217: .equals("int") ? Integer.TYPE : name
218: .equals("long") ? Long.TYPE : name
219: .equals("float") ? Float.TYPE : name
220: .equals("double") ? Double.TYPE : null;
221: }
222:
223: private static Class classNamedArrayPrimitive(Class c) {
224: return
225: // (c == void.class) ? void[].class :
226: (c == boolean.class) ? boolean[].class
227: : (c == byte.class) ? byte[].class
228: : (c == char.class) ? char[].class
229: : (c == short.class) ? short[].class
230: : (c == int.class) ? int[].class
231: : (c == long.class) ? long[].class
232: : (c == float.class) ? float[].class
233: : (c == double.class) ? double[].class
234: : null;
235: }
236:
237: private Import() {
238: } // Don't make one yourself.
239: }
|