SPR-8533
+ add LTW support for JBoss 7 (renamed existing classes to MC (JBoss 5&6) and introduced Modules (JBoss 7))
This commit is contained in:
parent
d97a5bf889
commit
1d690ab99f
|
|
@ -1,144 +1,32 @@
|
|||
/*
|
||||
* Copyright 2006-2009 the original author or authors.
|
||||
*
|
||||
* Copyright 2011 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.jboss;
|
||||
|
||||
import java.lang.instrument.ClassFileTransformer;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Reflective wrapper around a JBoss 5 class loader methods (discovered and called
|
||||
* through reflection) for load time weaving.
|
||||
* Simple interface used for handling the different JBoss class loader adapters.
|
||||
*
|
||||
* @author Costin Leau
|
||||
*/
|
||||
class JBossClassLoaderAdapter {
|
||||
interface JBossClassLoaderAdapter {
|
||||
|
||||
private static final String TRANSLATOR_NAME = "org.jboss.util.loading.Translator";
|
||||
private static final String POLICY_NAME = "org.jboss.classloader.spi.base.BaseClassLoaderPolicy";
|
||||
private static final String DOMAIN_NAME = "org.jboss.classloader.spi.base.BaseClassLoaderDomain";
|
||||
private static final String DEDICATED_SYSTEM = "org.jboss.classloader.spi.ClassLoaderSystem";
|
||||
private static final String LOADER_NAME = "org.jboss.classloader.spi.base.BaseClassLoader";
|
||||
private static final String GET_POLICY = "getPolicy";
|
||||
private static final String GET_DOMAIN = "getClassLoaderDomain";
|
||||
private static final String GET_SYSTEM = "getClassLoaderSystem";
|
||||
void addTransformer(ClassFileTransformer transformer);
|
||||
|
||||
// available since JBoss AS 5.1.0 / MC 2.0.6 (allows multiple transformers to be added)
|
||||
private static final String ADD_TRANSLATOR_NAME = "addTranslator";
|
||||
// available since JBoss AS 5.0.0 / MC 2.0.1 (allows only one transformer to be added)
|
||||
private static final String SET_TRANSLATOR_NAME = "setTranslator";
|
||||
ClassLoader getInstrumentableClassLoader();
|
||||
|
||||
private final ClassLoader classLoader;
|
||||
private final Class<?> translatorClass;
|
||||
|
||||
private final Method addTranslator;
|
||||
private final Object target;
|
||||
|
||||
JBossClassLoaderAdapter(ClassLoader classLoader) {
|
||||
Class<?> clazzLoaderType = null;
|
||||
try {
|
||||
// resolve BaseClassLoader.class
|
||||
clazzLoaderType = classLoader.loadClass(LOADER_NAME);
|
||||
|
||||
ClassLoader clazzLoader = null;
|
||||
// walk the hierarchy to detect the instrumentation aware classloader
|
||||
for (ClassLoader cl = classLoader; cl != null && clazzLoader == null; cl = cl.getParent()) {
|
||||
if (clazzLoaderType.isInstance(cl)) {
|
||||
clazzLoader = cl;
|
||||
}
|
||||
}
|
||||
|
||||
if (clazzLoader == null) {
|
||||
throw new IllegalArgumentException(classLoader + " and its parents are not suitable ClassLoaders: "
|
||||
+ "A [" + LOADER_NAME + "] implementation is required.");
|
||||
}
|
||||
|
||||
this.classLoader = clazzLoader;
|
||||
// use the classloader that loaded the classloader to load
|
||||
// the types for reflection purposes
|
||||
classLoader = clazzLoader.getClass().getClassLoader();
|
||||
|
||||
// BaseClassLoader#getPolicy
|
||||
Method method = clazzLoaderType.getDeclaredMethod(GET_POLICY);
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
Object policy = method.invoke(this.classLoader);
|
||||
|
||||
Object addTarget = null;
|
||||
Method addMethod = null;
|
||||
|
||||
// try the 5.1.x hooks
|
||||
// check existence of BaseClassLoaderPolicy#addTranslator(Translator)
|
||||
this.translatorClass = classLoader.loadClass(TRANSLATOR_NAME);
|
||||
Class<?> clazz = classLoader.loadClass(POLICY_NAME);
|
||||
try {
|
||||
addMethod = clazz.getDeclaredMethod(ADD_TRANSLATOR_NAME, translatorClass);
|
||||
addTarget = policy;
|
||||
} catch (NoSuchMethodException ex) {
|
||||
}
|
||||
|
||||
// fall back to 5.0.x method
|
||||
if (addMethod == null) {
|
||||
|
||||
// BaseClassLoaderPolicy#getClassLoaderDomain
|
||||
method = clazz.getDeclaredMethod(GET_DOMAIN);
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
Object domain = method.invoke(policy);
|
||||
|
||||
// BaseClassLoaderDomain#getClassLoaderSystem
|
||||
clazz = classLoader.loadClass(DOMAIN_NAME);
|
||||
method = clazz.getDeclaredMethod(GET_SYSTEM);
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
Object system = method.invoke(domain);
|
||||
|
||||
// resolve ClassLoaderSystem
|
||||
clazz = classLoader.loadClass(DEDICATED_SYSTEM);
|
||||
Assert.isInstanceOf(clazz, system, "JBoss LoadTimeWeaver requires JBoss loader system of type "
|
||||
+ clazz.getName() + " on JBoss 5.0.x");
|
||||
|
||||
// ClassLoaderSystem#setTranslator
|
||||
addMethod = clazz.getDeclaredMethod(SET_TRANSLATOR_NAME, translatorClass);
|
||||
addTarget = system;
|
||||
}
|
||||
|
||||
this.addTranslator = addMethod;
|
||||
this.target = addTarget;
|
||||
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalStateException(
|
||||
"Could not initialize JBoss LoadTimeWeaver because the JBoss 5 API classes are not available", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void addTransformer(ClassFileTransformer transformer) {
|
||||
InvocationHandler adapter = new JBossTranslatorAdapter(transformer);
|
||||
Object adapterInstance = Proxy.newProxyInstance(this.translatorClass.getClassLoader(),
|
||||
new Class[] { this.translatorClass }, adapter);
|
||||
|
||||
try {
|
||||
addTranslator.invoke(target, adapterInstance);
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalStateException("Could not add transformer on JBoss classloader " + classLoader, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public ClassLoader getClassLoader() {
|
||||
return classLoader;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import org.springframework.util.ClassUtils;
|
|||
|
||||
/**
|
||||
* {@link LoadTimeWeaver} implementation for JBoss's instrumentable ClassLoader.
|
||||
* Currently supports JBoss 5, 6 and 7 (since Spring 3.1).
|
||||
*
|
||||
* <p><b>NOTE:</b> Requires JBoss AS version 5.0.0 or higher.
|
||||
* <p><b>NOTE:</b> On JBoss 6.0.0, to avoid the container loading the classes before
|
||||
|
|
@ -41,8 +42,7 @@ import org.springframework.util.ClassUtils;
|
|||
*/
|
||||
public class JBossLoadTimeWeaver implements LoadTimeWeaver {
|
||||
|
||||
private final JBossClassLoaderAdapter classLoader;
|
||||
|
||||
private final JBossClassLoaderAdapter adapter;
|
||||
|
||||
/**
|
||||
* Create a new instance of the {@link JBossLoadTimeWeaver} class using
|
||||
|
|
@ -61,16 +61,25 @@ public class JBossLoadTimeWeaver implements LoadTimeWeaver {
|
|||
*/
|
||||
public JBossLoadTimeWeaver(ClassLoader classLoader) {
|
||||
Assert.notNull(classLoader, "ClassLoader must not be null");
|
||||
this.classLoader = new JBossClassLoaderAdapter(classLoader);
|
||||
String loaderClassName = classLoader.getClass().getName();
|
||||
|
||||
if (loaderClassName.startsWith("org.jboss.classloader")) {
|
||||
// JBoss AS 5 or JBoss AS 6
|
||||
this.adapter = new JBossMCAdapter(classLoader);
|
||||
} else if (loaderClassName.startsWith("org.jboss.modules")) {
|
||||
// JBoss AS 7
|
||||
this.adapter = new JBossModulesAdapter(classLoader);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unexpected classloader type: " + loaderClassName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void addTransformer(ClassFileTransformer transformer) {
|
||||
this.classLoader.addTransformer(transformer);
|
||||
this.adapter.addTransformer(transformer);
|
||||
}
|
||||
|
||||
public ClassLoader getInstrumentableClassLoader() {
|
||||
return this.classLoader.getClassLoader();
|
||||
return this.adapter.getInstrumentableClassLoader();
|
||||
}
|
||||
|
||||
public ClassLoader getThrowawayClassLoader() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* Copyright 2006-2009 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.jboss;
|
||||
|
||||
import java.lang.instrument.ClassFileTransformer;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Reflective wrapper around a JBoss 5 and 6 class loader methods (discovered and called
|
||||
* through reflection) for load time weaving.
|
||||
*
|
||||
* @author Costin Leau
|
||||
*/
|
||||
class JBossMCAdapter implements JBossClassLoaderAdapter {
|
||||
|
||||
private static final String TRANSLATOR_NAME = "org.jboss.util.loading.Translator";
|
||||
private static final String POLICY_NAME = "org.jboss.classloader.spi.base.BaseClassLoaderPolicy";
|
||||
private static final String DOMAIN_NAME = "org.jboss.classloader.spi.base.BaseClassLoaderDomain";
|
||||
private static final String DEDICATED_SYSTEM = "org.jboss.classloader.spi.ClassLoaderSystem";
|
||||
private static final String LOADER_NAME = "org.jboss.classloader.spi.base.BaseClassLoader";
|
||||
private static final String GET_POLICY = "getPolicy";
|
||||
private static final String GET_DOMAIN = "getClassLoaderDomain";
|
||||
private static final String GET_SYSTEM = "getClassLoaderSystem";
|
||||
|
||||
// available since JBoss AS 5.1.0 / MC 2.0.6 (allows multiple transformers to be added)
|
||||
private static final String ADD_TRANSLATOR_NAME = "addTranslator";
|
||||
// available since JBoss AS 5.0.0 / MC 2.0.1 (allows only one transformer to be added)
|
||||
private static final String SET_TRANSLATOR_NAME = "setTranslator";
|
||||
|
||||
private final ClassLoader classLoader;
|
||||
private final Class<?> translatorClass;
|
||||
|
||||
private final Method addTranslator;
|
||||
private final Object target;
|
||||
|
||||
JBossMCAdapter(ClassLoader classLoader) {
|
||||
Class<?> clazzLoaderType = null;
|
||||
try {
|
||||
// resolve BaseClassLoader.class
|
||||
clazzLoaderType = classLoader.loadClass(LOADER_NAME);
|
||||
|
||||
ClassLoader clazzLoader = null;
|
||||
// walk the hierarchy to detect the instrumentation aware classloader
|
||||
for (ClassLoader cl = classLoader; cl != null && clazzLoader == null; cl = cl.getParent()) {
|
||||
if (clazzLoaderType.isInstance(cl)) {
|
||||
clazzLoader = cl;
|
||||
}
|
||||
}
|
||||
|
||||
if (clazzLoader == null) {
|
||||
throw new IllegalArgumentException(classLoader + " and its parents are not suitable ClassLoaders: "
|
||||
+ "A [" + LOADER_NAME + "] implementation is required.");
|
||||
}
|
||||
|
||||
this.classLoader = clazzLoader;
|
||||
// use the classloader that loaded the classloader to load
|
||||
// the types for reflection purposes
|
||||
classLoader = clazzLoader.getClass().getClassLoader();
|
||||
|
||||
// BaseClassLoader#getPolicy
|
||||
Method method = clazzLoaderType.getDeclaredMethod(GET_POLICY);
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
Object policy = method.invoke(this.classLoader);
|
||||
|
||||
Object addTarget = null;
|
||||
Method addMethod = null;
|
||||
|
||||
// try the 5.1.x hooks
|
||||
// check existence of BaseClassLoaderPolicy#addTranslator(Translator)
|
||||
this.translatorClass = classLoader.loadClass(TRANSLATOR_NAME);
|
||||
Class<?> clazz = classLoader.loadClass(POLICY_NAME);
|
||||
try {
|
||||
addMethod = clazz.getDeclaredMethod(ADD_TRANSLATOR_NAME, translatorClass);
|
||||
addTarget = policy;
|
||||
} catch (NoSuchMethodException ex) {
|
||||
}
|
||||
|
||||
// fall back to 5.0.x method
|
||||
if (addMethod == null) {
|
||||
|
||||
// BaseClassLoaderPolicy#getClassLoaderDomain
|
||||
method = clazz.getDeclaredMethod(GET_DOMAIN);
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
Object domain = method.invoke(policy);
|
||||
|
||||
// BaseClassLoaderDomain#getClassLoaderSystem
|
||||
clazz = classLoader.loadClass(DOMAIN_NAME);
|
||||
method = clazz.getDeclaredMethod(GET_SYSTEM);
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
Object system = method.invoke(domain);
|
||||
|
||||
// resolve ClassLoaderSystem
|
||||
clazz = classLoader.loadClass(DEDICATED_SYSTEM);
|
||||
Assert.isInstanceOf(clazz, system, "JBoss LoadTimeWeaver requires JBoss loader system of type "
|
||||
+ clazz.getName() + " on JBoss 5.0.x");
|
||||
|
||||
// ClassLoaderSystem#setTranslator
|
||||
addMethod = clazz.getDeclaredMethod(SET_TRANSLATOR_NAME, translatorClass);
|
||||
addTarget = system;
|
||||
}
|
||||
|
||||
this.addTranslator = addMethod;
|
||||
this.target = addTarget;
|
||||
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalStateException(
|
||||
"Could not initialize JBoss LoadTimeWeaver because the JBoss 5 API classes are not available", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void addTransformer(ClassFileTransformer transformer) {
|
||||
InvocationHandler adapter = new JBossMCTranslatorAdapter(transformer);
|
||||
Object adapterInstance = Proxy.newProxyInstance(this.translatorClass.getClassLoader(),
|
||||
new Class[] { this.translatorClass }, adapter);
|
||||
|
||||
try {
|
||||
addTranslator.invoke(target, adapterInstance);
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalStateException("Could not add transformer on JBoss 5/6 classloader " + classLoader, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public ClassLoader getInstrumentableClassLoader() {
|
||||
return classLoader;
|
||||
}
|
||||
}
|
||||
|
|
@ -29,16 +29,16 @@ import java.security.ProtectionDomain;
|
|||
*
|
||||
* @author Costin Leau
|
||||
*/
|
||||
class JBossTranslatorAdapter implements InvocationHandler {
|
||||
class JBossMCTranslatorAdapter implements InvocationHandler {
|
||||
|
||||
private final ClassFileTransformer transformer;
|
||||
|
||||
/**
|
||||
* Creates a new {@link JBossTranslatorAdapter}.
|
||||
* Creates a new {@link JBossMCTranslatorAdapter}.
|
||||
* @param transformer the {@link ClassFileTransformer} to be adapted (must
|
||||
* not be <code>null</code>)
|
||||
*/
|
||||
public JBossTranslatorAdapter(ClassFileTransformer transformer) {
|
||||
public JBossMCTranslatorAdapter(ClassFileTransformer transformer) {
|
||||
this.transformer = transformer;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright 2011 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.jboss;
|
||||
|
||||
import java.lang.instrument.ClassFileTransformer;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* JBoss 7 Adapter.
|
||||
*
|
||||
* @author Costin Leau
|
||||
*/
|
||||
class JBossModulesAdapter implements JBossClassLoaderAdapter {
|
||||
|
||||
private static final String TRANSFORMER_FIELD_NAME = "transformer";
|
||||
private static final String TRANSFORMER_ADD_METHOD_NAME = "addTransformer";
|
||||
private static final String DELEGATING_TRANSFORMER_CLASS_NAME = "org.jboss.as.server.deployment.module.DelegatingClassFileTransformer";
|
||||
private final ClassLoader classLoader;
|
||||
private final Method addTransformer;
|
||||
private final Object delegatingTransformer;
|
||||
|
||||
public JBossModulesAdapter(ClassLoader loader) {
|
||||
this.classLoader = loader;
|
||||
|
||||
try {
|
||||
Field transformers = ReflectionUtils.findField(classLoader.getClass(), TRANSFORMER_FIELD_NAME);
|
||||
transformers.setAccessible(true);
|
||||
|
||||
delegatingTransformer = transformers.get(classLoader);
|
||||
|
||||
Assert.state(delegatingTransformer.getClass().getName().equals(DELEGATING_TRANSFORMER_CLASS_NAME),
|
||||
"Transformer not of the expected type: " + delegatingTransformer.getClass().getName());
|
||||
addTransformer = ReflectionUtils.findMethod(delegatingTransformer.getClass(), TRANSFORMER_ADD_METHOD_NAME,
|
||||
ClassFileTransformer.class);
|
||||
addTransformer.setAccessible(true);
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalStateException("Could not initialize JBoss 7 LoadTimeWeaver", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void addTransformer(ClassFileTransformer transformer) {
|
||||
try {
|
||||
addTransformer.invoke(delegatingTransformer, transformer);
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalStateException("Could not add transformer on JBoss 7 classloader " + classLoader, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public ClassLoader getInstrumentableClassLoader() {
|
||||
return classLoader;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue