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.
Related
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.
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.
I want to access a log file that is locked by a third party Java application. The file is locked for the whole day and will be released the next day. However, my objective is to read it now using RandomAccessFile (must use this class because I need to start/store the last position while reading) without waiting until tomorrow.
Currently, I can read the log only if I unlock it with a file Unlocker software. Can anyone suggest any jar/utilities that I can use in my Java program to meet my objective?
Assuming you're using a Microsoft operating system:
The software Shadow Copy is using using Microsoft's volume-shadow-service (VSS) to copy locked files.
You could use the software from within the Java Runtime Environment or perhaps make use of the VSS-API yourself via Java Native Interface.
My approach would be to shadow-copy the file and then access the content through it's copy. The downside is that you're possibly reading outdated information if the file has been updated since your copy operation.
However, this is just a guess as I'm not familiar with this topic.
You can lock/unlock files and folders in Java but only by application that locked them (you programmed). However there is no Java method/class which can unlock file used by other process.
You should bundle your application with another (native) software. For example you could create shell script for Linux systems and execute it. In Java application detect in which OS it is running so you can execute proper script/software.
When application requires RW lock, system must ensure that no one else have rights to modify it, thats why you need to kill process that is using it.
If you have access to source code of that 3rd party Java application (that is actually locking file you need), then you could implement server side which will listen requests for unlocking file and approval for locking it back again.
By my opinion better approach would be to transfer file by that application to yours, then do what you want and 3rd party app can run without interruption (shouldn't be noticeable). If you need to modify it, then 3rd should wait, your modifies and send back an updated version, 3rd continue to work.
I don't see any reliable tool to do such job, my first mind is to try to avoid the lock while exposing the file as a service through any servlet or any other mechanism. The servlet reads the file once then deliver its contents as plain text (or stream)... No more lock contention
HTH
Jerome
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.
This question already has an answer here:
Using special auto start servlet to initialize on startup and share application data
(1 answer)
Closed 7 years ago.
We have a few war files deployed inside an ear file. Some of the war files have a class that caches static data from our PLM system in singletons. Since some of the classes take several minutes to load we use the load-on-startup in the web.xml to load them ahead of time. This all works fine until we attempt to re-deploy the application on our production servers. (WebLogic 10.3) We get an exception from our PLM API about a dll already being loaded. Our PLM vendor has confirmed that this is a problem and stated that they don't support using the load-on-startup. This is also a huge problem on our development boxes where we have redeploy the app all the time. Most of us, when we're not working on one of the apps that uses a cache, have them commented out. Obviously we can't do that for the production servers. Right now we transfer the ear to the production server, deploy it in the console, wait for it to crash, shut the app server instance down and then start it up again.
We need to find a way around this...
One suggestion was to create a servlet that we can call after the server boots that will load the various caches. While this will work I'm looking for something a bit cleaner. Is there anyway to detect once the server started and then fire off the methods?
Thanks.
We had a similar problem with a third party JDBC driver that loaded a native DLL. When redeploying the app the driver would crash saying the DLL was already loaded. The solution (if one can call it that) was to move the driver from deploy into lib. This way the driver was global to the app server and didn't need to be reloaded when the app was redeployed.
What about using a servlet container lifecycle listener, such as ServletContextListener?
Example on how to use.
EDIT: Sorry, after re-reading your question I don't think this will work. You want something that will load only once per server life, not application life. The ServletContextListener's methods will be called each time the app is deployed, just like a load-on-startup servlet (which it seems you are using). My suggestion will do the exact same thing in a different way.
I would try Chris Nava's suggestion.
EDIT2: It looks like tomcat has some lifecycle listener(s) available to it also. It looks like documentation is sparse, but this potentially would allow you to do something on server startup specifically only once.
EDIT3: Yes, a tomcat lifecycle listener is the way to go. This link explains pretty well how to set one up. Should be fairly straight forward. If you ignore the part about adding the Transaction to tomcat, it goes over pretty thoroughly how to add a lifecycle listener.