Thomas Risberg
15 years ago
10 changed files with 484 additions and 0 deletions
@ -0,0 +1,50 @@
@@ -0,0 +1,50 @@
|
||||
/* |
||||
* Copyright 2002-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.security.ProtectionDomain; |
||||
import java.lang.instrument.ClassFileTransformer; |
||||
|
||||
import org.jboss.util.loading.Translator; |
||||
|
||||
/** |
||||
* ClassFileTransfomer to Translator bridge. |
||||
* |
||||
* @author Ales Justin |
||||
*/ |
||||
public class ClassFileTransformer2Translator implements Translator { |
||||
|
||||
private ClassFileTransformer transformer; |
||||
|
||||
public ClassFileTransformer2Translator(ClassFileTransformer transformer) { |
||||
if (transformer == null) { |
||||
throw new IllegalArgumentException("Null transformer"); |
||||
} |
||||
|
||||
this.transformer = transformer; |
||||
} |
||||
|
||||
public byte[] transform(ClassLoader loader, |
||||
String className, |
||||
Class<?> classBeingRedefined, |
||||
ProtectionDomain protectionDomain, |
||||
byte[] classfileBuffer) throws Exception { |
||||
return transformer.transform(loader, className, classBeingRedefined, protectionDomain, classfileBuffer); |
||||
} |
||||
|
||||
public void unregisterClassLoader(ClassLoader loader) { |
||||
} |
||||
} |
@ -0,0 +1,78 @@
@@ -0,0 +1,78 @@
|
||||
/* |
||||
* Copyright 2002-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.reflect.Method; |
||||
|
||||
import org.jboss.classloader.spi.ClassLoaderSystem; |
||||
import org.jboss.classloader.spi.base.BaseClassLoader; |
||||
import org.jboss.classloader.spi.base.BaseClassLoaderDomain; |
||||
import org.jboss.classloader.spi.base.BaseClassLoaderPolicy; |
||||
import org.jboss.classloader.spi.base.BaseClassLoaderSystem; |
||||
import org.jboss.util.loading.Translator; |
||||
|
||||
/** |
||||
* Reflective wrapper around a JBoss_5.0.x class loader. Used to encapsulate the classloader-specific methods |
||||
* (discovered and called through reflection) from the load-time weaver. |
||||
* |
||||
* @author Ales Justin |
||||
*/ |
||||
public class JBoss50ClassLoader extends JBoss5ClassLoader { |
||||
|
||||
private Method addTranslator; |
||||
|
||||
private ClassLoaderSystem system; |
||||
|
||||
public JBoss50ClassLoader(BaseClassLoader classLoader) { |
||||
super(classLoader); |
||||
} |
||||
|
||||
protected void fallbackStrategy() throws Exception { |
||||
try { |
||||
// let's check if we have a patched policy, with translator per policy
|
||||
addTranslator = getMethod(BaseClassLoaderPolicy.class, "addTranslator"); |
||||
} |
||||
catch (Exception ignored) { |
||||
//log.info("Policy doesn't have addTranslator, falling back to ClassLoaderSystem.");
|
||||
|
||||
Method getClassLoaderDomain = getMethod(BaseClassLoaderPolicy.class, "getClassLoaderDomain"); |
||||
BaseClassLoaderDomain domain = invokeMethod(getClassLoaderDomain, getPolicy(), BaseClassLoaderDomain.class); |
||||
Method getClassLoaderSystem = getMethod(BaseClassLoaderDomain.class, "getClassLoaderSystem"); |
||||
BaseClassLoaderSystem system = invokeMethod(getClassLoaderSystem, domain, BaseClassLoaderSystem.class); |
||||
if (system instanceof ClassLoaderSystem) { |
||||
this.system = ClassLoaderSystem.class.cast(system); |
||||
} |
||||
else { |
||||
throw new IllegalArgumentException( |
||||
"ClassLoaderSystem must be instance of [" + ClassLoaderSystem.class.getName() + "]"); |
||||
} |
||||
} |
||||
} |
||||
|
||||
protected void addTranslator(Translator translator) { |
||||
if (addTranslator != null) { |
||||
try { |
||||
addTranslator.invoke(translator); |
||||
} |
||||
catch (Exception e) { |
||||
throw new IllegalArgumentException(e); |
||||
} |
||||
} |
||||
else { |
||||
system.setTranslator(translator); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,37 @@
@@ -0,0 +1,37 @@
|
||||
/* |
||||
* Copyright 2002-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 org.jboss.classloader.spi.base.BaseClassLoader; |
||||
import org.jboss.util.loading.Translator; |
||||
|
||||
/** |
||||
* Reflective wrapper around a JBoss_5.1.x class loader. Used to encapsulate the classloader-specific methods |
||||
* (discovered and called through reflection) from the load-time weaver. |
||||
* |
||||
* @author <a href="mailto:ales.justin@jboss.org">Ales Justin</a> |
||||
*/ |
||||
public class JBoss51ClassLoader extends JBoss5ClassLoader { |
||||
|
||||
public JBoss51ClassLoader(BaseClassLoader classLoader) { |
||||
super(classLoader); |
||||
} |
||||
|
||||
protected void addTranslator(Translator translator) { |
||||
|
||||
getPolicy().addTranslator(translator); |
||||
} |
||||
} |
@ -0,0 +1,120 @@
@@ -0,0 +1,120 @@
|
||||
/* |
||||
* Copyright 2002-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.Method; |
||||
import java.security.AccessController; |
||||
import java.security.PrivilegedExceptionAction; |
||||
|
||||
import org.jboss.classloader.spi.ClassLoaderPolicy; |
||||
import org.jboss.classloader.spi.base.BaseClassLoader; |
||||
import org.jboss.util.loading.Translator; |
||||
|
||||
import org.springframework.util.Assert; |
||||
import org.springframework.instrument.classloading.SimpleThrowawayClassLoader; |
||||
|
||||
/** |
||||
* Reflective wrapper around a JBoss5 class loader. Used to encapsulate the classloader-specific methods (discovered and |
||||
* called through reflection) from the load-time weaver. |
||||
* |
||||
* @author Ales Justin |
||||
* @author Marius Bogoevici |
||||
*/ |
||||
public abstract class JBoss5ClassLoader extends ReflectionHelper { |
||||
|
||||
private final BaseClassLoader classLoader; |
||||
|
||||
private ClassLoaderPolicy policy; |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
protected JBoss5ClassLoader(BaseClassLoader classLoader) { |
||||
Assert.notNull(classLoader, "ClassLoader must not be null"); |
||||
this.classLoader = classLoader; |
||||
|
||||
try { |
||||
SecurityManager sm = System.getSecurityManager(); |
||||
if (sm != null) { |
||||
AccessController.doPrivileged(new InstantiationAction()); |
||||
} |
||||
else { |
||||
doInstantiate(); |
||||
} |
||||
} |
||||
catch (Exception e) { |
||||
throw new IllegalStateException( |
||||
"Could not initialize JBoss ClassLoader because JBoss5 API classes are not available", e); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Get the policy. |
||||
* |
||||
* @return the policy |
||||
*/ |
||||
protected ClassLoaderPolicy getPolicy() { |
||||
return policy; |
||||
} |
||||
|
||||
/** |
||||
* Do instantiate method, variables. |
||||
* |
||||
* @throws Exception for any error |
||||
*/ |
||||
private void doInstantiate() throws Exception { |
||||
Method getPolicy = getMethod(BaseClassLoader.class, "getPolicy"); |
||||
policy = invokeMethod(getPolicy, classLoader, ClassLoaderPolicy.class); |
||||
fallbackStrategy(); |
||||
} |
||||
|
||||
/** |
||||
* The fallback strategy. |
||||
* |
||||
* @throws Exception for any error |
||||
*/ |
||||
protected void fallbackStrategy() throws Exception { |
||||
} |
||||
|
||||
public void addTransformer(ClassFileTransformer transformer) { |
||||
Assert.notNull(transformer, "ClassFileTransformer must not be null"); |
||||
Translator translator = new ClassFileTransformer2Translator(transformer); |
||||
addTranslator(translator); |
||||
} |
||||
|
||||
/** |
||||
* Add the translator. |
||||
* |
||||
* @param translator the translator |
||||
*/ |
||||
protected abstract void addTranslator(Translator translator); |
||||
|
||||
public ClassLoader getInternalClassLoader() { |
||||
return classLoader; |
||||
} |
||||
|
||||
public ClassLoader getThrowawayClassLoader() { |
||||
return new SimpleThrowawayClassLoader(classLoader); |
||||
} |
||||
|
||||
/** Instantiation action. */ |
||||
private class InstantiationAction implements PrivilegedExceptionAction { |
||||
|
||||
public Object run() throws Exception { |
||||
doInstantiate(); |
||||
return null; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,120 @@
@@ -0,0 +1,120 @@
|
||||
/* |
||||
* Copyright 2002-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.Method; |
||||
|
||||
import org.jboss.classloader.spi.base.BaseClassLoader; |
||||
|
||||
import org.springframework.instrument.classloading.LoadTimeWeaver; |
||||
import org.springframework.util.Assert; |
||||
import org.springframework.util.ClassUtils; |
||||
|
||||
/** |
||||
* {@link LoadTimeWeaver} implementation for JBoss5's instrumentable ClassLoader. |
||||
* |
||||
* @author Ales Justin |
||||
*/ |
||||
public class JBoss5LoadTimeWeaver extends ReflectionHelper implements LoadTimeWeaver { |
||||
|
||||
private JBoss5ClassLoader classLoader; |
||||
|
||||
public JBoss5LoadTimeWeaver() { |
||||
this(ClassUtils.getDefaultClassLoader()); |
||||
} |
||||
|
||||
public JBoss5LoadTimeWeaver(ClassLoader classLoader) { |
||||
Assert.notNull(classLoader, "ClassLoader must not be null"); |
||||
BaseClassLoader bcl = determineClassLoader(classLoader); |
||||
if (bcl == null) { |
||||
throw new IllegalArgumentException( |
||||
classLoader + " and its parents are not suitable ClassLoaders: " + "An [" + |
||||
BaseClassLoader.class.getName() + "] implementation is required."); |
||||
} |
||||
this.classLoader = createClassLoaderWrapper(bcl); |
||||
} |
||||
|
||||
/** |
||||
* Create a JBoss5 classloader wrapper based on the underlying JBossAS version. |
||||
* |
||||
* @param bcl the base classloader |
||||
* @return new JBoss5 classloader wrapper |
||||
*/ |
||||
protected JBoss5ClassLoader createClassLoaderWrapper(BaseClassLoader bcl) { |
||||
int versionNumber = 0; |
||||
String tag; |
||||
|
||||
try { |
||||
// BCL should see Version class
|
||||
Class<?> versionClass = bcl.loadClass("org.jboss.Version"); |
||||
Method getInstance = getMethod(versionClass, "getInstance"); |
||||
Object version = getInstance.invoke(null); // static method
|
||||
|
||||
Method getMajor = getMethod(versionClass, "getMajor"); |
||||
versionNumber += 100 * invokeMethod(getMajor, version, Integer.class); |
||||
Method getMinor = getMethod(versionClass, "getMinor"); |
||||
versionNumber += 10 * invokeMethod(getMinor, version, Integer.class); |
||||
Method getRevision = getMethod(versionClass, "getRevision"); |
||||
versionNumber += invokeMethod(getRevision, version, Integer.class); |
||||
Method getTag = getMethod(versionClass, "getTag"); |
||||
tag = invokeMethod(getTag, version, String.class); |
||||
} |
||||
catch (Exception e) { |
||||
//log.warn("Exception creating JBoss5 CL wrapper: " + e + ", falling back to JBoss50ClassLoader wrapper.");
|
||||
return new JBoss50ClassLoader(bcl); |
||||
} |
||||
|
||||
if (versionNumber < 500) // this only works on new MC code
|
||||
{ |
||||
throw new IllegalArgumentException( |
||||
"JBoss5LoadTimeWeaver can only be used on new JBoss Microcontainer ClassLoader."); |
||||
} |
||||
else if (versionNumber <= 501 || (versionNumber == 510 && "Beta1".equals(tag))) { |
||||
return new JBoss50ClassLoader(bcl); |
||||
} |
||||
else { |
||||
return new JBoss51ClassLoader(bcl); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Find first BaseClassLoader implementation. |
||||
* |
||||
* @param classLoader the classloader |
||||
* @return BaseClassLoader instance or null if not found |
||||
*/ |
||||
private BaseClassLoader determineClassLoader(ClassLoader classLoader) { |
||||
for (ClassLoader cl = classLoader; cl != null; cl = cl.getParent()) { |
||||
if (cl instanceof BaseClassLoader) { |
||||
return (BaseClassLoader) cl; |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
public void addTransformer(ClassFileTransformer transformer) { |
||||
classLoader.addTransformer(transformer); |
||||
} |
||||
|
||||
public ClassLoader getInstrumentableClassLoader() { |
||||
return classLoader.getInternalClassLoader(); |
||||
} |
||||
|
||||
public ClassLoader getThrowawayClassLoader() { |
||||
return classLoader.getThrowawayClassLoader(); |
||||
} |
||||
} |
@ -0,0 +1,59 @@
@@ -0,0 +1,59 @@
|
||||
/* |
||||
* Copyright 2002-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.reflect.Method; |
||||
|
||||
/** |
||||
* Reflection helper. |
||||
* |
||||
* @author Ales Justin |
||||
*/ |
||||
public abstract class ReflectionHelper { |
||||
|
||||
/** |
||||
* Get method from class. |
||||
* |
||||
* @param clazz the owner class |
||||
* @param name the method name |
||||
* @return declared method |
||||
* @throws Exception for any error |
||||
*/ |
||||
protected static Method getMethod(Class<?> clazz, String name) throws Exception { |
||||
Method method = clazz.getDeclaredMethod(name); |
||||
method.setAccessible(true); |
||||
return method; |
||||
} |
||||
|
||||
/** |
||||
* Invoke method and check the result. |
||||
* |
||||
* @param method the method |
||||
* @param target the target |
||||
* @param expectedType the expected type |
||||
* @param <T> the exact type |
||||
* @return invocation's result |
||||
* @throws Exception for any error |
||||
*/ |
||||
protected static <T> T invokeMethod(Method method, Object target, Class<T> expectedType) throws Exception { |
||||
Object result = method.invoke(target); |
||||
if (expectedType.isInstance(result) == false) { |
||||
throw new IllegalArgumentException("Returned result must be instance of [" + expectedType.getName() + "]"); |
||||
} |
||||
|
||||
return expectedType.cast(result); |
||||
} |
||||
} |
Loading…
Reference in new issue