|
1 | 1 | /*
|
2 |
| - * Copyright 2002-2012 the original author or authors. |
| 2 | + * Copyright 2002-2013 the original author or authors. |
3 | 3 | *
|
4 | 4 | * Licensed under the Apache License, Version 2.0 (the "License");
|
5 | 5 | * you may not use this file except in compliance with the License.
|
|
17 | 17 | package org.springframework.instrument.classloading.glassfish;
|
18 | 18 |
|
19 | 19 | import java.lang.instrument.ClassFileTransformer;
|
| 20 | +import java.lang.reflect.InvocationTargetException; |
| 21 | +import java.lang.reflect.Method; |
20 | 22 |
|
21 | 23 | import org.springframework.instrument.classloading.LoadTimeWeaver;
|
22 | 24 | import org.springframework.util.Assert;
|
|
26 | 28 | * {@link LoadTimeWeaver} implementation for GlassFish's
|
27 | 29 | * {@link org.glassfish.api.deployment.InstrumentableClassLoader InstrumentableClassLoader}.
|
28 | 30 | *
|
29 |
| - * <p>As of Spring 3.0, GlassFish V3 is supported as well. |
| 31 | + * <p>As of Spring 4.0, this weaver supports GlassFish V3 and V4. |
30 | 32 | *
|
31 | 33 | * @author Costin Leau
|
32 | 34 | * @author Juergen Hoeller
|
33 | 35 | * @since 2.0.1
|
34 | 36 | */
|
35 | 37 | public class GlassFishLoadTimeWeaver implements LoadTimeWeaver {
|
36 | 38 |
|
37 |
| - private final GlassFishClassLoaderAdapter classLoader; |
| 39 | + private static final String INSTRUMENTABLE_LOADER_CLASS_NAME = "org.glassfish.api.deployment.InstrumentableClassLoader"; |
| 40 | + |
| 41 | + |
| 42 | + private final ClassLoader classLoader; |
| 43 | + |
| 44 | + private final Method addTransformerMethod; |
| 45 | + |
| 46 | + private final Method copyMethod; |
38 | 47 |
|
39 | 48 |
|
40 |
| - /** |
41 |
| - * Creates a new instance of the {@code GlassFishLoadTimeWeaver} class |
42 |
| - * using the default {@link ClassLoader}. |
43 |
| - * @see #GlassFishLoadTimeWeaver(ClassLoader) |
44 |
| - */ |
45 | 49 | public GlassFishLoadTimeWeaver() {
|
46 | 50 | this(ClassUtils.getDefaultClassLoader());
|
47 | 51 | }
|
48 | 52 |
|
49 |
| - /** |
50 |
| - * Creates a new instance of the {@code GlassFishLoadTimeWeaver} class. |
51 |
| - * @param classLoader the specific {@link ClassLoader} to use; must not be {@code null} |
52 |
| - * @throws IllegalArgumentException if the supplied {@code classLoader} is {@code null}; |
53 |
| - * or if the supplied {@code classLoader} is not an |
54 |
| - * {@link org.glassfish.api.deployment.InstrumentableClassLoader InstrumentableClassLoader} |
55 |
| - */ |
56 | 53 | public GlassFishLoadTimeWeaver(ClassLoader classLoader) {
|
57 | 54 | Assert.notNull(classLoader, "ClassLoader must not be null");
|
58 |
| - this.classLoader = new GlassFishClassLoaderAdapter(classLoader); |
| 55 | + |
| 56 | + Class<?> instrumentableLoaderClass; |
| 57 | + try { |
| 58 | + instrumentableLoaderClass = classLoader.loadClass(INSTRUMENTABLE_LOADER_CLASS_NAME); |
| 59 | + } |
| 60 | + catch (ClassNotFoundException ex) { |
| 61 | + throw new IllegalStateException( |
| 62 | + "Could not initialize GlassFishLoadTimeWeaver because GlassFish API classes are not available", ex); |
| 63 | + } |
| 64 | + try { |
| 65 | + this.addTransformerMethod = instrumentableLoaderClass.getMethod("addTransformer", ClassFileTransformer.class); |
| 66 | + this.copyMethod = instrumentableLoaderClass.getMethod("copy"); |
| 67 | + } |
| 68 | + catch (Exception ex) { |
| 69 | + throw new IllegalStateException( |
| 70 | + "Could not initialize GlassFishLoadTimeWeaver because GlassFish API classes are not available", ex); |
| 71 | + } |
| 72 | + |
| 73 | + ClassLoader clazzLoader = null; |
| 74 | + // Detect transformation-aware ClassLoader by traversing the hierarchy |
| 75 | + // (as in GlassFish, Spring can be loaded by the WebappClassLoader). |
| 76 | + for (ClassLoader cl = classLoader; cl != null && clazzLoader == null; cl = cl.getParent()) { |
| 77 | + if (instrumentableLoaderClass.isInstance(cl)) { |
| 78 | + clazzLoader = cl; |
| 79 | + } |
| 80 | + } |
| 81 | + |
| 82 | + if (clazzLoader == null) { |
| 83 | + throw new IllegalArgumentException(classLoader + " and its parents are not suitable ClassLoaders: A [" + |
| 84 | + instrumentableLoaderClass.getName() + "] implementation is required."); |
| 85 | + } |
| 86 | + |
| 87 | + this.classLoader = clazzLoader; |
59 | 88 | }
|
60 | 89 |
|
61 | 90 |
|
62 | 91 | @Override
|
63 | 92 | public void addTransformer(ClassFileTransformer transformer) {
|
64 |
| - this.classLoader.addTransformer(transformer); |
| 93 | + try { |
| 94 | + this.addTransformerMethod.invoke(this.classLoader, transformer); |
| 95 | + } |
| 96 | + catch (InvocationTargetException ex) { |
| 97 | + throw new IllegalStateException("GlassFish addTransformer method threw exception", ex.getCause()); |
| 98 | + } |
| 99 | + catch (Exception ex) { |
| 100 | + throw new IllegalStateException("Could not invoke GlassFish addTransformer method", ex); |
| 101 | + } |
65 | 102 | }
|
66 | 103 |
|
67 | 104 | @Override
|
68 | 105 | public ClassLoader getInstrumentableClassLoader() {
|
69 |
| - return this.classLoader.getClassLoader(); |
| 106 | + return this.classLoader; |
70 | 107 | }
|
71 | 108 |
|
72 | 109 | @Override
|
73 | 110 | public ClassLoader getThrowawayClassLoader() {
|
74 |
| - return this.classLoader.getThrowawayClassLoader(); |
| 111 | + try { |
| 112 | + return (ClassLoader) this.copyMethod.invoke(this.classLoader); |
| 113 | + } |
| 114 | + catch (InvocationTargetException ex) { |
| 115 | + throw new IllegalStateException("GlassFish copy method threw exception", ex.getCause()); |
| 116 | + } |
| 117 | + catch (Exception ex) { |
| 118 | + throw new IllegalStateException("Could not invoke GlassFish copy method", ex); |
| 119 | + } |
75 | 120 | }
|
76 | 121 |
|
77 | 122 | }
|
0 commit comments