001: /*
002: * Janino - An embedded Java[TM] compiler
003: *
004: * Copyright (c) 2006, 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.util.*;
037:
038: /**
039: * This {@link ClassLoader} allows for the loading of a set of Java<sup>TM</sup> classes
040: * provided in class file format.
041: */
042: public class ByteArrayClassLoader extends ClassLoader {
043:
044: /**
045: * The given {@link Map} of classes must not be modified afterwards.
046: *
047: * @param classes String className => byte[] data
048: */
049: public ByteArrayClassLoader(Map classes) {
050: this .classes = classes;
051: }
052:
053: /**
054: * @see #ByteArrayClassLoader(Map)
055: */
056: public ByteArrayClassLoader(Map classes, ClassLoader parent) {
057: super (parent);
058: this .classes = classes;
059: }
060:
061: /**
062: * Implements {@link ClassLoader#findClass(String)}.
063: * <p>
064: * Notice that, although nowhere documented, no more than one thread at a time calls this
065: * method, because {@link ClassLoader#loadClass(java.lang.String)} is
066: * <code>synchronized</code>.
067: */
068: protected Class findClass(String name)
069: throws ClassNotFoundException {
070: byte[] data = (byte[]) this .classes.get(name);
071: if (data == null)
072: throw new ClassNotFoundException(name);
073:
074: return super .defineClass(name, // name
075: data, 0, data.length // b, off, len
076: );
077: }
078:
079: /**
080: * An object is regarded equal to <code>this</code> iff
081: * <ul>
082: * <li>It is also an instance of {@link ByteArrayClassLoader}
083: * <li>Both have the same parent {@link ClassLoader}
084: * <li>Exactly the same classes (name, bytecode) were added to both
085: * </ul>
086: * Roughly speaking, equal {@link ByteArrayClassLoader}s will return functionally identical
087: * {@link Class}es on {@link ClassLoader#loadClass(java.lang.String)}.
088: */
089: public boolean equals(Object o) {
090: if (!(o instanceof ByteArrayClassLoader))
091: return false;
092: if (this == o)
093: return true;
094: ByteArrayClassLoader that = (ByteArrayClassLoader) o;
095:
096: if (this .getParent() != that.getParent())
097: return false;
098:
099: if (this .classes.size() != that.classes.size())
100: return false;
101: for (Iterator it = this .classes.entrySet().iterator(); it
102: .hasNext();) {
103: Map.Entry me = (Map.Entry) it.next();
104: byte[] ba = (byte[]) that.classes.get(me.getKey());
105: if (ba == null)
106: return false; // Key missing in "that".
107: if (!Arrays.equals((byte[]) me.getValue(), ba))
108: return false; // Byte arrays differ.
109: }
110: return true;
111: }
112:
113: public int hashCode() {
114: int hc = this .getParent().hashCode();
115:
116: for (Iterator it = this .classes.entrySet().iterator(); it
117: .hasNext();) {
118: Map.Entry me = (Map.Entry) it.next();
119: hc ^= me.getKey().hashCode();
120: byte[] ba = (byte[]) me.getValue();
121: for (int i = 0; i < ba.length; ++i) {
122: hc = (31 * hc) ^ ba[i];
123: }
124: }
125: return hc;
126: }
127:
128: private final Map classes; // String className => byte[] data
129: }
|