Starting Instrumentation Agent after VM Startup - java

I was hoping for someone to explain this item since I might be getting this wrong:
I was reading about Java Agent Instrumentation which says that the agent can start after VM startup. So if I want to dynamically replace some class (without brining down the app) is this what I am going to go for using agent-main? Or do I need to do something more here?
I know people might ask "Are you talking about JRebel" - not really because I want to do something simple and JRebel is an overkill.
instrument docs - Java docs for Instrumentation
I understand all the instrumentation overrides, but I am slightly confused how I can hook this agent with -agent argument after the app has started.

First your agent class needs to specify an agentmain method like:
public class MyAgent {
public static void agentmain(final String args, final Instrumentation inst) {
try {
System.out.println("Agent loaded.");
} catch (Exception e) {
// Catch and handle every exception as they would
// otherwise be ignored in an agentmain method
e.printStackTrace();
}
}
}
Compile it and pack it inside a jar-file for example. If you choose the jar-variant then it must specify the Agent-Class key in its manifest-file (MANIFEST.MF). It points to the class implementing the agentmain method. It could look like:
Manifest-Version: 1.0
Agent-Class: package1.package2.MyAgent
If it is located inside those packages, as an example.
After that you can load the agent via the VirtualMachine#loadAgent method (documentation). Note that the mechanism used by those classes are part of the Attach library of Java. They decided, as most users don't need it, to not directly add it to the systems path but you can just add it. It is located at
pathToYourJDKInstallation\jre\bin\attach.dll
And it needs to be somewhere where the system property java.library.path is pointing at. You could for example just copy it to your .../Windows/System32 folder or adjust the property or stuff like that.
As an example, if you want to inject an agent-jar inside another currently running jar, you could use a method like this:
public void injectJarIntoJar(final String processIdOfTargetJar,
final String pathToAgentJar, final String[] argumentsToPass) {
try {
final VirtualMachine vm = VirtualMachine.attach(processIdOfTargetJar);
vm.loadAgent(pathToAgentJar, argumentsToPass.toString());
vm.detach();
} catch (AttachNotSupportedException | AgentLoadException
| AgentInitializationException | IOException e) {
System.err.println("Unable to inject jar into target jar.");
}
}
With the same technique you can inject dll-libraries (if they implement the corresponding agent-methods via the native agent interface) into jars.
Actually, if that helps you, I have written some small library for that kind of stuff some time ago. See Mem-Eater-Bug, the corresponding class is Injector.java and the whole project has a small Wiki.
It has an example showing how to use that technique to manipulate a SpaceInvaders game written as Java application.

