I'm currently working on a client/server application that supports dynamicly loaded classes.
These classes are plugins which should not be able to access certain methods.
My first idea was a SecurityManager that checked class names in the stacktrace but that does not seem to be the ideal way to approache this.
How would one employ such restrictions to specific classes?
Is there a (realisable) way to read every referenced class from class file content?
Related
I have an application that consists of a grid of hazelcast nodes which uses extensive runtime bytecode generation (asm). Specifically I am dynamically building predicate<> Java functions from user entered filter expressions. I would like to store the predicates in a map so that they are available across the cluster without having to be recompiled. Predicates are not the only instance of this. I also have ORM style mapping classes that are generated at runtime which need to be shared across the cluster. These classes are loaded by a custom classloader called DynamiClassLoader.
At first I was unable to store my custom generated classes in Hazelcast IMaps, getting a ClassNotFoundexception. However, I found if tell Hazelcast to use my custom DynamicClassLoader using Config.setClassLoader() then it is able to find my dynamic classes and use them in the local member so I have no issues serializing and deserializing instances of my custom classes in IMaps in the same member.
However, I am still unable to deserialize instances of my predicates which were inserted into the map by a different member. I have enabled UserCodeDeployment and stepped through the code in my debugger to confirm that if it cannot find the class locally then it is hitting UserCodeDeploymentClassLoader.java and on the classNotFoundException it is proceeding to check other members for the classes but it is unable to find them. I haven't been able to discover how exactly this works. it seems to look in an internal map for which member any given class can be found on and it does not find my classes in there. I believe it dispatches an operation to other members then to look for the class, but in this case it looks like my custom classloader isn't used so it's not able to find my custom classes.
How can I make dynamically generated classes work with UserCodeDeployment on Hazelcast? Is there a way I can 'register' my dynamic classes with the member's code service or something like that?
Thankyou,
Troy.
I've finally figured this out after extensive debugging. It turns out that the operation in Hazelcast on the target member to find a class calls loadBytecodeFromParent() in ClassDataProvider.java. This looks for a .class file using getResourceAsStream on the classloader:
String resource = className.replace('.', '/').concat(".class");
...
is = parent.getResourceAsStream(resource);
Which basically looks for the class file on the filesystem. Since my dynamic classes are entirely in memory there is no .class file resource for it to find.
I resolved this, by putting a hashmap in my DynamicClassLoader to keep the generated bytecode in and overriding getResourceAsStream to return that bytecode when it's available before looking further. Now it works!
So my problem is very simple, I got a plugin management program that allows plugins to be loaded and run AFTER the initial program got launched. All that works fine, I can load and unload the classes as I wish but the problem I encountered now is the following:
I am now trying to write a plugin to that plugin management system which is going to take care of all networking to prevent every plugin to host its own connection. The problem is that I can't use bootstrap classes as the plugins are loaded dynamically on runtime (I don't even know if it's there till I look for it and load it) yet I do still want to override the normal socket class to filter what's going on. Same goes for other classes that I want to override using plugins so that other plugins trying to use those classes and their functions will no longer be able to access the native implementation but instead will have to go through my implementation of it. Don't ask, I have reasons :P
So all just put together shortly: I need a way to dynamically on runtime override native classes with my own implementations of them so that everything else I load will use my implementation instead of the native one. Any ideas?
Depending on how the dynamic class loading works, this is probably not possible (you need to provide more details to be sure, but if it's using a new ClassLoader per plugin, you can't override system classes from it)
But for your specific problem, namely to provide your own implementation of network sockets, there is a much better solution.
You need to implement java.net.SocketImplFactory and call Socket.setSocketImplFactory, as well as ServerSocket.setSocketFactory with an instance of your factory. (Don't ask me why these two methods are not named the same)
Your factory should then create your subclass of SocketImpl that can do all networking in its own way.
You should not override Socket. Just use Socket.setSocketFactory to provide your own implementation.
I don't want to use the URL Classloader to load classes.
I want to implement this myself.
I don't want to use a solution like JRebel (although it's great).
I've got prior experience of JavaAssist, bytecode generation, implementing javaagent class transformers etc.
I would like to write a javaagent which hooks into the classloader or defines it's own system classloader.
I'll store the class files in an in memory cache, and for particular files, periodically reload them from disk.
I'd prefer to do this in a way which doesn't involve continuously polling the file system and manually invalidating specific classes. I'd much rather intercept class loading events.
I last messed around with this stuff 4 years ago, and I'm sure, although my memory may deceive me that it was possible to do, but 8 hours of searching google doesn't present an obvious solution beyond building a patched JVM.
Is this actually possible?
I've created a stub implementation at https://github.com/packetops/poc_agent if anyone's interested in a simple example of javaagent use.
update
Just found this post - I may have been using the wrong approach, I'll investigate further.
It depends on what you want to do. If you want to reload your classes and define new ones, then you are fine with implementing your own classloader, as you already found.
If you want to replace existing classes, things become more "envolved". You can do this by implementing your own tiny Java agent. See the Java documentation, how to do this: http://docs.oracle.com/javase/7/docs/api/java/lang/instrument/package-summary.html
With the instrumentation mechanism you can not freely redefine classes, quote from Instrumentation.redefineClass:
The redefinition may change method bodies, the constant pool and attributes. The redefinition must not add, remove or rename fields or methods, change the signatures of methods, or change inheritance. These restrictions maybe be lifted in future versions. The class file bytes are not checked, verified and installed until after the transformations have been applied, if the resultant bytes are in error this method will throw an exception.
If you want to do more, you need to load it again. This can be done under the same name, by using a different classloader. The previous class definition will be unloaded, if no one else is using it any more. So, you need to reload any class that uses your previous class also. Utlimatly, you end up reinventing something like OSGi. Take a look at: Unloading classes in java?
As we know java class loading works like in picture below.
When we have a notion of plugin in our application (like app servers) we sometimes need some classes to be loaded in the instances class loader rather than in parent, so that each new instance (plugin, webapp or whatever) loads that particular class not delegating the parent...
For example Log4j classes, we need them to be loaded for each instance.
So in order to do this the best approach that came into my mind is to write custom classloader that will take a list of class names which shall be prevented from being delegated to parent classloader (ideally we want instances to be in complete isolation).
So the the application that will load other "instances" will use that custom classloader while loading those "instances"...
Is there an implementation of such classloader that solves this issue? (given that we dont want to know what OSGi is and we work with pure java no frameworks etc...)
My searches end up pointing some frameworks or some web container specific solutions, yet this is quite a simple task that is solved with one class, I'd like to find out if i'm missing something before i start implementing it.
Update (digging deeper) : suppose there is a class loaded by bootstrap which has static state that can be shared between instances (and we really badly want to make sure instances are completely isolated), now that class is obviously not included in our classpath, but it is loaded, and if we copy it instead of reffering it we will achieve the required isolation.
So do we have the notion of copying or cloneing a class from one classloader to other?
I am looking for a simple scenario when can be requirement to create a custom class loader?
Apart from that, just wanted to confirm that Does even bootstrap and application class loader extends java.lang.ClassLoader internally?
In short, it can be used to add new code or to change existing code on the fly. Here's a more detailed explanation from this URL.
Why write a custom class loader?
The three main reasons for wanting to create a custom class loader are:
To allow class loading from alternative repositories.
This is the most common case, in which an application developer might want to load classes from other locations, for example, over a network connection.
To partition user code.
This case is less frequently used by application developers, but widely used in servlet engines.
To allow the unloading of classes.
This case is useful if the application creates large numbers of classes that are used for only a finite period. Because a class loader maintains a cache of the classes that it has loaded, these classes cannot be unloaded until the class loader itself has been dereferenced. For this reason, system and extension classes are never unloaded, but application classes can be unloaded when their classloader is.