001: /*
002: * Janino - An embedded Java[TM] compiler
003: *
004: * Copyright (c) 2001-2007, Arno Unkrig
005: * All rights reserved.
006: *
007: * Redistribution and use in source and binary forms, with or without
008: * modification, are permitted provided that the following conditions
009: * are met:
010: *
011: * 1. Redistributions of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: * 2. Redistributions in binary form must reproduce the above
014: * copyright notice, this list of conditions and the following
015: * disclaimer in the documentation and/or other materials
016: * provided with the distribution.
017: * 3. The name of the author may not be used to endorse or promote
018: * products derived from this software without specific prior
019: * written permission.
020: *
021: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
022: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
023: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
024: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
025: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
026: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
027: * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
028: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
029: * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
030: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
031: * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
032: */
033:
034: package org.codehaus.janino;
035:
036: import java.io.*;
037: import java.util.*;
038:
039: import org.codehaus.janino.tools.Disassembler;
040:
041: /**
042: * This {@link ClassLoader} allows for the loading of a set of Java<sup>TM</sup> classes
043: * provided in class file format.
044: */
045: public class ByteArrayClassLoader extends ClassLoader {
046: private static final boolean DEBUG = false;
047:
048: /**
049: * The given {@link Map} of classes must not be modified afterwards.
050: *
051: * @param classes String className => byte[] data
052: */
053: public ByteArrayClassLoader(Map classes) {
054: this .classes = classes;
055: }
056:
057: /**
058: * @see #ByteArrayClassLoader(Map)
059: */
060: public ByteArrayClassLoader(Map classes, ClassLoader parent) {
061: super (parent);
062: this .classes = classes;
063: }
064:
065: /**
066: * Implements {@link ClassLoader#findClass(String)}.
067: * <p>
068: * Notice that, although nowhere documented, no more than one thread at a time calls this
069: * method, because {@link ClassLoader#loadClass(java.lang.String)} is
070: * <code>synchronized</code>.
071: */
072: protected Class findClass(String name)
073: throws ClassNotFoundException {
074: byte[] data = (byte[]) this .classes.get(name);
075: if (data == null)
076: throw new ClassNotFoundException(name);
077:
078: if (DEBUG) {
079: System.out.println("*** Disassembly of class \"" + name
080: + "\":");
081: try {
082: new Disassembler()
083: .disasm(new ByteArrayInputStream(data));
084: System.out.flush();
085: } catch (IOException ex) {
086: throw new RuntimeException(
087: "SNO: IOException despite ByteArrayInputStream");
088: }
089: }
090:
091: return super .defineClass(name, // name
092: data, 0, data.length // b, off, len
093: );
094: }
095:
096: /**
097: * An object is regarded equal to <code>this</code> iff
098: * <ul>
099: * <li>It is also an instance of {@link ByteArrayClassLoader}
100: * <li>Both have the same parent {@link ClassLoader}
101: * <li>Exactly the same classes (name, bytecode) were added to both
102: * </ul>
103: * Roughly speaking, equal {@link ByteArrayClassLoader}s will return functionally identical
104: * {@link Class}es on {@link ClassLoader#loadClass(java.lang.String)}.
105: */
106: public boolean equals(Object o) {
107: if (!(o instanceof ByteArrayClassLoader))
108: return false;
109: if (this == o)
110: return true;
111: ByteArrayClassLoader that = (ByteArrayClassLoader) o;
112:
113: {
114: final ClassLoader parentOfThis = this .getParent();
115: final ClassLoader parentOfThat = that.getParent();
116: if (parentOfThis == null ? parentOfThat != null
117: : !parentOfThis.equals(parentOfThat))
118: return false;
119: }
120:
121: if (this .classes.size() != that.classes.size())
122: return false;
123: for (Iterator it = this .classes.entrySet().iterator(); it
124: .hasNext();) {
125: Map.Entry me = (Map.Entry) it.next();
126: byte[] ba = (byte[]) that.classes.get(me.getKey());
127: if (ba == null)
128: return false; // Key missing in "that".
129: if (!Arrays.equals((byte[]) me.getValue(), ba))
130: return false; // Byte arrays differ.
131: }
132: return true;
133: }
134:
135: public int hashCode() {
136: int hc = this .getParent().hashCode();
137:
138: for (Iterator it = this .classes.entrySet().iterator(); it
139: .hasNext();) {
140: Map.Entry me = (Map.Entry) it.next();
141: hc ^= me.getKey().hashCode();
142: byte[] ba = (byte[]) me.getValue();
143: for (int i = 0; i < ba.length; ++i) {
144: hc = (31 * hc) ^ ba[i];
145: }
146: }
147: return hc;
148: }
149:
150: private final Map classes; // String className => byte[] data
151: }
|