load java clases from outside web application - java

I have a servlet which takes in some parameters. One of the parameters include the class name which should do some operations based on the other parameters sent to the servlet. The class name parameter is dynamic so the servlet wouldn't know which class to load beforehand.
Since the classes change frequently (for maintenance) i need to keep the classes outside of the Application since I cannot restart server in the production environment.
Also I need to keep in mind if the classes change the servlet needs to load up the most recent version of the class.What is the best option that i have.
Use a rule engine.
Use dynamic class loading but I am scared that after some there will be simply too many classes loaded in the memory and permgen space will suffer.
Please advise. Thanks in advance

This sounds like potentially dangerous in terms of security, but I am assuming you have taken steps to mitigate already.
The most straight-forward way, I believe, is to use dynamic class loading. Construct a URL classloader to load off a fixed file system location (make sure people cannot arbitrarily run any class they want!) load the class using that and execute the code (possibly via reflection as the class will not be visible on your web application's classloader) and properly dispose of the classloader and any objects created (such that there are no memory leak) As you mentioned, you might need to increase PermGen, but that goes for any solution that involves loading additional classes (which is part of your requirement)

Related

How to create a singleton from within a private classloader?

I have a Java class that gets instantiated by a third-party application as an extension. That is, as per the 3rd party software design, customers like us register our Java class to their application and their application will install it to execute custom logic at the right place and time.
Our custom Java class needs to marshal and unmarshal XML, for which it uses JAXB. It therefore needs a JAXB context.
I naively called JAXBContext.newInstance(MyClass.class) on every call and not-so-quickly discovered that that's a well known recipe for a memory leak. The common prescription is to make one (or at most only a few) JAXB contexts to share among your whole application.
Fine, except the third party application that invokes my class makes each invocation on a new ClassLoader instance that is private to that invocation.
So, even if I put the JAXBContext in a static field or static HashMap<>, it would still be private to the invocation!
QUESTION
How can I, in a class that is instantiated from a private ClassLoader instance, create a singleton to be shared across the JVM?
I am thinking along two possible lines, but I'd like advice on how to make either of them work or any completely different approach anyone has.
The three ideas I had were:
Find somewhere in a JVM class where I could write an object. E.g., if System.setProperty could write instance of Object instead of just String, the idea would be to create the JAXB context and put it in a property, since it is sure that System will already have been instantiated and that the custom classloader instance would inherit it. But System.setProperty does not take an Object value, so I don't know a practical way to do this.
Somehow force a class to load on the parent or root classloader where I could store by JAXB context. I don't know how to do this.
Use a ThreadLocal to store the JAXBContexts. I don't think each invocation is a brand new thread (they're probably reused from a thread pool), so this could maybe be the way to limit my contexts. But how to create the ThreadLocal variable so its shared across the instances? It seems like this leaves me with the same problem.
It sounds like your code is sandboxed with in the 3rd party application. So using static or ThreadLocal won't help since it will only exist within the same classloader, and if that classloader is changed... then the context is lost.
The closest solution is to inject your context into the application code. This is not the best idea, since it can be affected by outsiders and have unexpected consequences. Do note that this means a value you created in your classloader will remain in the application and thus the creating classloader will never be garbage collected. There's also the problem of where JAXB jar comes from. I assume from your code and not the 3rd party. So that jar is loaded each time in a different classloader, so to share an object from there might be a problem and require some proxy.
Honestly there can be so many unforeseen results.
The best idea is to ask the 3rd party to provide you with some API to enable that.
Before continuing, let's see other options:
Is there a replacement for using JAXB? Something that won't present the same memory leak problem.
Is the memory leak that serious? What if there is a temporary memory leak until an API is provided by the 3rd party application.
If you really want to try to inject the object, I'd be happy to help. But, from experience, these kinds of things are messy.

How to use the Java Instrumentation API to reload classes when they change on the the file system?

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?

Hacking a singleton with classloaders - Multiton in a Java web app

I am creating a web front end using an existing back end containing several singleton classes. The DataStore is initialized by passing a user object into it, which is fine in a desktop application environment where the app is launched once on each machine, but will not work in a server side application designed to cater for multiple users.
The database guys are reluctant to change the service layer and remove these singletons to allow an instance per user, or allow a single instance of a service layer object to serve multiple users. This is with good reason, the desktop app has been in use for 10 years and changes could have serious side effects for the desktop app.
I have been asked to investigate using classloaders to create multiple instances of the singletons. I am not comfortable with this idea at all, hacking singletons seems like bad practice, but changing the service layer could take months of work.
I have tested this out already by putting two identical WAR files of my app (with different file names) into Tomcat. Tomcat creates a classloader for each webapp and they worked just fine separately. I only encountered problems when the singletons used System.setProperty/System.getProperty, which is to be expected as the System class comes from a classloader much higher up in the tree.
To get this separation within a single webapp, it starts to get a bit complicated. It seems I would have to create a different classloader for each session, and use the classloader to load either all the classes in the whole service layer or just the ones which are singletons and their dependencies.
The problem comes when I'm thinking about how to use these objects in a session in a servlet. Because each Servlet has a single instance within a Tomcat, getting objects from the session and casting them will not be straightforward. Eg, to get a DataStore object from the session, I would have to cast it to the correct DataStore class loaded by the correct ClassLoader, since a single class loaded by two different ClassLoaders counts as two completely separate classes.
I have read that using ClassLoaders can cause all sorts of problems with memory leaks if they are not used carefully, and from the sounds of this, if I have 500 users, that is a lot of classloaders and classes loaded by classloaders. Won't I then have also have issues with PermGen?
I suppose from this large explanation, I really have 4 questions:
Hacking a singleton with classloaders in a webapp. Creating potentially hundreds of instances of the same classes designed to be singletons. Is that a terrible idea? So terrible I shouldn't contemplate it?
What is the best way to implement this if I absolutely have to?
How do I cater for casting in a Servlet, if I want to get and set objects into a session?
Will I end up with issues with memory leaks, and PermGen space?
I would really appreciate any suggestions. Thanks :)
It's not ideal, but I don't think it's terrible. In practice, it's not much worse than loading multiple versions of the same class (even without singletons), and that's becoming increasingly common in complex application server environments, particularly those with OSGi.
It's hard to say which approach is best, but to begin with, I would start by creating child class loaders of your web application class loader. Arrange to load implementation classes in the child class loaders (i.e., the ones with the singleton), and it possible, have the implementation class implement an interface that is loaded from the web application class loader.
By loading the interface from the web application class loader. This is basically the same approach that the application server itself is using to invoke your HttpServlet: the interface is loaded by the server, so it can refer to it directly, but the implementation is in a child class loader for your application. You're just creating a secondary layer of interface/impl split for your own convenience.
You'll end up with memory leaks if you store references to the child class loader (or its loaded classes, or instantiated objects from those classes) in a "parent" class loader (e.g., if the singleton registers an MBean, which causes it to get referenced in a JVM-wide object), but that's no different from if you weren't creating child class loaders. If you're dynamically creating/destroying these singletons (thus child class loaders), you'll have to take care that you don't retain references to those child class loaders (or classes/objects) longer than necessary. PermGen is probably more problematic. If you can run with Java 8, that's gone away; otherwise, you might have to increase the default PermGen size depending on how many of these class loaders/singletons you need to create.

Loading Java Classes which arent needed

I'm currently wondering what the actual overhead, in the JVM, is for loading extra classes which are never used.
We have code which iterates all the classes in the class path to find classes which implement a certain interface, we then load them.
This allows custom classes to be simply dropped in a directory and they get loaded and registered.
The side affect is that we hit every class in the class path, causing the classes to load. What would be the affect on the JVMs memory?
Does simply loading classes affect the memory much at all?
As usual, I would advise measuring this for your particular scenario.
Having said that, I'm not sure I'd advise scanning the whole classpath. If you don't control the classpath (it's your customer's, or similar), potentially they could add anything to it, and your process is going to scan anything they drop into their classpath (possibly unrelated to your app).
I'd suggest that you nominate only certain directories/repositories that classes can be uploaded to, and that way you'll restrict the classpath scanning and reduce the chances of inadvertently picking up stuff you don't intend to.
If you use a separate ClassLoader to load those classes and are very careful not to create any references to those classes or instances of them, then when the ClassLoader becomes eligible for garbage collection, so do the classes.
Thus, you could avoid unnecessarily clogging your PermGen space by doing 2 passes with separate ClassLoaders: one to load all the classes and identify those you want to keep, and another to actually use them.
Won't using ClassLoaders in this way have unintended side-effects? Like running static initialisers and so on.
You could use the ServiceLoader mechanism, but if that doesn't suit, you can inspect classes without using ClassLoaders - byte manipulation libraries like BCEL and ASM can be used to just inspect classes.
Yes, this forces the VM to load the class file and examine it (which can be a performance problem). Moreover, if you're using a Sun VM, then these classes will stay in memory forever. the Sun VM puts classes in the so called "PermGen" space which is never garbage collected unless you specify a special option.
So this is generally a bad idea but there are two simple workarounds:
Check the name of the class (the filename). Repeat the name of the interface in the name, so you can easily notice what you have to load and what not.
Use two directories. One contains normal classes, the other the one all those which you want to always load.
A "far out there" suggestion:
could you do the same thing but without actually using the VM? the class file spec is documented, couldn't you write your own app to just read the class files and figure out if they implement your interface/whatever without actually loading them?
That would get you the ability to scan any directories but without any worry of loading classes or static intializers or anything like that.

Which class would load first when Web application starts?

I have a web application and two class files,
First class is MyClass.class which is inside the abc.jar file (WEB-INF/lib/abc.jar) and
Second class is YourClass.class which is inside classes folder (WEB-INF/classes/ YourClass.class).
My question is which class would load first when the Application starts? And Why ?
In my experience you can't predict the order in which the classes are loaded by the JVM.
Once I made a test runner (kinda Maven's Surefire) and with the same JVM and OS it loaded classes in different order when run in different machines. The lesson learnt:
You shouldn't build your applications
to depend on class loading order
Classes are loaded as needed, for some definition of "needed". Exactly when a class is loaded is dependent upon the JRE implementation, javac implementation, exactly what thread are up to, server code and, of course, application code. It's a bad idea to make assumptions in this area. If you want to see what happens for a particular run, you can use -verbose:class
Sun's class loader docs always say WEB-INF/classes OR WEB-INF/lib, but doesn't say which one will be checked first.
From IBM docs:
"The rules for loading classes are spelled out in detail in the JVM specification. The basic principle is that classes are only loaded when needed (or at least appear to be loaded this way -- the JVM has some flexibility in the actual loading, but must maintain a fixed sequence of class initialization). Each class that gets loaded may have other classes that it depends on, so the loading process is recursive."
So I think the answer is: It depends on which classes is needed in your application first.
As duffymo points out, this can vary. One way you might ascertain the sequence for this specific app is to insert Response.Write text in the class constructors and web web app page loading methods. "Instantiated object in Class A", "Opened web page MyPage", and so on.
Once you've figured out the sequence, comment out the code for those so you can reuse them later to verify that you haven't made a change (such as instantiating an object earlier or later) that affected the sequence.

Categories

Resources