001: /**
002: * InstantJ
003: *
004: * Copyright (C) 2002 Andy Thomas
005: * Additional changes (C) 2002 Nils Meier
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: */package instantj.compile;
018:
019: import java.io.Serializable;
020: import java.util.Collection;
021: import java.util.HashMap;
022: import java.util.Iterator;
023: import java.util.Map;
024:
025: /**
026: * (C) 2002 Andy Thomas
027: * This class represents a single compilation source files class instance.
028: * This includes the classes name and the bytes that form the class.
029: */
030: public class CompiledClass implements Serializable {
031:
032: /** the compiled bytecode */
033: private byte[] bytecode;
034:
035: /** the name of the class */
036: private String name;
037:
038: /** inner classes */
039: private Map inners = null;
040:
041: /** dependencies to other classes */
042: private Map dependencies = null;
043:
044: /** cached mapping classloader2type */
045: private transient Map cl2type = null;
046:
047: /**
048: * Constructor
049: */
050: public CompiledClass(String name, byte[] bytecode) {
051: this .bytecode = bytecode;
052: this .name = name;
053: }
054:
055: /**
056: * Returns the code.
057: * @return byte[]
058: */
059: public byte[] getByteCode() {
060: return bytecode;
061: }
062:
063: /**
064: * Returns the name.
065: * @return String
066: */
067: public String getName() {
068: return name;
069: }
070:
071: /**
072: * Returns a (new) java type for this compiled class. The classloader
073: * used wraps
074: * <il>
075: * <li>Thread.currentThread().getContextClassLoader() if not null
076: * <li>getClass().getClassLoader() otherwise
077: * </il>
078: * and will return the same type for that classloader on successive calls.
079: */
080: public Class getType() {
081:
082: // nothing cached yet?
083: if (cl2type == null) {
084: cl2type = new HashMap();
085: }
086:
087: // lookup ClassLoader
088: ClassLoader cl = Thread.currentThread().getContextClassLoader();
089: if (cl == null)
090: cl = getClass().getClassLoader();
091:
092: // known?
093: Class result = (Class) cl2type.get(cl);
094: if (result == null) {
095: result = new CL(cl).loadClass();
096: cl2type.put(cl, result);
097: }
098: // done
099: return result;
100: }
101:
102: /**
103: * Method addInnerClasses.
104: * @param inners
105: */
106: public void addInnerClasses(Collection add) {
107: // check argument
108: if (add == null || add.size() == 0)
109: return;
110: // check state
111: if (inners == null)
112: inners = new HashMap();
113: // loop through list
114: Iterator it = add.iterator();
115: while (it.hasNext()) {
116: CompiledClass cc = (CompiledClass) it.next();
117: inners.put(cc.getName(), cc);
118: }
119: // done
120: }
121:
122: /**
123: * Add dependencies (other CompiledClasses)
124: */
125: public void addDependencies(Collection add) {
126: // check argument
127: if (add == null || add.size() == 0)
128: return;
129: // check state
130: if (dependencies == null)
131: dependencies = new HashMap();
132: // loop through list
133: Iterator it = add.iterator();
134: while (it.hasNext()) {
135: CompiledClass cc = (CompiledClass) it.next();
136: dependencies.put(cc.getName(), cc);
137: }
138: // done
139: }
140:
141: /**
142: * Builds a map of compiled classes
143: */
144: /*package*/static Map map(Map map, Collection ccs) {
145:
146: // check for null
147: if (ccs == null)
148: return map;
149:
150: // loop over compiled classes
151: Iterator it = ccs.iterator();
152: while (it.hasNext()) {
153:
154: CompiledClass cc = (CompiledClass) it.next();
155:
156: // map next
157: map.put(cc.getName(), cc);
158:
159: // map it's inner classes
160: if (cc.inners != null)
161: map(map, cc.inners.values());
162:
163: // map it's dependencies
164: if (cc.dependencies != null)
165: map(map, cc.dependencies.values());
166:
167: }
168:
169: // done
170: return map;
171: }
172:
173: /**
174: * A classloader for the compiled class
175: */
176: private class CL extends ClassLoader {
177:
178: /** instantiated classes */
179: private Map classInstances = new HashMap();
180:
181: /**
182: * Constructor
183: */
184: private CL(ClassLoader parent) {
185: super (parent);
186: }
187:
188: /**
189: * @see java.lang.ClassLoader#findClass(java.lang.String)
190: */
191: protected Class findClass(String key)
192: throws ClassNotFoundException {
193: // loaded it already?
194: Class result = (Class) classInstances.get(key);
195: if (result != null)
196: return result;
197: // maybe it's an inner type?
198: if (inners != null) {
199: CompiledClass cc = (CompiledClass) inners.get(key);
200: // .. have to load with this classloader
201: if (cc != null)
202: return loadClass(cc);
203: }
204: // maybe it's a type we're depending on?
205: if (dependencies != null) {
206: CompiledClass cc = (CompiledClass) dependencies
207: .get(key);
208: // .. have to use it's classloader
209: if (cc != null)
210: return cc.getType();
211: }
212:
213: // delegate
214: return super .findClass(key);
215: }
216:
217: /**
218: * Loads the class from the contained byte-data
219: * @return the Class
220: */
221: private Class loadClass() throws ClassFormatError {
222: return loadClass(CompiledClass.this );
223: }
224:
225: /**
226: * Loads the class from given compiled class
227: */
228: private Class loadClass(CompiledClass cc)
229: throws ClassFormatError {
230:
231: // Construct class
232: Class result = defineClass(null, cc.bytecode, 0,
233: cc.bytecode.length);
234:
235: // Resolve it
236: try {
237: resolveClass(result);
238: } catch (IncompatibleClassChangeError err) {
239: // can't happen
240: }
241:
242: // remember
243: classInstances.put(cc.name, result);
244:
245: // Done
246: return result;
247: }
248:
249: } //CL
250:
251: } //CompiledClass
|