So apparently you want to reload classes at runtime. Such that your project can react to changes of the code without restarting.
To achieve this you need to prepare your project and write a very clean architecture, it involves using interfaces, factory-patterns, proxy-patterns and a routine that checks for updates and then destroys and rebuilds all current objects.
Unfortunately this might not be an easy task, but it is doable, depending on the size of your project and the amount of code that should react dynamically to changes.
I found this article helpful, let me explain how it works. You can easily load a class with ClassLoader.loadClass(...) and you can also use that to reload a class, very easy. However at the time you have compiled your code classes are some kind of hardwired already. So your old code will continue to create instances of the old classes although you have reloaded the class.
This is the reason why we need some kind of architecture that allows exchanging the old class with the new class. Also it is pretty obvious that current instances of the old class can not automatically be transferred to the new version as everything could have changed. So you will also need a custom method that collects and rebuilds those instances.
The approach described in the article uses an Interface instead of an actual class in the first place. This allows to easily exchange the class behind that interface without breaking the code that uses the interface.
Then you need a factory where you ask for instances of that Interface. The factory can now check if the underlying class-file has changed, if so it reloads it and obtains a reference to the new class version. It can now always create an instance of the interface which uses the up-to-date class.
The factory, by that, is also able to collect all created instances in order to exchange them later, if the code base has changed. But the factory should reference them using WeakReference (documentation), else you have a big memory leak because the Garbage Collector would not be able to delete instances because the factory holds references to them.
Okay, now we are able to always obtain up-to-date implementations of an Interface. But how can we easily exchange existing instances. The answer is by using a proxy-pattern (explanation).
It is simple, you have a proxy class which is the actual object you are working with. It has all the methods of the Interface and upon calling methods it simply forwards to the real class.
Your factory, as it has a list of all current instances using WeakReference, can now iterate the list of proxies and exchange their real class with a new up-to-date version of the object.
Existing proxies that are used all around your project will now automatically use the new real version as the proxy itself has not changed, only its internal reference to the real target has changed.
Now some sample code to give you a rough idea.
The interface for the objects you want to monitor:
public interface IExample {
void example();
}
The real class, which you want to rebuild:
public class RealExample implements IExample {
#Override
public void example() {
System.out.println("Hi there.");
}
}
The proxy class that you will actually use:
public class ProxyExample implements IExample {
private IExample mTarget;
public ProxyExample(final IExample target) {
this.mTarget = target;
}
#Override
public void example() {
// Forward to the real implementation
this.mRealExample.example();
}
public void exchangeTarget(final IExample target) {
this.mTarget = target;
}
}
The factory you will mainly use:
public class ExampleFactory {
private static final String CLASS_NAME_TO_MONITOR = "somePackage.RealExample";
private final List<WeakReference<ProxyExample>> mInstances;
private final URLClassLoader mClassLoader;
public ExampleFactory() {
mInstances = new LinkedList<>();
// Classloader that will always load the up-to-date version of the class to monitor
mClassLoader = new URLClassLoader(new URL[] {getClassPath()}) {
public Class loadClass(final String name) {
if (CLASS_NAME_TO_MONITOR.equals(name)) {
return findClass(name);
}
return super.loadClass(name);
}
};
}
private IExample createRealInstance() {
return (IExample) this.mClassLoader.loadClass(CLASS_NAME_TO_MONITOR).newInstance();
}
public IExample createInstance() {
// Create an up-to-date instance
final IExample instance = createRealInstance();
// Create a proxy around it
final ProxyExample proxy = new ProxyExample(instance);
// Add the proxy to the monitor
this.mInstances.add(proxy);
return proxy;
}
public void updateAllInstances() {
// Iterate the proxies and update their references
// Use a ListIterator to easily remove instances that have been cleared
final ListIterator<WeakReference<ProxyExample>> instanceIter =
this.mInstances.listIterator();
while (instanceIter.hasNext()) {
final WeakReference<ProxyExample> reference = instanceIter.next();
final ProxyExample proxy = reference.get();
// Remove the instance if it was already cleared,
// for example by the garbage collector
if (proxy == null) {
instanceIter.remove();
continue;
}
// Create an up-to-date instance for exchange
final IExample instance = createRealInstance();
// Update the target of the proxy instance
proxy.exchangeTarget(instance);
}
}
}
And finally how to use it:
public static void main(final String[] args) {
final ExampleFactory factory = new ExampleFactory();
// Get some instances using the factory
final IExample example1 = factory.createInstance();
final IExample example2 = factory.createInstance();
// Prints "Hi there."
example1.example();
// Update all instances
factory.updateAllInstances();
// Prints whatever the class now contains
example1.example();
}

Attaching an agent at runtime requires use of the attach API which is contained in the tools.jar until Java 8 and is contained in its own module starting from Java 9. The location of the tools.jar and the name of its classes is system-dependent (OS, version, vendor) and as of Java 9 it does not exist at all but must be resolved via its module.
If you are looking for an easy way to access this functionality, try out Byte Buddy which has a subproject byte-buddy-agent for this. Create a Java agent as you are used to it but add anAgent-Main entry where you would put your Pre-Main in the manifest. Also, name the entry method agentmain, not premain.
Using byte-buddy-agent, you can write a program:
class AgentLoader {
public static void main(String[] args) {
String processId = ...
File agentJar = ...
ByteBuddyAgent.attach(processId, agentJar);
}
}
and you are done.

Related

Listening to class reload in Java

