KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > instrument > classloading > ShadowingClassLoader


1 /*
2  * Copyright 2002-2007 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.instrument.classloading;
18
19 import java.io.IOException JavaDoc;
20 import java.io.InputStream JavaDoc;
21 import java.lang.instrument.ClassFileTransformer JavaDoc;
22 import java.lang.instrument.IllegalClassFormatException JavaDoc;
23 import java.net.URL JavaDoc;
24 import java.util.ArrayList JavaDoc;
25 import java.util.Enumeration JavaDoc;
26 import java.util.HashMap JavaDoc;
27 import java.util.LinkedList JavaDoc;
28 import java.util.List JavaDoc;
29 import java.util.Map JavaDoc;
30
31 import org.springframework.util.Assert;
32 import org.springframework.util.FileCopyUtils;
33 import org.springframework.util.StringUtils;
34
35 /**
36  * ClassLoader decorator that shadows an enclosing ClassLoader, applying
37  * registered transformers to all affected classes.
38  *
39  * @author Rob Harrop
40  * @author Rod Johnson
41  * @author Costin Leau
42  * @since 2.0
43  * @see #addTransformer
44  * @see #isClassNameExcludedFromShadowing(String)
45  * @see #getOptionalExcludedPackages()
46  */

47 public class ShadowingClassLoader extends ClassLoader JavaDoc {
48
49     /** Packages that are excluded by default */
50     public static final String JavaDoc[] DEFAULT_EXCLUDED_PACKAGES = new String JavaDoc[] {"java.", "javax.", "sun.", "com.sun.",
51             "org.w3c.", "org.xml.", "org.dom4j.", "org.aspectj.", "org.apache.xerces.", "org.apache.commons.logging."};
52
53
54     /** Optional excluded packages */
55     public final List JavaDoc<String JavaDoc> optionalExcludedPackages = new ArrayList JavaDoc<String JavaDoc>();
56
57     private final ClassLoader JavaDoc enclosingClassLoader;
58
59     private final List JavaDoc<ClassFileTransformer JavaDoc> classFileTransformers = new LinkedList JavaDoc<ClassFileTransformer JavaDoc>();
60
61     private final Map JavaDoc<String JavaDoc, Class JavaDoc> classCache = new HashMap JavaDoc<String JavaDoc, Class JavaDoc>();
62
63
64     /**
65      * Create a new ShadowingClassLoader, decorating the given ClassLoader.
66      * @param enclosingClassLoader the ClassLoader to decorate
67      */

68     public ShadowingClassLoader(ClassLoader JavaDoc enclosingClassLoader) {
69         Assert.notNull(enclosingClassLoader, "Enclosing ClassLoader must not be null");
70         this.enclosingClassLoader = enclosingClassLoader;
71     }
72
73     /**
74      * Add the given ClassFileTransformer to the list of transformers that this
75      * ClassLoader will apply.
76      * @param transformer the ClassFileTransformer
77      */

78     public void addTransformer(ClassFileTransformer JavaDoc transformer) {
79         Assert.notNull(transformer, "Transformer must not be null");
80         this.classFileTransformers.add(transformer);
81     }
82
83     /**
84      * Copy all ClassFileTransformers from the given ClassLoader to the list of
85      * transformers that this ClassLoader will apply.
86      * @param other the ClassLoader to copy from
87      */

88     public void copyTransformers(ShadowingClassLoader other) {
89         Assert.notNull(other, "Other ClassLoader must not be null");
90         this.classFileTransformers.addAll(other.classFileTransformers);
91     }
92
93
94     public Class JavaDoc<?> loadClass(String JavaDoc name) throws ClassNotFoundException JavaDoc {
95         if (shouldShadow(name)) {
96             Class JavaDoc cls = this.classCache.get(name);
97             if (cls != null) {
98                 return cls;
99             }
100             return doLoadClass(name);
101         }
102         else {
103             return this.enclosingClassLoader.loadClass(name);
104         }
105     }
106
107     /**
108      * Determine whether the given class should be excluded from shadowing.
109      * @param className the name of the class
110      */

111     private boolean shouldShadow(String JavaDoc className) {
112         return (!className.equals(getClass().getName()) && !className.endsWith("ShadowingClassLoader")
113                 && !isExcludedPackage(className) && !isClassNameExcludedFromShadowing(className));
114     }
115
116     /**
117      * Determine whether the given class is defined in an excluded package.
118      * @param className the name of the class
119      */

120     private boolean isExcludedPackage(String JavaDoc className) {
121         for (int i = 0; i < DEFAULT_EXCLUDED_PACKAGES.length; i++) {
122             if (className.startsWith(DEFAULT_EXCLUDED_PACKAGES[i])) {
123                 return true;
124             }
125         }
126         // optional exclude packages
127
for (String JavaDoc pkg : this.optionalExcludedPackages) {
128             if (className.startsWith(pkg)) {
129                 return true;
130             }
131         }
132         return false;
133     }
134
135     /**
136      * Subclasses can override this method to specify whether or not a
137      * particular class should be excluded from shadowing.
138      * @param className the class name to test
139      */

140     protected boolean isClassNameExcludedFromShadowing(String JavaDoc className) {
141         return false;
142     }
143
144     private Class JavaDoc doLoadClass(String JavaDoc name) throws ClassNotFoundException JavaDoc {
145         String JavaDoc internalName = StringUtils.replace(name, ".", "/") + ".class";
146         InputStream JavaDoc is = this.enclosingClassLoader.getResourceAsStream(internalName);
147         if (is == null) {
148             throw new ClassNotFoundException JavaDoc(name);
149         }
150         try {
151             byte[] bytes = FileCopyUtils.copyToByteArray(is);
152             bytes = applyTransformers(name, bytes);
153             Class JavaDoc cls = defineClass(name, bytes, 0, bytes.length);
154             this.classCache.put(name, cls);
155             return cls;
156         }
157         catch (IOException JavaDoc ex) {
158             throw new ClassNotFoundException JavaDoc("Cannot load resource for class [" + name + "]", ex);
159         }
160     }
161
162     private byte[] applyTransformers(String JavaDoc name, byte[] bytes) {
163         String JavaDoc internalName = StringUtils.replace(name, ".", "/");
164         try {
165             for (ClassFileTransformer JavaDoc transformer : this.classFileTransformers) {
166                 byte[] transformed = transformer.transform(this, internalName, null, null, bytes);
167                 bytes = (transformed != null ? transformed : bytes);
168             }
169             return bytes;
170         }
171         catch (IllegalClassFormatException JavaDoc ex) {
172             throw new IllegalStateException JavaDoc(ex);
173         }
174     }
175
176     public URL JavaDoc getResource(String JavaDoc name) {
177         return this.enclosingClassLoader.getResource(name);
178     }
179
180     public InputStream JavaDoc getResourceAsStream(String JavaDoc name) {
181         return this.enclosingClassLoader.getResourceAsStream(name);
182     }
183
184     public Enumeration JavaDoc<URL JavaDoc> getResources(String JavaDoc name) throws IOException JavaDoc {
185         return this.enclosingClassLoader.getResources(name);
186     }
187
188     /**
189      * Get the list of optional package names that can be excluded from shadowing.
190      */

191     public List JavaDoc<String JavaDoc> getOptionalExcludedPackages() {
192         return this.optionalExcludedPackages;
193     }
194
195 }
196
Popular Tags