KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > instrument > classloading > tomcat > TomcatInstrumentableClassLoader


1 /*
2  * Copyright 2002-2006 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.tomcat;
18
19 import java.lang.instrument.ClassFileTransformer JavaDoc;
20 import java.lang.reflect.Field JavaDoc;
21 import java.lang.reflect.Modifier JavaDoc;
22
23 import org.apache.catalina.loader.ResourceEntry;
24 import org.apache.catalina.loader.WebappClassLoader;
25
26 import org.springframework.instrument.classloading.WeavingTransformer;
27
28 /**
29  * Extension of Tomcat's default class loader which adds instrumentation
30  * to loaded classes without the need of using a VM-wide agent.
31  *
32  * <p>To be registered using a <code>Loader</code> tag in Tomcat's <code>Context</code>
33  * definition in the <code>server.xml</code> file, with the Spring-provided
34  * "spring-tomcat-weaver.jar" file deployed into Tomcat's "server/lib" directory.
35  * The required configuration tag looks as follows:
36  *
37  * <pre>
38  * &lt;Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/&gt;</pre>
39  *
40  * <p>Typically used in combination with a
41  * {@link org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver}
42  * defined in the Spring application context. The <code>addTransformer</code> and
43  * <code>getThrowawayClassLoader</code> methods mirror the corresponding methods
44  * in the LoadTimeWeaver interface, as expected by ReflectiveLoadTimeWeaver.
45  *
46  * <p>See the PetClinic sample application for a full example of this
47  * ClassLoader in action.
48  *
49  * <p><b>NOTE:</b> Requires Apache Tomcat version 5.0 or higher.
50  *
51  * @author Costin Leau
52  * @since 2.0
53  * @see #addTransformer
54  * @see #getThrowawayClassLoader
55  * @see org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver
56  */

57 public class TomcatInstrumentableClassLoader extends WebappClassLoader {
58
59     /** Use an internal WeavingTransformer */
60     private final WeavingTransformer weavingTransformer;
61
62
63     public TomcatInstrumentableClassLoader() {
64         super();
65         this.weavingTransformer = new WeavingTransformer();
66     }
67
68     public TomcatInstrumentableClassLoader(ClassLoader JavaDoc classLoader) {
69         super(classLoader);
70         this.weavingTransformer = new WeavingTransformer(classLoader);
71     }
72
73
74     /**
75      * Delegate for LoadTimeWeaver's <code>addTransformer</code> method.
76      * Typically called through ReflectiveLoadTimeWeaver.
77      * @see org.springframework.instrument.classloading.LoadTimeWeaver#addTransformer
78      * @see org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver
79      */

80     public void addTransformer(ClassFileTransformer JavaDoc transformer) {
81         this.weavingTransformer.addTransformer(transformer);
82     }
83
84     /**
85      * Delegate for LoadTimeWeaver's <code>getThrowawayClassLoader</code> method.
86      * Typically called through ReflectiveLoadTimeWeaver.
87      * @see org.springframework.instrument.classloading.LoadTimeWeaver#getThrowawayClassLoader
88      * @see org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver
89      */

90     public ClassLoader JavaDoc getThrowawayClassLoader() {
91         WebappClassLoader tempLoader = new WebappClassLoader();
92         // Use reflection to copy all the fields since most of them are private
93
// on pre-5.5 Tomcat.
94
shallowCopyFieldState(this, tempLoader);
95         return tempLoader;
96     }
97
98
99     @Override JavaDoc
100     protected ResourceEntry findResourceInternal(String JavaDoc name, String JavaDoc path) {
101         ResourceEntry entry = super.findResourceInternal(name, path);
102         // Postpone String parsing as much as possible (it is slow).
103
if (entry != null && entry.binaryContent != null && path.endsWith(".class")) {
104             byte[] transformed = this.weavingTransformer.transformIfNecessary(name, entry.binaryContent);
105             entry.binaryContent = transformed;
106         }
107         return entry;
108     }
109
110     @Override JavaDoc
111     public String JavaDoc toString() {
112         StringBuilder JavaDoc sb = new StringBuilder JavaDoc(getClass().getName());
113         sb.append("\r\n");
114         sb.append(super.toString());
115         return sb.toString();
116     }
117
118
119     // The code below is orginially taken from ReflectionUtils and optimized for
120
// local usage. There is no dependency on ReflectionUtils to keep this class
121
// self-contained (since it gets deployed into Tomcat's server class loader).
122

123     /**
124      * Given the source object and the destination, which must be the same class
125      * or a subclass, copy all fields, including inherited fields. Designed to
126      * work on objects with public no-arg constructors.
127      * @throws IllegalArgumentException if arguments are incompatible or either
128      * is <code>null</code>
129      */

130     private static void shallowCopyFieldState(final Object JavaDoc src, final Object JavaDoc dest) throws IllegalArgumentException JavaDoc {
131         if (src == null) {
132             throw new IllegalArgumentException JavaDoc("Source for field copy cannot be null");
133         }
134         if (dest == null) {
135             throw new IllegalArgumentException JavaDoc("Destination for field copy cannot be null");
136         }
137         Class JavaDoc targetClass = findCommonAncestor(src.getClass(), dest.getClass());
138
139         // Keep backing up the inheritance hierarchy.
140
do {
141             // Copy each field declared on this class unless it's static or
142
// file.
143
Field JavaDoc[] fields = targetClass.getDeclaredFields();
144             for (int i = 0; i < fields.length; i++) {
145                 Field JavaDoc field = fields[i];
146                 // Skip static and final fields (the old FieldFilter)
147
// do not copy resourceEntries - it's a cache that holds class entries.
148
if (!(Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers()) ||
149                         field.getName().equals("resourceEntries"))) {
150                     try {
151                         // copy the field (the old FieldCallback)
152
field.setAccessible(true);
153                         Object JavaDoc srcValue = field.get(src);
154                         field.set(dest, srcValue);
155                     }
156                     catch (IllegalAccessException JavaDoc ex) {
157                         throw new IllegalStateException JavaDoc(
158                                 "Shouldn't be illegal to access field '" + fields[i].getName() + "': " + ex);
159                     }
160                 }
161             }
162             targetClass = targetClass.getSuperclass();
163         }
164         while (targetClass != null && targetClass != Object JavaDoc.class);
165     }
166
167     private static Class JavaDoc findCommonAncestor(Class JavaDoc one, Class JavaDoc two) throws IllegalArgumentException JavaDoc {
168         Class JavaDoc ancestor = one;
169         while (ancestor != Object JavaDoc.class || ancestor != null) {
170             if (ancestor.isAssignableFrom(two)) {
171                 return ancestor;
172             }
173             ancestor = ancestor.getSuperclass();
174         }
175         // try the other class hierarchy
176
ancestor = two;
177         while (ancestor != Object JavaDoc.class || ancestor != null) {
178             if (ancestor.isAssignableFrom(one)) {
179                 return ancestor;
180             }
181             ancestor = ancestor.getSuperclass();
182         }
183         return null;
184     }
185
186 }
187
Popular Tags