001: /* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com
002:
003: This file is part of the db4o open source object database.
004:
005: db4o is free software; you can redistribute it and/or modify it under
006: the terms of version 2 of the GNU General Public License as published
007: by the Free Software Foundation and as clarified by db4objects' GPL
008: interpretation policy, available at
009: http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
010: Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
011: Suite 350, San Mateo, CA 94403, USA.
012:
013: db4o is distributed in the hope that it will be useful, but WITHOUT ANY
014: WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: for more details.
017:
018: You should have received a copy of the GNU General Public License along
019: with this program; if not, write to the Free Software Foundation, Inc.,
020: 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
021: package EDU.purdue.cs.bloat.context;
022:
023: import java.io.*;
024: import java.net.*;
025: import java.util.*;
026:
027: import EDU.purdue.cs.bloat.editor.*;
028: import EDU.purdue.cs.bloat.file.*;
029: import EDU.purdue.cs.bloat.reflect.*;
030: import EDU.purdue.cs.bloat.util.*;
031:
032: /**
033: * <code>BloatingClassLoader</code> is a Java class loader that BLOATs a class
034: * before it is loader into a Java Virtual Machine. It loads its classes from a
035: * set of {@link URL}s.
036: */
037: public abstract class BloatingClassLoader extends URLClassLoader {
038:
039: /**
040: * A ClassInfoLoader that loads classes from the same locations as this
041: * class loader.
042: */
043: ClassInfoLoader loader = new BloatingClassInfoLoader();
044:
045: /** The context that is used to edit classes, etc. */
046: private final EditorContext context = new PersistentBloatContext(
047: loader, false);
048:
049: /**
050: * Maps ClassInfos to their committed bytes (as a ByteArrayOutputStream)
051: */
052: private final Map classBytes = new HashMap();
053:
054: // //////////////////// Constructors /////////////////////////
055:
056: /**
057: * Creates a new <code>BloatingClassLoader</code> that loads its classes
058: * from a given set of URLs.
059: */
060: public BloatingClassLoader(final URL[] urls) {
061: super (urls);
062: }
063:
064: /**
065: * Creates a new <code>BloatingClassLoader</code> that loads its classes
066: * from a given set of URLs. Before attempting to load a class, this
067: * <code>BloatingClassLoader</code> will delegate to its parent class
068: * loader.
069: */
070: public BloatingClassLoader(final URL[] urls,
071: final ClassLoader parent) {
072: super (urls);
073: }
074:
075: /**
076: * Before the <code>Class</code> is created, invoke {@link
077: * #bloat(ClassEditor)}.
078: */
079: protected Class findClass(final String name)
080: throws ClassNotFoundException {
081:
082: final ClassInfo info = this .loader.loadClass(name);
083: final ClassEditor ce = this .context.editClass(info);
084:
085: this .bloat(ce);
086:
087: ce.commit();
088: final ByteArrayOutputStream baos = (ByteArrayOutputStream) this .classBytes
089: .get(info);
090: Assert.isNotNull(baos, "No bytes for " + name);
091:
092: final byte[] bytes = baos.toByteArray();
093: return super .defineClass(name, bytes, 0, bytes.length);
094: }
095:
096: /**
097: * Returns a <code>ClassInfoLoader</code> that loads classes from the same
098: * place as this <code>ClassLoader</code>.
099: */
100: public ClassInfoLoader getClassInfoLoader() {
101: return this .loader;
102: }
103:
104: protected EditorContext getEditorContext() {
105: return context;
106: }
107:
108: /**
109: * This method is invoked as a class is being loaded.
110: */
111: protected abstract void bloat(ClassEditor ce);
112:
113: /**
114: * This inner class is a ClassInfoLoader that loads classes from the same
115: * locations as the outer BloatClassLoader. The primary reason that we have
116: * this class is because the loadClass method of ClassInfoLoader has a
117: * different signature from ClassLoader. Hence, a ClassLoader cannot be a
118: * ClassInfoLoader.
119: */
120: class BloatingClassInfoLoader implements ClassInfoLoader {
121:
122: public ClassInfo loadClass(final String name)
123: throws ClassNotFoundException {
124:
125: final String classFileName = name.replace('.', '/')
126: + ".class";
127: final InputStream is = BloatingClassLoader.this
128: .getResourceAsStream(classFileName);
129: if (is == null) {
130: throw new ClassNotFoundException(
131: "Could not find class " + name);
132: }
133:
134: final DataInputStream dis = new DataInputStream(is);
135: return new ClassFile(null, this , dis);
136: }
137:
138: public ClassInfo newClass(final int modifiers,
139: final int classIndex, final int super ClassIndex,
140: final int[] interfaceIndexes,
141: final java.util.List constants) {
142:
143: return new ClassFile(modifiers, classIndex,
144: super ClassIndex, interfaceIndexes, constants, this );
145: }
146:
147: public OutputStream outputStreamFor(final ClassInfo info)
148: throws IOException {
149:
150: // Maintain a mapping between ClassInfos and their committed bytes
151: final OutputStream os = new ByteArrayOutputStream();
152: classBytes.put(info, os);
153: return (os);
154: }
155: }
156: }
|