For performance reasons, I have a class that stores a Map whose key is a Class<?> and its value is function of that class's fields. The map is populated during code execution according to the type of the calling object. The above is a generalization/simplification
public class Cache {
private static final Map<Class<?>, String> fieldsList = ...;
//Synchronization omitted for brevity
public String getHqlFor(Class<?> entity){
if (!fieldsList.containsKey(entity))
fieldsList.put(entity,createHql(entity));
return fieldsList.get(entity);
}
}
During development, thanks to the help of Jrebel, I often make modifications to classes by changing entire properties or just their names. I can continue development just fine. However, if I already put a value into the cache it will be stale forever.
What I am asking here is if it is possible to intercept the event that a class in the classpath has changed. Very broad... But my specific problem is very simple: since I have such a need only during development, I just want to wipe that cache in case any class in my classpath changes.
How can I accomplish this? I don't need to do anything special than intercepting the event and simply wiping the cache
JRebel has a plugin API that you can use to trigger code on class reloads. The tutorial complete with example application and plugin available here: https://manuals.zeroturnaround.com/jrebel/advanced/custom.html
The JRebel plugin is a self-contained jar built against the JRebel SDK, which is attached to the running application via the JVM argument -Drebel.plugins=/path/to/my-plugin.jar. The JRebel agent attached to the application will load and start plugins from this argument.
If the application is not started with the JRebel agent, the plugin is simply not loaded.
In your example you want to register a ClassEventListener that will clear the Cache.fieldsList map. As it is a private field, you need to access it via reflection or add a get/clear method via a ClassBytecodeProcessor
public class MyPlugin implements Plugin {
void preinit() {
ReloaderFactory.getInstance().addClassReloadListener(new ClassEventListenerAdapter(0) {
#Override
public void onClassEvent(int eventType, Class<?> klass) throws Exception {
Cache.clear();
}
});
}
// ... other methods ...
}
And to clear the map
public class CacheCBP extends JavassistClassBytecodeProcessor {
public void process(ClassPool cp, ClassLoader cl, CtClass ctClass) {
ctClass.addMethod(CtMethod.make("public static void clear() { fieldsList.clear(); }", ctClass));
}
}
However a better option is to only clear/recalculate the single class entry on class reload if possible. The example didn't display whether the info computed from one class depended on superclass infos, but if this is true, the JRebel SDK has methods to register a reload listener on the class hierarchy as well.
There is an existing class ClassValue which already does the job for you:
public class Cache {
private final ClassValue<String> backend = new ClassValue<String>() {
#Override
protected String computeValue(Class<?> entity) {
return createHql(entity);
}
};
public String getHqlFor(Class<?> entity){
return backend.get(entity);
}
}
When you call get, it will call computeValue if this is the first call for this specific Class argument or return the already existing value otherwise. It does already care thread safety and for allowing classes to get garbage collected. You don’t need to know when class unloading actually happens.

Java calling unknown code or method from, not yet, existing dependency

i have two independent projects Basic and Extension with following setup
Project A:
class Handler {
public void handle(){
...
}
}
Project B
import Handler; //from Proejct A
class SomeClass{
someMethod() {
handle(); //dependency to Project As class with handle method
}
}
So the problem is the dependecy to the handle method which exists at Project A but not at compile time on Project B.
The final step is to have build Project Extension as a jar and import it inside Project Basic.
Ofc the compiler will give me error when i build Project B since the handle is not known at compile time.
For this issue i need a solution:
Either: Tell java that the missing code (import class with handle method) will be there at running time.
Or maybe Dependency Injection due to a factory pattern.
I am known to the factory pattern, but i don't understand how it could help me in this situation.
Or another solution.
Can you help me?
Neither of these are valid Java - won't compile. The proper keyword is "class", not "Class".
You have to provide it at compile time once you get it right - you have no choice. No way around it.
Maybe you should look at the Java JDK and follow the example in the java.sql package: Interfaces. Connection, ResultSet, Statement, etc. are all interfaces so vendors can provide their own implementations. Users only deal with interfaces.
Your GenericHandler should be an interface that you provide to clients. They add their implementations and add their JAR file containing the custom implementation at runtime.
Basic interface that all extensions implement:
public interface GenericHandler {
void genericHandle();
}
Extension code:
import GenericHandler;
public class Extension implements GenericHandler {
public void genericHandle() {
// Do something useful here
}
}
The factory pattern works only if you provide a finite, closed set of implementations:
public class GenericHandlerFactory {
private final GenericHandlerFactory instance = new GenericHandlerFactory();
private GenericHandlerFactory() {}
public GenericHandler getInstance() { return this.instance; }
public GenericHandler createHandler(Class genericHandlerClass) {
GenericHandler result = null;
// Code to create the GenericHandler you want.
return result;
}
}
If users can extend your interface without your knowledge then a factory can't work; you have to stick to the JDBC example.

