10 changed files with 395 additions and 0 deletions
@ -0,0 +1,6 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<project name="org.springframework.instrument.classloading"> |
||||||
|
<property file="${basedir}/../build.properties"/> |
||||||
|
<import file="${basedir}/../build-spring-framework/package-bundle.xml"/> |
||||||
|
<import file="${basedir}/../spring-build/standard/default.xml"/> |
||||||
|
</project> |
||||||
@ -0,0 +1,25 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<?xml-stylesheet type="text/xsl" href="http://ivyrep.jayasoft.org/ivy-doc.xsl"?> |
||||||
|
<ivy-module |
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||||
|
xsi:noNamespaceSchemaLocation="http://incubator.apache.org/ivy/schemas/ivy.xsd" |
||||||
|
version="1.3"> |
||||||
|
|
||||||
|
<info organisation="org.springframework" module="${ant.project.name}"> |
||||||
|
<license name="Apache 2.0" url="http://www.apache.org/licenses/LICENSE-2.0"/> |
||||||
|
</info> |
||||||
|
|
||||||
|
<configurations> |
||||||
|
<include file="${spring.build.dir}/common/default-ivy-configurations.xml"/> |
||||||
|
</configurations> |
||||||
|
|
||||||
|
<publications> |
||||||
|
<artifact name="${ant.project.name}"/> |
||||||
|
<artifact name="${ant.project.name}-sources" type="src" ext="jar"/> |
||||||
|
</publications> |
||||||
|
|
||||||
|
<dependencies> |
||||||
|
<dependency org="org.apache.catalina" name="com.springsource.org.apache.catalina" rev="6.0.16" conf="provided->compile"/> |
||||||
|
</dependencies> |
||||||
|
|
||||||
|
</ivy-module> |
||||||
@ -0,0 +1,12 @@ |
|||||||
|
<?xml version="1.0"?> |
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> |
||||||
|
<modelVersion>4.0.0</modelVersion> |
||||||
|
<parent> |
||||||
|
<groupId>org.springframework</groupId> |
||||||
|
<artifactId>org.springframework.parent</artifactId> |
||||||
|
<version>3.0-M1-SNAPSHOT</version> |
||||||
|
</parent> |
||||||
|
<artifactId>org.springframework.agent</artifactId> |
||||||
|
<packaging>jar</packaging> |
||||||
|
<name>Spring Framework: Agent</name> |
||||||
|
</project> |
||||||
@ -0,0 +1,107 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2007 the original author or authors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.springframework.instrument.classloading; |
||||||
|
|
||||||
|
import java.lang.instrument.ClassFileTransformer; |
||||||
|
import java.lang.instrument.IllegalClassFormatException; |
||||||
|
import java.security.ProtectionDomain; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* ClassFileTransformer-based weaver, allowing for a list of transformers to be |
||||||
|
* applied on a class byte array. Normally used inside class loaders. |
||||||
|
* |
||||||
|
* <p>Note: This class is deliberately implemented for minimal external dependencies, |
||||||
|
* since it is included in weaver jars (to be deployed into application servers). |
||||||
|
* |
||||||
|
* @author Rod Johnson |
||||||
|
* @author Costin Leau |
||||||
|
* @author Juergen Hoeller |
||||||
|
* @since 2.0 |
||||||
|
*/ |
||||||
|
public class WeavingTransformer { |
||||||
|
|
||||||
|
private final ClassLoader classLoader; |
||||||
|
|
||||||
|
private final List<ClassFileTransformer> transformers = new ArrayList<ClassFileTransformer>(); |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Create a new WeavingTransformer for the given class loader. |
||||||
|
* @param classLoader the ClassLoader to build a transformer for |
||||||
|
*/ |
||||||
|
public WeavingTransformer(ClassLoader classLoader) { |
||||||
|
if (classLoader == null) { |
||||||
|
throw new IllegalArgumentException("ClassLoader must not be null"); |
||||||
|
} |
||||||
|
this.classLoader = classLoader; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Add a class file transformer to be applied by this weaver. |
||||||
|
* @param transformer the class file transformer to register |
||||||
|
*/ |
||||||
|
public void addTransformer(ClassFileTransformer transformer) { |
||||||
|
if (transformer == null) { |
||||||
|
throw new IllegalArgumentException("Transformer must not be null"); |
||||||
|
} |
||||||
|
this.transformers.add(transformer); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Apply transformation on a given class byte definition. |
||||||
|
* The method will always return a non-null byte array (if no transformation has taken place |
||||||
|
* the array content will be identical to the original one). |
||||||
|
* @param className the full qualified name of the class in dot format (i.e. some.package.SomeClass) |
||||||
|
* @param bytes class byte definition |
||||||
|
* @return (possibly transformed) class byte definition |
||||||
|
*/ |
||||||
|
public byte[] transformIfNecessary(String className, byte[] bytes) { |
||||||
|
String internalName = className.replace(".", "/"); |
||||||
|
return transformIfNecessary(className, internalName, bytes, null); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Apply transformation on a given class byte definition. |
||||||
|
* The method will always return a non-null byte array (if no transformation has taken place |
||||||
|
* the array content will be identical to the original one). |
||||||
|
* @param className the full qualified name of the class in dot format (i.e. some.package.SomeClass) |
||||||
|
* @param internalName class name internal name in / format (i.e. some/package/SomeClass) |
||||||
|
* @param bytes class byte definition |
||||||
|
* @param pd protection domain to be used (can be null) |
||||||
|
* @return (possibly transformed) class byte definition |
||||||
|
*/ |
||||||
|
public byte[] transformIfNecessary(String className, String internalName, byte[] bytes, ProtectionDomain pd) { |
||||||
|
byte[] result = bytes; |
||||||
|
for (ClassFileTransformer cft : this.transformers) { |
||||||
|
try { |
||||||
|
byte[] transformed = cft.transform(this.classLoader, internalName, null, pd, result); |
||||||
|
if (transformed != null) { |
||||||
|
result = transformed; |
||||||
|
} |
||||||
|
} |
||||||
|
catch (IllegalClassFormatException ex) { |
||||||
|
throw new IllegalStateException("Class file transformation failed", ex); |
||||||
|
} |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,196 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2007 the original author or authors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.springframework.instrument.classloading.tomcat; |
||||||
|
|
||||||
|
import java.lang.instrument.ClassFileTransformer; |
||||||
|
import java.lang.reflect.Field; |
||||||
|
import java.lang.reflect.Modifier; |
||||||
|
|
||||||
|
import org.apache.catalina.loader.ResourceEntry; |
||||||
|
import org.apache.catalina.loader.WebappClassLoader; |
||||||
|
|
||||||
|
import org.springframework.instrument.classloading.WeavingTransformer; |
||||||
|
|
||||||
|
/** |
||||||
|
* Extension of Tomcat's default class loader which adds instrumentation |
||||||
|
* to loaded classes without the need to use a VM-wide agent. |
||||||
|
* |
||||||
|
* <p>To be registered using a <code>Loader</code> tag in Tomcat's <code>Context</code> |
||||||
|
* definition in the <code>server.xml</code> file, with the Spring-provided |
||||||
|
* "spring-tomcat-weaver.jar" file deployed into Tomcat's "server/lib" directory. |
||||||
|
* The required configuration tag looks as follows: |
||||||
|
* |
||||||
|
* <pre class="code"><Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/></pre> |
||||||
|
* |
||||||
|
* <p>Typically used in combination with a |
||||||
|
* {@link org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver} |
||||||
|
* defined in the Spring application context. The <code>addTransformer</code> and |
||||||
|
* <code>getThrowawayClassLoader</code> methods mirror the corresponding methods |
||||||
|
* in the LoadTimeWeaver interface, as expected by ReflectiveLoadTimeWeaver. |
||||||
|
* |
||||||
|
* <p>See the PetClinic sample application for a full example of this |
||||||
|
* ClassLoader in action. |
||||||
|
* |
||||||
|
* <p><b>NOTE:</b> Requires Apache Tomcat version 5.0 or higher. |
||||||
|
* |
||||||
|
* @author Costin Leau |
||||||
|
* @author Juergen Hoeller |
||||||
|
* @since 2.0 |
||||||
|
* @see #addTransformer |
||||||
|
* @see #getThrowawayClassLoader |
||||||
|
* @see org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver |
||||||
|
*/ |
||||||
|
public class TomcatInstrumentableClassLoader extends WebappClassLoader { |
||||||
|
|
||||||
|
/** Use an internal WeavingTransformer */ |
||||||
|
private final WeavingTransformer weavingTransformer; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Create a new <code>TomcatInstrumentableClassLoader</code> using the |
||||||
|
* current context class loader. |
||||||
|
* @see #TomcatInstrumentableClassLoader(ClassLoader) |
||||||
|
*/ |
||||||
|
public TomcatInstrumentableClassLoader() { |
||||||
|
super(); |
||||||
|
this.weavingTransformer = new WeavingTransformer(this); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Create a new <code>TomcatInstrumentableClassLoader</code> with the |
||||||
|
* supplied class loader as parent. |
||||||
|
* @param parent the parent {@link ClassLoader} to be used |
||||||
|
*/ |
||||||
|
public TomcatInstrumentableClassLoader(ClassLoader parent) { |
||||||
|
super(parent); |
||||||
|
this.weavingTransformer = new WeavingTransformer(this); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Delegate for LoadTimeWeaver's <code>addTransformer</code> method. |
||||||
|
* Typically called through ReflectiveLoadTimeWeaver. |
||||||
|
* @see org.springframework.instrument.classloading.LoadTimeWeaver#addTransformer |
||||||
|
* @see org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver |
||||||
|
*/ |
||||||
|
public void addTransformer(ClassFileTransformer transformer) { |
||||||
|
this.weavingTransformer.addTransformer(transformer); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Delegate for LoadTimeWeaver's <code>getThrowawayClassLoader</code> method. |
||||||
|
* Typically called through ReflectiveLoadTimeWeaver. |
||||||
|
* @see org.springframework.instrument.classloading.LoadTimeWeaver#getThrowawayClassLoader |
||||||
|
* @see org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver |
||||||
|
*/ |
||||||
|
public ClassLoader getThrowawayClassLoader() { |
||||||
|
WebappClassLoader tempLoader = new WebappClassLoader(); |
||||||
|
// Use reflection to copy all the fields since most of them are private
|
||||||
|
// on pre-5.5 Tomcat.
|
||||||
|
shallowCopyFieldState(this, tempLoader); |
||||||
|
return tempLoader; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
protected ResourceEntry findResourceInternal(String name, String path) { |
||||||
|
ResourceEntry entry = super.findResourceInternal(name, path); |
||||||
|
// Postpone String parsing as much as possible (it is slow).
|
||||||
|
if (entry != null && entry.binaryContent != null && path.endsWith(".class")) { |
||||||
|
byte[] transformed = this.weavingTransformer.transformIfNecessary(name, entry.binaryContent); |
||||||
|
entry.binaryContent = transformed; |
||||||
|
} |
||||||
|
return entry; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String toString() { |
||||||
|
StringBuilder sb = new StringBuilder(getClass().getName()); |
||||||
|
sb.append("\r\n"); |
||||||
|
sb.append(super.toString()); |
||||||
|
return sb.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
// The code below is orginially taken from ReflectionUtils and optimized for
|
||||||
|
// local usage. There is no dependency on ReflectionUtils to keep this class
|
||||||
|
// self-contained (since it gets deployed into Tomcat's server class loader).
|
||||||
|
|
||||||
|
/** |
||||||
|
* Given the source object and the destination, which must be the same class
|
||||||
|
* or a subclass, copy all fields, including inherited fields. Designed to |
||||||
|
* work on objects with public no-arg constructors. |
||||||
|
* @throws IllegalArgumentException if arguments are incompatible or either |
||||||
|
* is <code>null</code> |
||||||
|
*/ |
||||||
|
private static void shallowCopyFieldState(final Object src, final Object dest) throws IllegalArgumentException { |
||||||
|
if (src == null) { |
||||||
|
throw new IllegalArgumentException("Source for field copy cannot be null"); |
||||||
|
} |
||||||
|
if (dest == null) { |
||||||
|
throw new IllegalArgumentException("Destination for field copy cannot be null"); |
||||||
|
} |
||||||
|
Class targetClass = findCommonAncestor(src.getClass(), dest.getClass()); |
||||||
|
|
||||||
|
// Keep backing up the inheritance hierarchy.
|
||||||
|
do { |
||||||
|
// Copy each field declared on this class unless it's static or
|
||||||
|
// file.
|
||||||
|
Field[] fields = targetClass.getDeclaredFields(); |
||||||
|
for (int i = 0; i < fields.length; i++) { |
||||||
|
Field field = fields[i]; |
||||||
|
// Skip static and final fields (the old FieldFilter)
|
||||||
|
// do not copy resourceEntries - it's a cache that holds class entries.
|
||||||
|
if (!(Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers()) || |
||||||
|
field.getName().equals("resourceEntries"))) { |
||||||
|
try { |
||||||
|
// copy the field (the old FieldCallback)
|
||||||
|
field.setAccessible(true); |
||||||
|
Object srcValue = field.get(src); |
||||||
|
field.set(dest, srcValue); |
||||||
|
} |
||||||
|
catch (IllegalAccessException ex) { |
||||||
|
throw new IllegalStateException( |
||||||
|
"Shouldn't be illegal to access field '" + fields[i].getName() + "': " + ex); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
targetClass = targetClass.getSuperclass(); |
||||||
|
} |
||||||
|
while (targetClass != null && targetClass != Object.class); |
||||||
|
} |
||||||
|
|
||||||
|
private static Class findCommonAncestor(Class one, Class two) throws IllegalArgumentException { |
||||||
|
Class ancestor = one; |
||||||
|
while (ancestor != Object.class || ancestor != null) { |
||||||
|
if (ancestor.isAssignableFrom(two)) { |
||||||
|
return ancestor; |
||||||
|
} |
||||||
|
ancestor = ancestor.getSuperclass(); |
||||||
|
} |
||||||
|
// try the other class hierarchy
|
||||||
|
ancestor = two; |
||||||
|
while (ancestor != Object.class || ancestor != null) { |
||||||
|
if (ancestor.isAssignableFrom(one)) { |
||||||
|
return ancestor; |
||||||
|
} |
||||||
|
ancestor = ancestor.getSuperclass(); |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,7 @@ |
|||||||
|
<html> |
||||||
|
<body> |
||||||
|
|
||||||
|
Support for class instrumentation on Apache Tomcat. |
||||||
|
|
||||||
|
</html> |
||||||
|
</body> |
||||||
@ -0,0 +1,7 @@ |
|||||||
|
<html> |
||||||
|
<body> |
||||||
|
<p> |
||||||
|
The Spring Data Binding framework, an internal library used by Spring Web Flow. |
||||||
|
</p> |
||||||
|
</body> |
||||||
|
</html> |
||||||
@ -0,0 +1,28 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> |
||||||
|
|
||||||
|
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> |
||||||
|
|
||||||
|
<!-- Appenders --> |
||||||
|
<appender name="console" class="org.apache.log4j.ConsoleAppender"> |
||||||
|
<param name="Target" value="System.out" /> |
||||||
|
<layout class="org.apache.log4j.PatternLayout"> |
||||||
|
<param name="ConversionPattern" value="%-5p: %c - %m%n" /> |
||||||
|
</layout> |
||||||
|
</appender> |
||||||
|
|
||||||
|
<logger name="org.springframework.beans"> |
||||||
|
<level value="warn" /> |
||||||
|
</logger> |
||||||
|
|
||||||
|
<logger name="org.springframework.binding"> |
||||||
|
<level value="debug" /> |
||||||
|
</logger> |
||||||
|
|
||||||
|
<!-- Root Logger --> |
||||||
|
<root> |
||||||
|
<priority value="warn" /> |
||||||
|
<appender-ref ref="console" /> |
||||||
|
</root> |
||||||
|
|
||||||
|
</log4j:configuration> |
||||||
@ -0,0 +1,6 @@ |
|||||||
|
Bundle-SymbolicName: org.springframework.instrument.classloading |
||||||
|
Bundle-Name: Spring Instrument Classloading |
||||||
|
Bundle-Vendor: SpringSource |
||||||
|
Bundle-ManifestVersion: 2 |
||||||
|
Import-Template: |
||||||
|
org.apache.catalina.*;version="[6.0.16, 7.0.0)" |
||||||
Loading…
Reference in new issue