001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.object.loaders;
006:
007: import org.apache.commons.io.IOUtils;
008:
009: import com.tc.asm.ClassReader;
010: import com.tc.asm.ClassVisitor;
011: import com.tc.asm.ClassWriter;
012: import com.tc.object.ClientObjectManager;
013: import com.tc.object.bytecode.Manager;
014: import com.tc.object.bytecode.ManagerImpl;
015: import com.tc.object.bytecode.hook.impl.ClassProcessorHelper;
016: import com.tc.object.bytecode.hook.impl.DSOContextImpl;
017: import com.tc.object.bytecode.hook.impl.PreparedComponentsFromL2Connection;
018: import com.tc.object.config.DSOClientConfigHelper;
019: import com.tc.object.tx.ClientTransactionManager;
020:
021: import java.io.IOException;
022: import java.io.InputStream;
023: import java.lang.reflect.Constructor;
024: import java.net.URL;
025: import java.net.URLClassLoader;
026: import java.util.HashMap;
027: import java.util.Map;
028:
029: /**
030: * DSO Class loader for internal testing. The main purpose of this loader is to force test classes to be be defined
031: * specifically in this loader (and consequently within an isolated DSO context)
032: */
033: public class IsolationClassLoader extends URLClassLoader implements
034: NamedClassLoader {
035: private static final ClassLoader SYSTEM_LOADER = ClassLoader
036: .getSystemClassLoader();
037:
038: private final Manager manager;
039: private final DSOClientConfigHelper config;
040: private final Map onLoadErrors;
041: private final StandardClassProvider classProvider;
042: private final Map adapters = new HashMap();
043:
044: public IsolationClassLoader(DSOClientConfigHelper config,
045: PreparedComponentsFromL2Connection connectionComponents) {
046: this (config, true, null, null, connectionComponents);
047: }
048:
049: public IsolationClassLoader(DSOClientConfigHelper config,
050: ClientObjectManager objectManager,
051: ClientTransactionManager txManager) {
052: this (config, false, objectManager, txManager, null);
053: }
054:
055: private IsolationClassLoader(DSOClientConfigHelper config,
056: boolean startClient, ClientObjectManager objectManager,
057: ClientTransactionManager txManager,
058: PreparedComponentsFromL2Connection connectionComponents) {
059: super (getSystemURLS(), null);
060: this .config = config;
061: this .classProvider = new StandardClassProvider();
062: this .manager = createManager(startClient, objectManager,
063: txManager, config, connectionComponents);
064: this .onLoadErrors = new HashMap();
065: }
066:
067: public void init() {
068: manager.init();
069: ClassProcessorHelper.setContext(this , DSOContextImpl
070: .createContext(config, classProvider, manager));
071: }
072:
073: private static URL[] getSystemURLS() {
074: return ((URLClassLoader) SYSTEM_LOADER).getURLs();
075: }
076:
077: private Manager createManager(boolean startClient,
078: ClientObjectManager objectManager,
079: ClientTransactionManager txManager,
080: DSOClientConfigHelper theConfig,
081: PreparedComponentsFromL2Connection connectionComponents) {
082: classProvider.registerNamedLoader(this );
083: return new ManagerImpl(startClient, objectManager, txManager,
084: theConfig, classProvider, connectionComponents, false);
085: }
086:
087: public void stop() {
088: this .manager.stop();
089: }
090:
091: public Class loadClass(String name) throws ClassNotFoundException {
092: throwIfNeeded(name);
093:
094: Class c = findLoadedClass(name);
095: if (c != null) {
096: return c;
097: }
098:
099: if (name.startsWith("com.tc.")) {
100: return SYSTEM_LOADER.loadClass(name);
101: } else {
102: if (adapters.containsKey(name)) {
103: System.out.println("***** using adapter! name=["
104: + name + "]");
105: return adaptClass(name);
106: }
107:
108: return super .loadClass(name);
109: }
110: }
111:
112: private Class adaptClass(String name) throws ClassNotFoundException {
113: byte[] orig = getBytes(name);
114:
115: ClassReader cr = new ClassReader(orig);
116: ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS);
117:
118: Class adapterClass = (Class) adapters.get(name);
119:
120: try {
121: Constructor cstr = adapterClass
122: .getConstructor(new Class[] { ClassVisitor.class });
123: cstr.setAccessible(true);
124: ClassVisitor cv = (ClassVisitor) cstr
125: .newInstance(new Object[] { cw });
126: cr.accept(cv, ClassReader.SKIP_FRAMES);
127:
128: byte[] adapted = cw.toByteArray();
129:
130: return defineClass(name, adapted, 0, adapted.length);
131: } catch (Exception e) {
132: throw new ClassNotFoundException(name, e);
133: }
134: }
135:
136: private byte[] getBytes(String name) throws ClassNotFoundException {
137: InputStream is = super .getResourceAsStream(name.replace('.',
138: '/').concat(".class"));
139: if (is == null) {
140: throw new ClassNotFoundException(name);
141: }
142:
143: try {
144: return IOUtils.toByteArray(is);
145: } catch (IOException ioe) {
146: throw new ClassNotFoundException(name, ioe);
147: } finally {
148: IOUtils.closeQuietly(is);
149: }
150: }
151:
152: private void throwIfNeeded(String name)
153: throws ClassNotFoundException {
154: // throw exception if one is registered
155: final String t = (String) onLoadErrors.get(name);
156: if (t != null) {
157: ClassNotFoundException rv = new ClassNotFoundException(t);
158: throw rv;
159: }
160: }
161:
162: public String __tc_getClassLoaderName() {
163: return loaderName();
164: }
165:
166: public static String loaderName() {
167: return IsolationClassLoader.class.getName();
168: }
169:
170: public void __tc_setClassLoaderName(String name) {
171: throw new AssertionError();
172: }
173:
174: /**
175: * a ClassNotFoundException or NoClassDefFoundError with errorMessage will to be thrown referencing class className
176: */
177: public void throwOnLoad(String className, String errorMessage) {
178: onLoadErrors.put(className, errorMessage);
179: }
180:
181: protected Class findClass(String name)
182: throws ClassNotFoundException {
183: throwIfNeeded(name);
184: return super .findClass(name);
185: }
186:
187: public void addAdapter(String name, Class adapterClass) {
188: Object prev = adapters.put(name, adapterClass);
189: if (prev != null) {
190: throw new AssertionError("adapter already exists for "
191: + name);
192: }
193: }
194: }
|