final static attribute change.. any idea or approach?

I have to maintain a code to add more flexibility to a final static variable in a class.
The variable is no more a global constant and may be changed.
The problem is that the class is in a common library and used in different projects.
Do you have an approach or a design pattern better than copying and pasting the class code from the common library to my specific application and refactoring it?
Example:
Commons project
Class CommonClass {
public final static var globalSomething = somethingGlobal;
public static method(){ //CommonClass.globalSomething is used here}
}
In my App (and other apps that reference commons) we can use the static attribute and also call the method:
---> var b = CommonClass.somethingGlobal;
---> var c = CommonClass.method() //we know that CommonClass.globalSomething is used here
Expectations:
Ability to change CommonClass.somethingGlobal in my app and take these changes in call CommonClass.method()
I can modify (add methods) in the common class but i have to keep the same initial behavior (not to break other project referencing common project)
If I got you right, you want to implement this as a parameter.
Looking at your example:
var c = CommonClass.method() //we know that CommonClass.globalSomething is used here
there is already something wrong with it. You shouldn't have to know that you have to set CommonClass.somethingGlobal correctly before calling the method. This way the client has to know the implementation, violating the principle of information hiding. If the value is required, introduce it as parameter:
Class CommonClass {
public static void method(var globalSomething){}
}
An alternative would be making both your variable and your method non-static and use a constructor:
Class CommonClass {
public var globalSomething = somethingGlobal;
public CommonClass(var globalSomething) {
this.globalSomething = globalSomething;
}
public void method(){}
}
PS: Your example code is not java. I corrected it partially in my answer.

how to register a java class if the static initializer isn't called till the class is referenced

I've an interface implemented by classes that perform a file processing, say searching or whatever.
public interface FileProcessorInterface {
public void processFile(String fileName);
}
Then i have a different implementation for each file type:
public class TxtProcessor implements FileProcessorInterface {
#Override public void processFile(String fileName) { //do the work }
}
Thus i have the Utilizer of the processor, that has a method that allows for registering each class, something like this:
class Utilizer {
Map <String, Class> registered = new HashMap<>();
public void registerClass(String fileExt, Class clazz) {
registered.put(fileExt, clazz);
}
public void processFile(String fileName) {
//1) get the registered class from registered map (omitted because easy and not relevant)
//2) create an instance of the class using reflection (omitted because easy and not relevant)
FileProcessorInterface p = ....
p.processFile(fileName);
}
So far it's ok.
Now, i'm providing many implementations of my interface.
And i am tempted to provide each implementation class with a static initializer that register itself in the Utilizer, in the case of my previous TxtProcessor it would be:
class TxtProcessor implements FileProcessorInterface {
//previous code
static {
Utilizer.registerClass("txt", TxtProcessor.class);
}
}
The problem is that this static method will never be called because in the "statically reachable" code of the application there is no reference to my TxtProcessor class, since it is instantiated via reflection. So the jvm does not call the static initializer.
Say that i have two parts: the "generic code" that is the Utilizer and on the other side the implementations; it has to be thought as something provided dinamically and so it is not known by the Utilizer part.
Infact the idea was exactly that each class would register itself leaving the Utilizer untouched.
It is hard for me conceiving a solution that does not put some form of 'knowledge' of the implementations on the Utilizer side (and that stays simple), just because of the problem of the static initializer not called. How to overcome this?
Using reflections seems to be the best fit here. It's like geared to do this.
All you need is a small static block in Utilizer as
static {
Reflections reflections = new Reflections(
new ConfigurationBuilder()
.setUrls(ClasspathHelper.forPackage("path.to.all.processors.pkg"))
.setScanners(new SubTypesScanner())
);
reflections.getSubTypesOf(path.to.all.processors.pkg.FileProcessor.class);
}
If you don't want a third-part dependency, just add a FileProcessors.properties file to your classpath
txt=path.to.all.processors.pkg.TxtProcessor
doc=path.to.all.processors.pkg.DocProcessor
pdf=path.to.all.processors.pkg.PdfProcessor
and then register all the listed classes from Utilizer as
static {
Properties processors = new Properties();
try {
processors.load(Utilizer.class
.getResourceAsStream("FileProcessors.properties"));
} catch (IOException e) {
e.printStackTrace();
}
for (String ext : processors.stringPropertyNames()) {
Utilizer.registerClass(ext, Class.forName(processors.getProperty(ext));
}
}
This no longer requires a static block in every FileProcessor now.
You can look at Reflections library. It allow you to find all the classes which implement an interface, have an annotation or extend a class.
You Could...
Use the same concept as JDBC does for loading it's drivers. This would require you to use Class#forName to initialize the class when the program is first loaded. While this does mean that the implementation is still dynamic from the point of view of your utility class, it is specified at run time by your application...
This gives you control over which implementation you might want to use
You Could...
Use the same concept as something like java.awt.Toolkit uses when it initializes it's instance.
It basically looks up the resource (in this case a System property) and then loads the class dynamically using Class.
Personally, I normally look for a named resource (usually a properties file) and load a key from it.
Something like getClass().getResource("/some/gloabl/configFile");, which every implementation would need to provide.
Then, if available, read the properties file and find the key I'm after.
If more then one implementation is linked in though, there is no guarantee which one will be loaded.
Quick and dirty: You can statically initialize your Utilizer in main() with correct association.
Better solution: externalize in a resource file association like
txt=path.to.package.TxProcessor
load it in Utilizer and load FileProcessorInterface implementors with Class.forName()
you can force the static init by Class.forName(fqn, true, classLoader) or the short form Class.forName(fqn)
You could have a registry file (for example, some XML file), that would contain the list of all classes you support :
<item type="txt">somepackage.TxtProcessor</item>
<item type="gif">somepackage.GIFProcessor</item>
...
Your Utilizer would load this file into its registry.

How can I exclude annotated definition from build in java?

I am building an Android app. Now, I have a source code for API #1, I should get it adapted for API #2. Then I will publish the both versions for API #1 and API #2 in different packages. I can't use something like values-en, because both versions can be used worldwide. Also, the user may not have choice.
As the new version will use same UI and DB logic, (and because now the code is erroneous,) I don't want to separate the code. If i were coding in c or c++, I must use #ifdef and Makefile. However, I'm in Java. It's possible to run the API-dependent code by determining the package name in runtime, but it's somewhat weird.
I think I can use annotations. What I expect is:
package foo.app;
public class API {
public boolean prepare() { ... }
#TargetPlatform(1)
public void open() { ... }
#TargetPlatform(2)
public void open() { ... }
}
and use only one of them. Also, this is good:
package foo.app;
public class R {
#TargetPlatform(1) com.example.foo.app.R R;
#TargetPlatform(2) net.example.foo.app.R R;
}
Just defining an annotation is simple. What I don't know is, how can I exclude unused duplicates from build or execution, or so on? If the work can be done in this way, I can do anything.
You cannot use annotations for that.
It would be better to hide the implementation specific classes behind an interface.
public interface Api {
boolean prepare();
void open();
}
To create a Api instance use a factory class:
public class ApiFactory {
public static Api createApi() {
if(isTargetPlatform1())
return new com.example.foo.app.Api();
else
return new net.example.foo.app.Api();
}
private boolean isTargetPlatform1() {
// determine the current platform, e.g. by reading a configuration file
}
}
In all other places you only refer to the Api interface and ApiFactory class.
Use it like that:
Api api = ApiFactory.createApi();
api.open();
// ...
A more advanced solution would be to use dependency injection.

Categories