Initial import of instrument.classloading module
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
|
||||
<path id="bundles">
|
||||
<pathelement location="../org.springframework.instrument"/>
|
||||
<pathelement location="../org.springframework.instrument.classloading"/>
|
||||
<pathelement location="../org.springframework.core"/>
|
||||
<pathelement location="../org.springframework.expression"/>
|
||||
<pathelement location="../org.springframework.beans"/>
|
||||
|
||||
6
org.springframework.instrument.classloading/build.xml
Normal file
6
org.springframework.instrument.classloading/build.xml
Normal file
@@ -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>
|
||||
25
org.springframework.instrument.classloading/ivy.xml
Normal file
25
org.springframework.instrument.classloading/ivy.xml
Normal file
@@ -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>
|
||||
12
org.springframework.instrument.classloading/pom.xml
Normal file
12
org.springframework.instrument.classloading/pom.xml
Normal file
@@ -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>
|
||||
6
org.springframework.instrument.classloading/template.mf
Normal file
6
org.springframework.instrument.classloading/template.mf
Normal file
@@ -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)"
|
||||
Reference in New Issue
Block a user