Drop weaving support for pre-Servlet-3.1 servers
Issue: SPR-14467
This commit is contained in:
parent
36db6b2753
commit
54f01cffaf
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2002-2017 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -42,8 +42,8 @@ import org.springframework.instrument.classloading.websphere.WebSphereLoadTimeWe
|
||||||
* Spring's {@code <context:load-time-weaver>} XML tag.
|
* Spring's {@code <context:load-time-weaver>} XML tag.
|
||||||
*
|
*
|
||||||
* <p>This class implements a runtime environment check for obtaining the
|
* <p>This class implements a runtime environment check for obtaining the
|
||||||
* appropriate weaver implementation: As of Spring 4.0, it detects Oracle WebLogic 10,
|
* appropriate weaver implementation: As of Spring Framework 5.0, it detects
|
||||||
* GlassFish 3, Tomcat 6, 7 and 8, JBoss AS 5, 6 and 7, IBM WebSphere 7 and 8,
|
* Oracle WebLogic 10+, GlassFish 4+, Tomcat 8+, WildFly 8+, IBM WebSphere 8.5+,
|
||||||
* {@link InstrumentationSavingAgent Spring's VM agent}, and any {@link ClassLoader}
|
* {@link InstrumentationSavingAgent Spring's VM agent}, and any {@link ClassLoader}
|
||||||
* supported by Spring's {@link ReflectiveLoadTimeWeaver}.
|
* supported by Spring's {@link ReflectiveLoadTimeWeaver}.
|
||||||
*
|
*
|
||||||
|
@ -84,9 +84,11 @@ public class DefaultContextLoadTimeWeaver implements LoadTimeWeaver, BeanClassLo
|
||||||
else {
|
else {
|
||||||
try {
|
try {
|
||||||
this.loadTimeWeaver = new ReflectiveLoadTimeWeaver(classLoader);
|
this.loadTimeWeaver = new ReflectiveLoadTimeWeaver(classLoader);
|
||||||
|
if (logger.isInfoEnabled()) {
|
||||||
logger.info("Using a reflective load-time weaver for class loader: " +
|
logger.info("Using a reflective load-time weaver for class loader: " +
|
||||||
this.loadTimeWeaver.getInstrumentableClassLoader().getClass().getName());
|
this.loadTimeWeaver.getInstrumentableClassLoader().getClass().getName());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (IllegalStateException ex) {
|
catch (IllegalStateException ex) {
|
||||||
throw new IllegalStateException(ex.getMessage() + " Specify a custom LoadTimeWeaver or start your " +
|
throw new IllegalStateException(ex.getMessage() + " Specify a custom LoadTimeWeaver or start your " +
|
||||||
"Java virtual machine with Spring's agent: -javaagent:org.springframework.instrument.jar");
|
"Java virtual machine with Spring's agent: -javaagent:org.springframework.instrument.jar");
|
||||||
|
@ -123,16 +125,20 @@ public class DefaultContextLoadTimeWeaver implements LoadTimeWeaver, BeanClassLo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (IllegalStateException ex) {
|
catch (IllegalStateException ex) {
|
||||||
|
if (logger.isInfoEnabled()) {
|
||||||
logger.info("Could not obtain server-specific LoadTimeWeaver: " + ex.getMessage());
|
logger.info("Could not obtain server-specific LoadTimeWeaver: " + ex.getMessage());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
if (this.loadTimeWeaver instanceof InstrumentationLoadTimeWeaver) {
|
if (this.loadTimeWeaver instanceof InstrumentationLoadTimeWeaver) {
|
||||||
|
if (logger.isInfoEnabled()) {
|
||||||
logger.info("Removing all registered transformers for class loader: " +
|
logger.info("Removing all registered transformers for class loader: " +
|
||||||
this.loadTimeWeaver.getInstrumentableClassLoader().getClass().getName());
|
this.loadTimeWeaver.getInstrumentableClassLoader().getClass().getName());
|
||||||
|
}
|
||||||
((InstrumentationLoadTimeWeaver) this.loadTimeWeaver).removeTransformers();
|
((InstrumentationLoadTimeWeaver) this.loadTimeWeaver).removeTransformers();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2017 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -29,7 +29,7 @@ import org.springframework.util.ClassUtils;
|
||||||
* {@link LoadTimeWeaver} implementation for GlassFish's
|
* {@link LoadTimeWeaver} implementation for GlassFish's
|
||||||
* {@code org.glassfish.api.deployment.InstrumentableClassLoader InstrumentableClassLoader}.
|
* {@code org.glassfish.api.deployment.InstrumentableClassLoader InstrumentableClassLoader}.
|
||||||
*
|
*
|
||||||
* <p>As of Spring 4.0, this weaver supports GlassFish V3 and V4.
|
* <p>As of Spring Framework 5.0, this weaver supports GlassFish 4+.
|
||||||
*
|
*
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
|
@ -37,7 +37,8 @@ import org.springframework.util.ClassUtils;
|
||||||
*/
|
*/
|
||||||
public class GlassFishLoadTimeWeaver implements LoadTimeWeaver {
|
public class GlassFishLoadTimeWeaver implements LoadTimeWeaver {
|
||||||
|
|
||||||
private static final String INSTRUMENTABLE_LOADER_CLASS_NAME = "org.glassfish.api.deployment.InstrumentableClassLoader";
|
private static final String INSTRUMENTABLE_LOADER_CLASS_NAME =
|
||||||
|
"org.glassfish.api.deployment.InstrumentableClassLoader";
|
||||||
|
|
||||||
|
|
||||||
private final ClassLoader classLoader;
|
private final ClassLoader classLoader;
|
||||||
|
@ -57,16 +58,10 @@ public class GlassFishLoadTimeWeaver implements LoadTimeWeaver {
|
||||||
Class<?> instrumentableLoaderClass;
|
Class<?> instrumentableLoaderClass;
|
||||||
try {
|
try {
|
||||||
instrumentableLoaderClass = classLoader.loadClass(INSTRUMENTABLE_LOADER_CLASS_NAME);
|
instrumentableLoaderClass = classLoader.loadClass(INSTRUMENTABLE_LOADER_CLASS_NAME);
|
||||||
}
|
|
||||||
catch (ClassNotFoundException ex) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Could not initialize GlassFishLoadTimeWeaver because GlassFish API classes are not available", ex);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
this.addTransformerMethod = instrumentableLoaderClass.getMethod("addTransformer", ClassFileTransformer.class);
|
this.addTransformerMethod = instrumentableLoaderClass.getMethod("addTransformer", ClassFileTransformer.class);
|
||||||
this.copyMethod = instrumentableLoaderClass.getMethod("copy");
|
this.copyMethod = instrumentableLoaderClass.getMethod("copy");
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Throwable ex) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"Could not initialize GlassFishLoadTimeWeaver because GlassFish API classes are not available", ex);
|
"Could not initialize GlassFishLoadTimeWeaver because GlassFish API classes are not available", ex);
|
||||||
}
|
}
|
||||||
|
@ -97,7 +92,7 @@ public class GlassFishLoadTimeWeaver implements LoadTimeWeaver {
|
||||||
catch (InvocationTargetException ex) {
|
catch (InvocationTargetException ex) {
|
||||||
throw new IllegalStateException("GlassFish addTransformer method threw exception", ex.getCause());
|
throw new IllegalStateException("GlassFish addTransformer method threw exception", ex.getCause());
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Throwable ex) {
|
||||||
throw new IllegalStateException("Could not invoke GlassFish addTransformer method", ex);
|
throw new IllegalStateException("Could not invoke GlassFish addTransformer method", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,7 +110,7 @@ public class GlassFishLoadTimeWeaver implements LoadTimeWeaver {
|
||||||
catch (InvocationTargetException ex) {
|
catch (InvocationTargetException ex) {
|
||||||
throw new IllegalStateException("GlassFish copy method threw exception", ex.getCause());
|
throw new IllegalStateException("GlassFish copy method threw exception", ex.getCause());
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Throwable ex) {
|
||||||
throw new IllegalStateException("Could not invoke GlassFish copy method", ex);
|
throw new IllegalStateException("Could not invoke GlassFish copy method", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple interface used for handling the different JBoss class loader adapters.
|
|
||||||
*
|
|
||||||
* @author Costin Leau
|
|
||||||
* @since 3.1
|
|
||||||
*/
|
|
||||||
interface JBossClassLoaderAdapter {
|
|
||||||
|
|
||||||
void addTransformer(ClassFileTransformer transformer);
|
|
||||||
|
|
||||||
ClassLoader getInstrumentableClassLoader();
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2015 the original author or authors.
|
* Copyright 2002-2017 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -17,23 +17,20 @@
|
||||||
package org.springframework.instrument.classloading.jboss;
|
package org.springframework.instrument.classloading.jboss;
|
||||||
|
|
||||||
import java.lang.instrument.ClassFileTransformer;
|
import java.lang.instrument.ClassFileTransformer;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
import org.springframework.instrument.classloading.LoadTimeWeaver;
|
import org.springframework.instrument.classloading.LoadTimeWeaver;
|
||||||
import org.springframework.instrument.classloading.SimpleThrowawayClassLoader;
|
import org.springframework.instrument.classloading.SimpleThrowawayClassLoader;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link LoadTimeWeaver} implementation for JBoss's instrumentable ClassLoader.
|
* {@link LoadTimeWeaver} implementation for JBoss's instrumentable ClassLoader.
|
||||||
* Autodetects the specific JBoss version at runtime: currently supports
|
* Thanks to Ales Justin and Marius Bogoevici for the initial prototype.
|
||||||
* JBoss AS 6 and 7, as well as WildFly 8 and 9 (as of Spring 4.2).
|
|
||||||
*
|
*
|
||||||
* <p><b>NOTE:</b> On JBoss 6, to avoid the container loading the classes before the
|
* <p>As of Spring Framework 5.0, this weaver supports WildFly 8+.
|
||||||
* application actually starts, one needs to add a <tt>WEB-INF/jboss-scanning.xml</tt>
|
|
||||||
* file to the application archive - with the following content:
|
|
||||||
* <pre class="code"><scanning xmlns="urn:jboss:scanning:1.0"/></pre>
|
|
||||||
*
|
|
||||||
* <p>Thanks to Ales Justin and Marius Bogoevici for the initial prototype.
|
|
||||||
*
|
*
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
|
@ -41,7 +38,15 @@ import org.springframework.util.ClassUtils;
|
||||||
*/
|
*/
|
||||||
public class JBossLoadTimeWeaver implements LoadTimeWeaver {
|
public class JBossLoadTimeWeaver implements LoadTimeWeaver {
|
||||||
|
|
||||||
private final JBossClassLoaderAdapter adapter;
|
private static final String DELEGATING_TRANSFORMER_CLASS_NAME =
|
||||||
|
"org.jboss.as.server.deployment.module.DelegatingClassFileTransformer";
|
||||||
|
|
||||||
|
|
||||||
|
private final ClassLoader classLoader;
|
||||||
|
|
||||||
|
private final Object delegatingTransformer;
|
||||||
|
|
||||||
|
private final Method addTransformer;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -61,25 +66,48 @@ public class JBossLoadTimeWeaver implements LoadTimeWeaver {
|
||||||
*/
|
*/
|
||||||
public JBossLoadTimeWeaver(ClassLoader classLoader) {
|
public JBossLoadTimeWeaver(ClassLoader classLoader) {
|
||||||
Assert.notNull(classLoader, "ClassLoader must not be null");
|
Assert.notNull(classLoader, "ClassLoader must not be null");
|
||||||
if (classLoader.getClass().getName().startsWith("org.jboss.modules")) {
|
this.classLoader = classLoader;
|
||||||
// JBoss AS 7 or WildFly
|
try {
|
||||||
this.adapter = new JBossModulesAdapter(classLoader);
|
Field transformer = ReflectionUtils.findField(classLoader.getClass(), "transformer");
|
||||||
|
if (transformer == null) {
|
||||||
|
throw new IllegalArgumentException("Could not find 'transformer' field on JBoss ClassLoader: " +
|
||||||
|
classLoader.getClass().getName());
|
||||||
}
|
}
|
||||||
else {
|
transformer.setAccessible(true);
|
||||||
// JBoss AS 6
|
this.delegatingTransformer = transformer.get(classLoader);
|
||||||
this.adapter = new JBossMCAdapter(classLoader);
|
if (!this.delegatingTransformer.getClass().getName().equals(DELEGATING_TRANSFORMER_CLASS_NAME)) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Transformer not of the expected type DelegatingClassFileTransformer: " +
|
||||||
|
this.delegatingTransformer.getClass().getName());
|
||||||
|
}
|
||||||
|
this.addTransformer = ReflectionUtils.findMethod(this.delegatingTransformer.getClass(),
|
||||||
|
"addTransformer", ClassFileTransformer.class);
|
||||||
|
if (this.addTransformer == null) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Could not find 'addTransformer' method on JBoss DelegatingClassFileTransformer: " +
|
||||||
|
this.delegatingTransformer.getClass().getName());
|
||||||
|
}
|
||||||
|
this.addTransformer.setAccessible(true);
|
||||||
|
}
|
||||||
|
catch (Throwable ex) {
|
||||||
|
throw new IllegalStateException("Could not initialize JBoss LoadTimeWeaver", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addTransformer(ClassFileTransformer transformer) {
|
public void addTransformer(ClassFileTransformer transformer) {
|
||||||
this.adapter.addTransformer(transformer);
|
try {
|
||||||
|
this.addTransformer.invoke(this.delegatingTransformer, transformer);
|
||||||
|
}
|
||||||
|
catch (Throwable ex) {
|
||||||
|
throw new IllegalStateException("Could not add transformer on JBoss ClassLoader: " + this.classLoader, ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClassLoader getInstrumentableClassLoader() {
|
public ClassLoader getInstrumentableClassLoader() {
|
||||||
return this.adapter.getInstrumentableClassLoader();
|
return this.classLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,105 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2013 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.ReflectionUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reflective wrapper around a JBoss 6 class loader methods
|
|
||||||
* (discovered and called through reflection) for load-time weaving.
|
|
||||||
*
|
|
||||||
* @author Costin Leau
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 3.1
|
|
||||||
*/
|
|
||||||
class JBossMCAdapter implements JBossClassLoaderAdapter {
|
|
||||||
|
|
||||||
private static final String LOADER_NAME = "org.jboss.classloader.spi.base.BaseClassLoader";
|
|
||||||
|
|
||||||
private static final String TRANSLATOR_NAME = "org.jboss.util.loading.Translator";
|
|
||||||
|
|
||||||
|
|
||||||
private final ClassLoader classLoader;
|
|
||||||
|
|
||||||
private final Object target;
|
|
||||||
|
|
||||||
private final Class<?> translatorClass;
|
|
||||||
|
|
||||||
private final Method addTranslator;
|
|
||||||
|
|
||||||
|
|
||||||
public JBossMCAdapter(ClassLoader classLoader) {
|
|
||||||
try {
|
|
||||||
// Resolve BaseClassLoader.class
|
|
||||||
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("getPolicy");
|
|
||||||
ReflectionUtils.makeAccessible(method);
|
|
||||||
this.target = method.invoke(this.classLoader);
|
|
||||||
|
|
||||||
// Check existence of BaseClassLoaderPolicy#addTranslator(Translator)
|
|
||||||
this.translatorClass = classLoader.loadClass(TRANSLATOR_NAME);
|
|
||||||
this.addTranslator = this.target.getClass().getMethod("addTranslator", this.translatorClass);
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Could not initialize JBoss LoadTimeWeaver because the JBoss 6 API classes are not available", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addTransformer(ClassFileTransformer transformer) {
|
|
||||||
InvocationHandler adapter = new JBossMCTranslatorAdapter(transformer);
|
|
||||||
Object adapterInstance = Proxy.newProxyInstance(this.translatorClass.getClassLoader(),
|
|
||||||
new Class<?>[] {this.translatorClass}, adapter);
|
|
||||||
try {
|
|
||||||
this.addTranslator.invoke(this.target, adapterInstance);
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
throw new IllegalStateException("Could not add transformer on JBoss 6 ClassLoader " + this.classLoader, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ClassLoader getInstrumentableClassLoader() {
|
|
||||||
return this.classLoader;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,87 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2013 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.security.ProtectionDomain;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adapter that implements JBoss Translator interface, delegating to a
|
|
||||||
* standard JDK {@link ClassFileTransformer} underneath.
|
|
||||||
*
|
|
||||||
* <p>To avoid compile time checks again the vendor API, a dynamic proxy is
|
|
||||||
* being used.
|
|
||||||
*
|
|
||||||
* @author Costin Leau
|
|
||||||
* @since 3.1
|
|
||||||
*/
|
|
||||||
class JBossMCTranslatorAdapter implements InvocationHandler {
|
|
||||||
|
|
||||||
private final ClassFileTransformer transformer;
|
|
||||||
|
|
||||||
|
|
||||||
public JBossMCTranslatorAdapter(ClassFileTransformer transformer) {
|
|
||||||
this.transformer = transformer;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
|
||||||
String name = method.getName();
|
|
||||||
if ("equals".equals(name)) {
|
|
||||||
return proxy == args[0];
|
|
||||||
}
|
|
||||||
else if ("hashCode".equals(name)) {
|
|
||||||
return hashCode();
|
|
||||||
}
|
|
||||||
else if ("toString".equals(name)) {
|
|
||||||
return toString();
|
|
||||||
}
|
|
||||||
else if ("transform".equals(name)) {
|
|
||||||
return transform((ClassLoader) args[0], (String) args[1], (Class<?>) args[2],
|
|
||||||
(ProtectionDomain) args[3], (byte[]) args[4]);
|
|
||||||
}
|
|
||||||
else if ("unregisterClassLoader".equals(name)) {
|
|
||||||
unregisterClassLoader((ClassLoader) args[0]);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new IllegalArgumentException("Unknown method: " + method);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
|
|
||||||
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws Exception {
|
|
||||||
|
|
||||||
return this.transformer.transform(loader, className, classBeingRedefined, protectionDomain, classfileBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void unregisterClassLoader(ClassLoader loader) {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
StringBuilder builder = new StringBuilder(getClass().getName());
|
|
||||||
builder.append(" for transformer: ");
|
|
||||||
builder.append(this.transformer);
|
|
||||||
return builder.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,80 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2002-2013 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.ReflectionUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reflective wrapper around a JBoss 7 class loader methods
|
|
||||||
* (discovered and called through reflection) for load-time weaving.
|
|
||||||
*
|
|
||||||
* @author Costin Leau
|
|
||||||
* @author Juergen Hoeller
|
|
||||||
* @since 3.1
|
|
||||||
*/
|
|
||||||
class JBossModulesAdapter implements JBossClassLoaderAdapter {
|
|
||||||
|
|
||||||
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 transformer = ReflectionUtils.findField(loader.getClass(), "transformer");
|
|
||||||
transformer.setAccessible(true);
|
|
||||||
this.delegatingTransformer = transformer.get(loader);
|
|
||||||
if (!this.delegatingTransformer.getClass().getName().equals(DELEGATING_TRANSFORMER_CLASS_NAME)) {
|
|
||||||
throw new IllegalStateException("Transformer not of the expected type DelegatingClassFileTransformer: " +
|
|
||||||
this.delegatingTransformer.getClass().getName());
|
|
||||||
}
|
|
||||||
this.addTransformer = ReflectionUtils.findMethod(this.delegatingTransformer.getClass(),
|
|
||||||
"addTransformer", ClassFileTransformer.class);
|
|
||||||
this.addTransformer.setAccessible(true);
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
throw new IllegalStateException("Could not initialize JBoss 7 LoadTimeWeaver", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addTransformer(ClassFileTransformer transformer) {
|
|
||||||
try {
|
|
||||||
this.addTransformer.invoke(this.delegatingTransformer, transformer);
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
throw new IllegalStateException("Could not add transformer on JBoss 7 ClassLoader " + this.classLoader, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ClassLoader getInstrumentableClassLoader() {
|
|
||||||
return this.classLoader;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2017 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -76,7 +76,7 @@ public class TomcatLoadTimeWeaver implements LoadTimeWeaver {
|
||||||
}
|
}
|
||||||
this.copyMethod = copyMethod;
|
this.copyMethod = copyMethod;
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Throwable ex) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"Could not initialize TomcatLoadTimeWeaver because Tomcat API classes are not available", ex);
|
"Could not initialize TomcatLoadTimeWeaver because Tomcat API classes are not available", ex);
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,7 @@ public class TomcatLoadTimeWeaver implements LoadTimeWeaver {
|
||||||
catch (InvocationTargetException ex) {
|
catch (InvocationTargetException ex) {
|
||||||
throw new IllegalStateException("Tomcat addTransformer method threw exception", ex.getCause());
|
throw new IllegalStateException("Tomcat addTransformer method threw exception", ex.getCause());
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Throwable ex) {
|
||||||
throw new IllegalStateException("Could not invoke Tomcat addTransformer method", ex);
|
throw new IllegalStateException("Could not invoke Tomcat addTransformer method", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,7 +109,7 @@ public class TomcatLoadTimeWeaver implements LoadTimeWeaver {
|
||||||
catch (InvocationTargetException ex) {
|
catch (InvocationTargetException ex) {
|
||||||
throw new IllegalStateException("Tomcat copy method threw exception", ex.getCause());
|
throw new IllegalStateException("Tomcat copy method threw exception", ex.getCause());
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Throwable ex) {
|
||||||
throw new IllegalStateException("Could not invoke Tomcat copy method", ex);
|
throw new IllegalStateException("Could not invoke Tomcat copy method", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2017 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -28,7 +28,6 @@ import java.util.List;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* Reflective wrapper around a WebSphere 7+ class loader. Used to
|
* Reflective wrapper around a WebSphere 7+ class loader. Used to
|
||||||
* encapsulate the classloader-specific methods (discovered and
|
* encapsulate the classloader-specific methods (discovered and
|
||||||
* called through reflection) from the load-time weaver.
|
* called through reflection) from the load-time weaver.
|
||||||
|
@ -45,6 +44,7 @@ class WebSphereClassLoaderAdapter {
|
||||||
|
|
||||||
private static final String PLUGINS_FIELD = "preDefinePlugins";
|
private static final String PLUGINS_FIELD = "preDefinePlugins";
|
||||||
|
|
||||||
|
|
||||||
private ClassLoader classLoader;
|
private ClassLoader classLoader;
|
||||||
|
|
||||||
private Class<?> wsPreProcessorClass;
|
private Class<?> wsPreProcessorClass;
|
||||||
|
@ -68,13 +68,13 @@ class WebSphereClassLoaderAdapter {
|
||||||
this.transformerList = wsCompoundClassLoaderClass.getDeclaredField(PLUGINS_FIELD);
|
this.transformerList = wsCompoundClassLoaderClass.getDeclaredField(PLUGINS_FIELD);
|
||||||
this.transformerList.setAccessible(true);
|
this.transformerList.setAccessible(true);
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Throwable ex) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"Could not initialize WebSphere LoadTimeWeaver because WebSphere API classes are not available", ex);
|
"Could not initialize WebSphere LoadTimeWeaver because WebSphere API classes are not available", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!wsCompoundClassLoaderClass.isInstance(classLoader)) {
|
if (!wsCompoundClassLoaderClass.isInstance(classLoader)) {
|
||||||
throw new IllegalArgumentException("ClassLoader must be instance of [" + COMPOUND_CLASS_LOADER_NAME + "]");
|
throw new IllegalArgumentException("ClassLoader must be instance of " + COMPOUND_CLASS_LOADER_NAME);
|
||||||
}
|
}
|
||||||
this.classLoader = classLoader;
|
this.classLoader = classLoader;
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,7 @@ class WebSphereClassLoaderAdapter {
|
||||||
catch (InvocationTargetException ex) {
|
catch (InvocationTargetException ex) {
|
||||||
throw new IllegalStateException("WebSphere addPreDefinePlugin method threw exception", ex.getCause());
|
throw new IllegalStateException("WebSphere addPreDefinePlugin method threw exception", ex.getCause());
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Throwable ex) {
|
||||||
throw new IllegalStateException("Could not invoke WebSphere addPreDefinePlugin method", ex);
|
throw new IllegalStateException("Could not invoke WebSphere addPreDefinePlugin method", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ class WebSphereClassLoaderAdapter {
|
||||||
catch (InvocationTargetException ex) {
|
catch (InvocationTargetException ex) {
|
||||||
throw new IllegalStateException("WebSphere CompoundClassLoader constructor failed", ex.getCause());
|
throw new IllegalStateException("WebSphere CompoundClassLoader constructor failed", ex.getCause());
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Throwable ex) {
|
||||||
throw new IllegalStateException("Could not construct WebSphere CompoundClassLoader", ex);
|
throw new IllegalStateException("Could not construct WebSphere CompoundClassLoader", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2012 the original author or authors.
|
* Copyright 2002-2017 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -13,6 +13,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.instrument.classloading.websphere;
|
package org.springframework.instrument.classloading.websphere;
|
||||||
|
|
||||||
import java.lang.instrument.ClassFileTransformer;
|
import java.lang.instrument.ClassFileTransformer;
|
||||||
|
@ -46,7 +47,7 @@ class WebSphereClassPreDefinePlugin implements InvocationHandler {
|
||||||
this.transformer = transformer;
|
this.transformer = transformer;
|
||||||
ClassLoader classLoader = transformer.getClass().getClassLoader();
|
ClassLoader classLoader = transformer.getClass().getClassLoader();
|
||||||
|
|
||||||
// first force the full class loading of the weaver by invoking transformation on a dummy class
|
// First force the full class loading of the weaver by invoking transformation on a dummy class
|
||||||
try {
|
try {
|
||||||
String dummyClass = Dummy.class.getName().replace('.', '/');
|
String dummyClass = Dummy.class.getName().replace('.', '/');
|
||||||
byte[] bytes = FileCopyUtils.copyToByteArray(classLoader.getResourceAsStream(dummyClass + ".class"));
|
byte[] bytes = FileCopyUtils.copyToByteArray(classLoader.getResourceAsStream(dummyClass + ".class"));
|
||||||
|
@ -81,17 +82,14 @@ class WebSphereClassPreDefinePlugin implements InvocationHandler {
|
||||||
protected byte[] transform(String className, byte[] classfileBuffer, CodeSource codeSource, ClassLoader classLoader)
|
protected byte[] transform(String className, byte[] classfileBuffer, CodeSource codeSource, ClassLoader classLoader)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
|
||||||
// NB: WebSphere passes className as "." without class while the transformer expects a VM, "/" format
|
// NB: WebSphere passes className as "." without class while the transformer expects a VM "/" format
|
||||||
byte[] result = transformer.transform(classLoader, className.replace('.', '/'), null, null, classfileBuffer);
|
byte[] result = transformer.transform(classLoader, className.replace('.', '/'), null, null, classfileBuffer);
|
||||||
return (result != null ? result : classfileBuffer);
|
return (result != null ? result : classfileBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder builder = new StringBuilder(getClass().getName());
|
return getClass().getName() + " for transformer: " + this.transformer;
|
||||||
builder.append(" for transformer: ");
|
|
||||||
builder.append(this.transformer);
|
|
||||||
return builder.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue