DeleteOnExit jvm shutdown - java

I currently have a tomcat webapp that needs files deleted when the JVM is being shutdown. I created a custom ContextLoaderListener to handle the contextDestroyed event. Inside of here I call deleteOnExit on the appropriate files. However, ever since jdk 1.6.0_14 I am unable to deleteOnExit. Googling indicates that there was a change that is somewhat expected, but I haven't seen a work around for this. Anyone have any ideas?
Below code does NOT work.
for(File f : myFileList)
try{
f.deleteOnExit()
} finally {
f.delete()
}

I don't think you're going to be happy with the results of cleaning up files as part of an orderly shutdown process. For example, if your process crashes or is stopped with "kill -9", then your cleanup code will not run.
A more reliable approach is to set up the environment during start up / initialization. If you segregate the files for this application in a specific directory, then this is easy: just empty the directory in question.
Exactly where the "empty directory" call belongs, depends on your application. For example, if you wrote a servlet, then use the init method. Or, if you use Spring, then they provide various initialization hooks such as an init-method.

Related

Java - How to replace a running jar file

I want my java application to be able to automatically keep itself up to date, i already made all the code to download the latest jar file and put it in the designated path but since my program has to be open to actually check if there are updates available and then update them it gives me this error:
Exception in thread "main" java.nio.file.FileSystemException: name.jar: The process cannot access the file because it is being used by another process
Now my question is not why i get this error since it is quite obvious why, the question is: how would i go about actually updating the .jar file succesfully since it has to be open to actually download the update? I'd rather not make another .jar to act like a standalone updater if there are other options.
Example of the code i'm using to test:
URL url = new URL("<working url to the .jar file>");
InputStream in = url.openStream();
Files.copy(in, Paths.get("app.jar"), StandardCopyOption.REPLACE_EXISTING);
in.close();
First of all: the other answer is correct, there are ways to silently update/restart JAR files. And downloading new JARs, with a full restart, that is fine.
But the question asks about updating a JAR "in use", and for that I have a distinct non-answer: you are going down the very wrong rabbit hole!
Even if you somehow hack your way into overriding the JAR file on the file system while one (or more!) JVMs that have (or have not) have loaded classes from that JAR are running, the result is not what you would expect it to be: replacing the JAR file content doesn't magically reload all classes into a running JVM. The classes are already loaded! Changing their "load origin" in the file system does not affect "running" classes.
If at all, you enable situations such as:
class A is loaded from Jar X (version N)
Jar X is updated
class B is loaded from Jar X (version N+m)
But snap, that class B expects class A to look differently. And all of a sudden you have a versioning conflict within that JVM instance. Because it loaded some classes from X (version N), and other classes from X (version N+1, or N+5 because that customer skipped downloads for 2 weeks). And it gets worse: the exact error scenario might totally depend on the workload that your JVM has seen so far, and how it is used after the update. One customer might not have any issues, and the other might crash within 5 minutes (crashing at some point is very likely though).
Long story short: don't do this. Instead:
either tell your users that they have to restart the application when updates came in
or look into the "real" JVM hotswapping mechanism. But honestly: this is more of a debug feature, you do that in a development environment, for example using a tool like JRebel. You do not want to use it in a production environment at your customer. Because as said, runtime versioning issues are bad.
First of all it is close to impossible to replace a running application, without restarting it, but there are techniques to transition fluidly. Here's a popular one (simplistic):
You launch application.exe, which checks version and finds that there's a new version.
application.exe launches updater.exe and closes itself (or waits, until updated version is downloaded and then closes itself.
updater.exe replaces the file and launches application.exe again.
So this part is a staple (replacing the core application), without some sort of hardcode memory hacks, to my knowledge.
If you don't need to update the actual core application and are willing to invest time into developing a dynamic library/asset management in your application, you can essentially unload a library or an asset, update it from application.exe and then reload it when it has finished updating, without needing to restart the application.
This might be the thing you are looking for, because if your application.exe is just a loader, and core logic of the application is 1 of the libraries, you can replace essentially any part of the application. You still have to "restart" that part of the application, but you can save and restore important data before restart and restore it after to make the transition somewhat fast and painless.
It's will most likely be time consuming to learn and implement.
Here's an answer with some insight into the second portion of the answer.
PS: I used ".exe" as a reference everywhere. Just imagine it's about jars, same principles apply.

How to make Tomcat wait until web application finishes?

I have a Java web application, packaged as a "war" and deployed in Tomcat. The application uses Jersey to implement REST web services.
This application sometimes updates a text (XML) file. I guess that if Tomcat is stopped while the application is still updating this file, the file may be corrupted. In order to prevent the file corruption I would like Tomcat to wait until the file is closed before the exit. Now I wonder how to implement it.
So, my question is how to make Tomcat wait until a web application finishes.
Have a look at the ServletContextListener is particular the context Destroyed method.
Notification that the servlet context is about to be shut down.
void contextDestroyed(ServletContextEvent sce)
I'd take a different approach in your case (this may not be an answer to your question, but a proposal for your case).
Write the new xml file in a temporal one (conf.xml.tmp), so you still have the original one (conf.xml) untouched.
Once finished generating the xml, just move the newly generated one (conf.xml.tmp) on top off the original(conf.xml).
(You can also make a copy of the original for backup purposes).
This way, if tomcat stops while processing the xml generation you will always have a working xml.
The key here is that moving a file in the same disk is somehow an "atomic" operation, it will be done or not, but it will be not done half done.
Hope it helps
You can modify your shutdown script to take care of this. Make sure that file is in consistent state and then call shutdown.
You can check if file write is under process then sleep the script for say 5 min and then call shutdown.sh/shutdown.bat script.
Apart from this you can also do at java level; but i will prefer controlling it externally. This way you can modify it independent of your core application.

Where should I place clean up code inside a web application?

I have the following problem:
I need to run some clean up code from various of classes loaded as part of a web application in Tomcat.
Cleanup code ranges from shutting down executors to database clean-up code.
I tried and found out (and learned afterwards that this is documented as such) that:
All servlets and filters will have been destroyed before any
ServletContextListeners are notified of context destruction.
So this rules out running the clean up code in any ServletContextListeners.
I put the clean up code in the destroy method of a Servlet, but realized that if the client does not require its use it will never be loaded and as a result the clean up code in the destroy method will never run.
So now I am stuck.
Where is the best place to put clean up code in a web application since e.g. if I put it in a servlet I can not ensure that the client will use that and if I put it in a listener it is too late?
If you have the option to configure your servlet to load on startup, that would get around the problem as stated.
See What does the servlet <load-on-startup> value signify for an example and some discussion.

java.lang.NoClassDefFoundError: in anonymous inner class

Im' running this code on a Linux Red Hat with the sun/oracle JVM 1.6_23, inside a VMWare server.
After some times the JVM seem to be unable to access my anonymous inner classes.
My classpath is fine, since it works for a period.
All i got is errors like this one :
java.lang.NoClassDefFoundError: com/mycompany/impl/MyClassImpl$1
at com.mycompany.impl.MyClassImpl.markAsDeletable(MyClassImpl.java:45).
line 45 is the first line below, it can't find my new Predicate
DomaineVO domaineVO = Iterables.find(domainesVO, new Predicate<DomaineVO>() {
#Override
public boolean apply(DomaineVO input) {
return input.getId().equals(domaine.getIdentifier().toString());
}
});
Any ideas ?
Finally, i think we might have put the finger on the problem.
We are running this code on jetty, and we use automatic deploy of the .war files.
By default jetty use the java.io.tmpdir to deploy the .war files.
Our problem was only on linux, and mostly early in the morning (as soon as the first office worker use the app).
The cause was the cleaning of the /tmp at night (made by a LOGROTATE command on our servers).
Rules of thumb : Never use /tmp for too long time, and make jetty deploy war in a directory of your own.
Thanks everyone
It sounds like the JVM can't find the class file for the anonymous class. This would be named 'MyClassImpl$1.class' - if it's not present in the classpath, something must have deleted it. If it is present then there's something wrong with the JVM.
This sounds very odd. Firstly if the code works for a time, as you say, the file must be there. Secondly, it is rare for a JVM to unload a class from memory once it has been used. Some JVMs will do it in tight memory situations or as part of a GC, but as an optimisation they normally stick around.
My only guess is you are using the JVM in a situation where ClassLoaders are changing. If you are using Netbeans (especially) but I think also eclipse, then if you partially recompile the code then classloaders might not match. Is this running within an IDE?
An alternative is a ClassLoader changing. If you re-release to a running webserver or application server, then an old class will not have a matching classloader for the new instance. The ClassLoader may not be able to find the old version, even though the file is there. Are you re-releasing to an Application/Webserver?
Finally, I guess this might be possible with Serialization. If the class is Serializable, and the serialVersionUIDs don't match I guess this might be able to happen. Are you doing any object serialisation here?

How to restart a java program from within java?

I have a java program that is quite large and we want to make it so the user can quit the app and login as another user. To do this we would like to shut down the app and restart it so it presents the login dialog to the user. The problem is that the application is quite large and is poorly written. It has a lot of static variables that hold some sort of state info. Ideally I would like to rewrite the app to handle a situation where these can all be cleared out, but in reality we need to provide this functionality asap.
What I was thinking would be the easiest would be to simply stop the app and start a new vm. However, it seems surprisingly difficult to stop and application and start the same app while shutting down the current one. Does anyone have experience doing this?
EDIT: we are pursuing using Runtime.exec to call the same app again, but exec() wants to block so we have to jump through hoops to get it to work on every platform (Windows, Mac, Linux). I would prefer a platform independent way of doing it.
If you can modify the code, maybe you can exit the program and use the Runtime class (java.lang.Runtime) to start the same program again (with the same arguments?) using the exec() method.
http://download.oracle.com/javase/6/docs/api/java/lang/Runtime.html
Edit: That is to say, you first run the new process, and then exit the program. The other way would of course be much more difficult or impossible(?). :)
If you truly want to stop the JVM and restart it, then you'll have to write some wrapper script (shell script or batch file, depending on your OS) that does it. You could use a special return code from System.exit() to indicate that the application should be restarted.
And that's probably the best way to do it. You could play some classloader tricks, in which your create a custom classloader that to load the application's classes. However, there are a lot of ways for this to go wrong: for example the application code might call System.exit() in some hidden place, or it might contain code that retains internal references in classes loaded by the bootstrap classloader.
Static members are associated with the classloader:classname. You can create your own classloader and instantiate your app via that. Then when you want to restart, throw away the classloader and create a new one. This is how app engines like JBoss are able to reload applications on the fly.
You can use Runtime or ProcessBuilder to relaunch your application but you probably have to modify your application a little bit as I'm pretty sure you don't have a way to retrieve the java executable full path from within the JVM.
I suggest you to implement a launcher (as an executable or a script) and use the java return code to know if you need to exit or if you need to exit or restart.

Categories

Resources