10 changed files with 395 additions and 0 deletions
@ -0,0 +1,6 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -0,0 +1,7 @@
|
||||
<html> |
||||
<body> |
||||
|
||||
Support for class instrumentation on Apache Tomcat. |
||||
|
||||
</html> |
||||
</body> |
||||
@ -0,0 +1,7 @@
@@ -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 @@
@@ -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 @@
@@ -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