forked from apache/netbeans
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request apache#4273 from nbauma109/patch-4243
Issue 4243: delete java/lang/Module and use dynamic proxy to implement Instrumentation across JDK versions…
- Loading branch information
Showing
2 changed files
with
47 additions
and
110 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,6 +26,8 @@ | |
import java.lang.instrument.UnmodifiableClassException; | ||
import java.lang.reflect.InvocationTargetException; | ||
import java.lang.reflect.Method; | ||
import java.lang.reflect.InvocationHandler; | ||
import java.lang.reflect.Proxy; | ||
import java.security.ProtectionDomain; | ||
import java.util.Collection; | ||
import java.util.List; | ||
|
@@ -41,14 +43,20 @@ | |
* | ||
* @author Jaroslav Tulach <[email protected]> | ||
*/ | ||
final class NbInstrumentation implements Instrumentation { | ||
final class NbInstrumentation implements InvocationHandler { | ||
private static final Logger LOG = Logger.getLogger(NbInstrumentation.class.getName()); | ||
private static final Object LOCK = new Object(); | ||
private static volatile Collection<NbInstrumentation> ACTIVE; | ||
|
||
private final List<ClassFileTransformer> transformers = new CopyOnWriteArrayList<ClassFileTransformer>(); | ||
private static final ThreadLocal<Boolean> IN = new ThreadLocal<Boolean>(); | ||
|
||
private final List<ClassFileTransformer> transformers = new CopyOnWriteArrayList<>(); | ||
private static final ThreadLocal<Boolean> IN = new ThreadLocal<>(); | ||
|
||
private final Instrumentation instrumentationProxy; | ||
|
||
public NbInstrumentation() { | ||
instrumentationProxy = (Instrumentation) Proxy.newProxyInstance(getClass().getClassLoader(), new Class<?>[] { Instrumentation.class }, this); | ||
} | ||
|
||
static NbInstrumentation registerAgent(ClassLoader l, String agentClassName) { | ||
try { | ||
return registerImpl(agentClassName, l); | ||
|
@@ -57,29 +65,31 @@ static NbInstrumentation registerAgent(ClassLoader l, String agentClassName) { | |
return null; | ||
} | ||
} | ||
|
||
static void unregisterAgent(NbInstrumentation instr) { | ||
synchronized (LOCK) { | ||
if (ACTIVE != null) { | ||
Collection<NbInstrumentation> clone = new WeakSet<NbInstrumentation>(ACTIVE); | ||
Collection<NbInstrumentation> clone = new WeakSet<>(ACTIVE); | ||
clone.remove(instr); | ||
ACTIVE = clone; | ||
} | ||
} | ||
} | ||
|
||
private static NbInstrumentation registerImpl(String agentClassName, ClassLoader l) throws ClassNotFoundException, IllegalArgumentException, NoSuchMethodException, SecurityException, IllegalAccessException, InvocationTargetException { | ||
final NbInstrumentation inst = new NbInstrumentation(); | ||
synchronized (LOCK) { | ||
if (ACTIVE == null) { | ||
ACTIVE = new WeakSet<NbInstrumentation>(); | ||
ACTIVE = new WeakSet<>(); | ||
} else { | ||
ACTIVE = new WeakSet<NbInstrumentation>(ACTIVE); | ||
ACTIVE = new WeakSet<>(ACTIVE); | ||
} | ||
ACTIVE.add(inst); | ||
} | ||
Class<?> agentClass = Class.forName(agentClassName, true, l); | ||
try { | ||
Method m = agentClass.getMethod("agentmain", String.class, Instrumentation.class); // NOI18N | ||
m.invoke(null, "", inst); | ||
m.invoke(null, "", inst.getInstrumentationProxy()); | ||
} catch (NoSuchMethodException ex) { | ||
Method m = agentClass.getMethod("agentmain", String.class); // NOI18N | ||
m.invoke(null, ""); | ||
|
@@ -112,86 +122,36 @@ public static byte[] patchByteCode(ClassLoader l, String className, ProtectionDo | |
// | ||
|
||
@Override | ||
public void addTransformer(ClassFileTransformer transformer, boolean canRetransform) { | ||
transformers.add(transformer); | ||
} | ||
|
||
@Override | ||
public void addTransformer(ClassFileTransformer transformer) { | ||
transformers.add(transformer); | ||
} | ||
|
||
@Override | ||
public boolean removeTransformer(ClassFileTransformer transformer) { | ||
return transformers.remove(transformer); | ||
} | ||
|
||
@Override | ||
public boolean isRetransformClassesSupported() { | ||
return false; | ||
} | ||
|
||
@Override | ||
public void retransformClasses(Class<?>... classes) throws UnmodifiableClassException { | ||
throw new UnmodifiableClassException(); | ||
} | ||
|
||
@Override | ||
public boolean isRedefineClassesSupported() { | ||
return false; | ||
} | ||
|
||
@Override | ||
public void redefineClasses(ClassDefinition... definitions) throws ClassNotFoundException, UnmodifiableClassException { | ||
throw new UnmodifiableClassException(); | ||
} | ||
|
||
@Override | ||
public boolean isModifiableClass(Class<?> theClass) { | ||
return false; | ||
} | ||
|
||
@SuppressWarnings("rawtypes") | ||
@Override | ||
public Class[] getAllLoadedClasses() { | ||
return new Class[0]; | ||
} | ||
|
||
@SuppressWarnings("rawtypes") | ||
@Override | ||
public Class[] getInitiatedClasses(ClassLoader loader) { | ||
return new Class[0]; | ||
} | ||
|
||
@Override | ||
public long getObjectSize(Object objectToSize) { | ||
return 42; | ||
} | ||
|
||
@Override | ||
public void appendToBootstrapClassLoaderSearch(JarFile jarfile) { | ||
} | ||
|
||
@Override | ||
public void appendToSystemClassLoaderSearch(JarFile jarfile) { | ||
throw new UnsupportedOperationException(); | ||
} | ||
|
||
@Override | ||
public boolean isNativeMethodPrefixSupported() { | ||
return false; | ||
} | ||
|
||
@Override | ||
public void setNativeMethodPrefix(ClassFileTransformer transformer, String prefix) { | ||
throw new UnsupportedOperationException(); | ||
} | ||
|
||
public void redefineModule(java.lang.Module module, Set<java.lang.Module> extraReads, Map<String, Set<java.lang.Module>> extraExports, Map<String, Set<java.lang.Module>> extraOpens, Set<Class<?>> extraUses, Map<Class<?>, List<Class<?>>> extraProvides) { | ||
throw new UnsupportedOperationException(); | ||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { | ||
switch (method.getName()) { | ||
case "addTransformer": | ||
return transformers.add((ClassFileTransformer) args[0]); | ||
case "removeTransformer": | ||
return transformers.remove(args[0]); | ||
case "isRetransformClassesSupported": | ||
case "isRedefineClassesSupported": | ||
case "isModifiableClass": | ||
case "isNativeMethodPrefixSupported": | ||
case "isModifiableModule": | ||
return false; | ||
case "retransformClasses": | ||
case "redefineClasses": | ||
throw new UnmodifiableClassException(); | ||
case "getAllLoadedClasses": | ||
case "getInitiatedClasses": | ||
return new Class[0]; | ||
case "getObjectSize": | ||
return 42; | ||
case "appendToSystemClassLoaderSearch": | ||
case "setNativeMethodPrefix": | ||
case "redefineModule": | ||
throw new UnsupportedOperationException(); | ||
default: | ||
return null; | ||
} | ||
} | ||
|
||
public boolean isModifiableModule(java.lang.Module module) { | ||
return false; | ||
public Instrumentation getInstrumentationProxy() { | ||
return instrumentationProxy; | ||
} | ||
} |