Skip to content

Commit

Permalink
#1298 - Dynamic instrumentation with javaagent is broken
Browse files Browse the repository at this point in the history
  • Loading branch information
andrey-yanchevsky-provi committed Oct 31, 2023
1 parent 79dc6cf commit 4b50620
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,16 @@
package org.javalite.instrumentation;

import javassist.CtClass;
import javassist.NotFoundException;

import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.ProtectionDomain;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import static java.util.Arrays.asList;
import java.util.*;

/**
* @author igor, on 5/12/14.
Expand All @@ -40,7 +36,12 @@ public class JavaAgent {
private static InstrumentationModelFinder modelFinder;
private static ModelInstrumentation modelInstrumentation;
private static final Set<ClassLoader> loaders = new HashSet<ClassLoader>();
private static Method modelFound;
private static Method modelFoundMethod;

private static final List<String> skipList = new ArrayList<>(Arrays.asList("rt.jar", "activejdbc-", "javalite-common", "mysql-connector", "slf4j",
"rt.jar", "jre", "jdk", "springframework", "servlet-api", "activeweb", "junit", "jackson", "jaxen",
"dom4j", "guice", "javax", "aopalliance", "commons-logging", "app-config", "freemarker",
"commons-fileupload", "hamcrest", "commons-fileupload", "commons-io", "javassist", "ehcache", "xml-apis"));

private JavaAgent() {

Expand All @@ -54,7 +55,14 @@ public static void premain(String args, java.lang.instrument.Instrumentation ins
modelFinder = new InstrumentationModelFinder();
modelInstrumentation = new ModelInstrumentation();
//calling this via reflection because we do not want AJ dependency on instrumentation project
modelFound = Classes.ModelFinder.getDeclaredMethod("modelFound", String.class);
modelFoundMethod = Classes.ModelFinder.getDeclaredMethod("modelFound", String.class, String.class);
if (args != null && args.isBlank()) {
for(var s : args.split(",")) {
if (!s.isBlank()) {
skipList.add(s);
}
}
}
} catch (Exception e) {
throw new InstrumentationException(e);
}
Expand All @@ -64,52 +72,59 @@ public static void premain(String args, java.lang.instrument.Instrumentation ins
public synchronized byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
try {

CtClass clazz = modelFinder.getClazz(className.replace('/', '.'));
if (modelFinder.isModel(clazz)) {
if (!loaders.contains(loader) && loader instanceof URLClassLoader) {
if (!loaders.contains(loader)) {
scanLoader(loader);
loaders.add(loader);
List<CtClass> models = modelFinder.getModels();
for (CtClass ctClass : models) {
modelFound.invoke(null, ctClass.getName());
modelFoundMethod.invoke(null, Instrumentation.getDatabaseName(ctClass), ctClass.getName());
}
}
byte[] bytecode = modelInstrumentation.instrument(clazz);
Logger.debug("Instrumented model: " + clazz.getName());
return bytecode;
} else {
return null;
}
} catch (Exception e) {
} catch (NotFoundException ignored) {
} catch (Throwable e) {
throw new InstrumentationException(e);
}
return null;
}
});
}

private static void scanLoader(ClassLoader loader) throws ClassNotFoundException, IOException, URISyntaxException {
Logger.debug("Scanning class loader: " + loader);
//lets skip known jars to save some time
List<String> toSkipList = asList("rt.jar", "activejdbc-", "javalite-common", "mysql-connector", "slf4j",
"rt.jar", "jre", "jdk", "springframework", "servlet-api", "activeweb", "junit", "jackson", "jaxen",
"dom4j", "guice", "javax", "aopalliance", "commons-logging", "app-config", "freemarker",
"commons-fileupload", "hamcrest", "commons-fileupload", "commons-io", "javassist", "ehcache", "xml-apis");

private static void scanLoader(ClassLoader loader) throws IOException {
URL[] urls;
if (loader instanceof URLClassLoader) {
URL[] urls = ((URLClassLoader) loader).getURLs();
for (URL url : urls) {
boolean skip = false;
for (String name : toSkipList) {
if (url.getPath().contains(name)) {
skip = true;
}
urls = ((URLClassLoader) loader).getURLs();
} else {
Enumeration<URL> e = loader.getResources("");
List<URL> urlList = new ArrayList<>();
while(e.hasMoreElements()) {
URL url = e.nextElement();
urlList.add(url);
}
urls = urlList.toArray(new URL[0]);
}
for (URL url : urls) {
boolean skip = false;
for (String name : skipList) {
if (url.getPath().contains(name) || url.getProtocol().contains("jar")) {
skip = true;
break;
}

if (!skip) {
}
if (!skip) {
try {
modelFinder.processURL(url);
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ protected void checkAttribute(String attribute) {
}
}

protected static String getDbName(Class<? extends Model> modelClass) {
protected static String getDbName(Class<?> modelClass) {
DbName dbNameAnnotation = modelClass.getAnnotation(DbName.class);
return dbNameAnnotation == null ? DB.DEFAULT_NAME : dbNameAnnotation.value();
}
Expand Down
36 changes: 6 additions & 30 deletions activejdbc/src/main/java/org/javalite/activejdbc/ModelFinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.io.IOException;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class ModelFinder {

Expand Down Expand Up @@ -66,15 +67,6 @@ private static synchronized Map<String, Set<String>> getModelMap() {
return modelMap;
}

// protected static Set<String> getModelsForDb(String dbName) throws ClassNotFoundException {
// Set<String> modelClassNames = getModelMap().get(dbName);
// if (modelClassNames == null || modelClassNames.isEmpty()){
// throw new InitException("you are trying to work with models, but no models are found. Maybe you have " +
// "no models in project, or you did not instrument the models. It is expected that you have " +
// "a file activejdbc_models.properties on classpath");
// }
// return modelClassNames;
// }
protected static Set<Class<? extends Model>> getModelsForDb(String dbName) throws ClassNotFoundException {
Set<String> modelClassNames = getModelMap().get(dbName);
Set<Class<? extends Model>> classSet = new HashSet<>();
Expand All @@ -100,26 +92,10 @@ protected static Set<Class<? extends Model>> getModelsForDb(String dbName) throw
}
return classSet;
}
//
// //called dynamically from JavaAgent
// public static void modelFound(String modelClassName){
// synchronized (modelMap){
// if(!modelClassNames.contains(modelClassName))
// modelClassNames.add(modelClassName);
// }
// }

// @SuppressWarnings("unchecked")
// public static void registerModelClass(String className) throws IOException, ClassNotFoundException {
// Class clazz = Class.forName(className);
// if (!clazz.equals(Model.class) && Model.class.isAssignableFrom(clazz)) {
// String dbName = MetaModel.getDbName(clazz);
// Set<Class<? extends Model>> classSet = modelClasses.get(dbName);
// if (classSet == null) {
// modelClasses.put(dbName, classSet = new HashSet<>());
// } else if(classSet.contains(clazz)) return;
// classSet.add(clazz);
// }
// }
//
public synchronized static void modelFound(String dbName, String modelClassName) throws ClassNotFoundException {
Set<String> models = getModelMap().computeIfAbsent(dbName, k -> ConcurrentHashMap.newKeySet());
models.add(modelClassName);
}

}

0 comments on commit 4b50620

Please sign in to comment.