Java - How to replace a running jar file - java

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.

Related

Library does not find its own "sublibrary"

I'm trying to make an addresslist in Java, which saves its contents in a Sqlite database.
Therefor (and for other future uses), I tried to create my own library for all kinds of database connections ("PentagonsDatabaseConnector-1.0.jar"). It currently supports Sqlite and MySql.
It references other libraries for them to provide the JDBC-drivers ("mysql-connector-java-8.0.16.jar" and "sqlite-jdbc-3.30.1.jar").
Problem: My Library works just fine if I'm accessing it from its own project folder, but as soon as I compile it and add it to the "Adressliste"-project, it isn't able to find the JDBC-drivers anymore (I can access the rest of my self-written library without problems though). Also, as shown in the screenshot, "PentagonsDatabaseConnector-1.0.jar" brings the JDBC-libraries with itself in "lib"-folder.
LINK TO THE SCREENSHOT
Do you guys have an idea whats wrong?
Thank you for your help!
Ps: Sorry for bad English, I'm German :)
Java cannot read jars-in-jars.
Dependencies come in a few flavours. In this case, PentagonsDC is a normal dependency; it must be there at runtime, and also be there at compile time.
The JDBC libraries are a bit special; they are runtime-only deps. You don't need them to be around at compile time. You want this, because JDBC libraries are, as a concept, pluggable.
Okay, so what do I do?
Use a build system to manage your dependencies is the answer 90%+ of java programmers go to, and what I recommend you do here. Particularly for someone starting out, I advise Maven. Here you'd just put in a text file the names of your dependencies and maven just takes care of it, at least at compile time.
For the runtime aspect, you have a few options. It depends on how your java app runs.
Some examples:
Manifest-based classpaths
You run your java application 'stand alone', as in, you wrote the psv main(String[]) method that starts the app and you distribute it everywhere it needs to run. In this case, the usual strategy is to have an installer (you need a JVM on the client to run your application and neither oracle nor any OS vendor supports maintaining a functioning JVM on end-user's systems anymore; it is now your job – this is unfortunately non-trivial), and given that you have that, you should deploy your jars such that they contain in the manifest (jars are zips, the manifest ends up at META-INF/MANIFEST.MF):
Main-Class: com.of.yourproj.Main
Class-Path: lib/sqlite-jdbc.jar lib/mysql-jdbc.jar lib/guava.jar
And then have a directory stucture like so:
C:\Program Files\yourapp\yourapp.jar
C:\Program Files\yourapp\lib\sqlite-jdbc.jar
C:\Program Files\yourapp\lib\mysql-jdbc.jar
Or the equivalent on any other OS. The classpath entries in the manifest are space separated and resolved relative to the dir that 'yourapp.jar' is in. Done this way, you can run yourapp.jar from anywhere and it along with all entries listed in Class-Path are now available to it.
Build tools can make this manifest for you.
Shading / Uberjars
Shading is the notion of packing everything into a single giant jar; not jars-in-jars, but unpack the contents of your dependency jars into the main app jar. This can be quite slow in the build (if you have a few hundred MB worth of deps, those need to be packed in and all class files need analysis for the shade rewrite, that's a lot of bits to process, so it always takes some time). The general idea behind shading is that deployment 'is as simple as transferring one jar file', but this is not actually practical, given that you can no longer assume that end users have a JVM installed, and even if they do, you cannot rely on it being properly up to date. I mention it here because you may hear this from others, but I wouldn't recommend it.
If you really do want to go for this, the only option is build systems: They have a plugin to do it; there is no command line tool that ships with java itself that can do this. There are also caveats about so-called 'signed jars' which cannot just be unpacked into a single uberjar.
App container
Not all java apps are standalone where you provide the main. If you're writing a web service, for example, you have no main at all; the framework does. Instead of a single entrypoint ('main' - the place where your code initially begins execution), web services have tons of entrypoints: One for every URL you want to respond to. The framework takes care of invoking them, and usually these frameworks have their own documentation and specs for how dependencies are loaded. Usually it is a matter of putting a jar in one place and its dependencies in a subdir named 'lib', or you build a so-called war file, but, really, so many web frameworks and so many options on how they do this. The good news is, usually its simple and the tutorial of said framework will cover it.
This advice applies to any 'app container' system; those are usually web frameworks, but there are non-web related frameworks that take care of launching your app.
Don't do these
Don't force your users to manually supply the -classpath option or mess with the CLASSPATH environment variable.
Don't try to write a custom classloader that loads jars-in-jars.
NB: Sqlite2 is rather complicated for java; it's not getting you many of the benefits that the 'lite' is supposed to bring you, as it is a native dependency. The simple, works everywhere solution in the java sphere is 'h2', which is written in all java, thus shipping the entire h2 engine as part of the java app is possible with zero native components.

Is it possible in Tomcat/Java EE server to deploy app in RAM memory, to speed up development?

Even if we enable "deploy on save" with our IDE, we still need to wait some time to propagate changes. This can be annoying espacially when we deploy small changes.
So, is it possible to run some servlet container in-memory with IDE-compatible deployment to speed up deployment and development time? Or even run whole container in-memory with server dependencies (JSP compilator etc.).
(I know that I can install Tomcat on RAMDisk, but looking for "more native" solution)
According from their site
JRebel is a JVM-plugin that makes it possible for Java developers to instantly see any code change made to an app without redeploying. JRebel lets you see code changes instantly, versioning classes and resources individually and updating one at a time instead of as a lump application redeploy. When developers make a change to any class or resource in their IDE, the change is immediately reflected in the deployed application, skipping the build and redeploy phases and preventing an average of 5.25 work weeks per year in redeploys!
http://zeroturnaround.com/software/jrebel/
The first thing you can do is to set the deployment path to your webapps directory. This way you deploy the application "exploded" without copying the whole app to another deployment directory. Make sure to let the classes be compiled into the WEB-INF/classes directory.
A second, more problematic thing is, the class loader. When the JVM runs in debug mode, some code changes made within methods will be recognized by the class loader and you would see the changes immediately. But some changes, like method signature and structural class changes will not be detected, so a restart of the JVM will be necessary. You can provide a self brewed class loader which will be able to reload anything when the underlying class files changes.
The tomcat container is loaded in memory when you start it. And tomcat loads all the applications available in webapps directory. Later as and when application classes are required are loaded. And application may load some other resources as required.
If you open the task manager on windows or similar thing on other OS, you can see that tomcat java process is always runnning once started. You may also check its current memory footprint . So it is not unloaded and re-loaded on demand.

Updating a Jar in production

I have a Swing/Java application that is being used for clients and has weekly updates.
The problem is the setup just lay out the classes and their respective directories and on the update I just update the classes.
I want to do a single jar containing all the classes, but I'm not sure how would I be able to update it...
Also some clients need some updates during the week where only one or two classes would be updated.
What is the right way of doing this ?
Im using Eclipse.
EDIT: I know how to create the jar, I just dont know how to dynamically update it.
I would suggest you look into Java WebStart which is designed to do exactly what you need.
You need to first create the finished deployment and then you can look into creating a JNLP file for the deployment, and a way to put all the files to a web server for the user to access. For now just let the user download the whole thing every time you update. When you get more experienced you can look into how you can make incremental updates.
I would strongly recommend including a build number or timestamp in the deployment paths so a jar file is not cached incorrectly in the client by accident.
The general way of doing this, even if only small changes were made, would be to repackage your JAR after each update and give that JAR to a user. The user would replace the existing JAR. How you produce your JAR is up to you. Many IDEs support it, you could write a shell script, use existing build systems like ant or maven or even make, whatever. (See edit below)
If your JAR is very large and deployment is cumbersome, you may be able to split your project into smaller subcomponents, each with their own JAR, and only redistribute the ones containing changes. That may or may not be a major refactoring for you, and it might not even be appropriate. For most small or average size projects, this is generally unnecessary.
As for deployment, there are also a zillion ways to make that easier on the user. You could just give them a JAR file. You could use e.g. install4j. You could use Java Web Start (although its kind of clunky). There are others.
Both install4j and JWS support automatically checking for updates. If you choose to support that feature, all you would need to do is update your distribution site, and users would receive updates automatically. That's also up to you.
But a short answer to your question is: If you have all of your classes packaged in a JAR, no matter how many classes change, you'll want to give the entire updated JAR to the user. The benefit that counters this cost is that a JAR is a nice, compressed, self-contained collection of your application/library's source, which makes management and deployment very convenient.
Edit: Responding to your edit where you specify that you are using Eclipse, Josh M gives you instructions in his comment on your answer. To add to his comment, to export a Runnable Jar you'll have to have a Run Configuration set up which, if you've been running your application in Eclipse already, you probably already have. If not you can create one in the Run menu.
Edit 2: Please refer to Thorbjørn Ravn Andersen's answer as well for some good JWS tips.

How to inject compile classes in existing jar?

I need to patch a system in production however I have already change the main trunck in CVS. Since there are a lot of changes I do not want to revert the code to a previous version as there is only one class involve.
Could this be done ?
Stop the application.
Safely replace a edited *.class into an existing jar.
Re-start the application.
Many Thanks
Unless the jars are signed by someone else, it can be done. Jar files are just zip files after all, you unzip them, replace the file and zip them up again. If the jars are signed and you have the key, you have to sign the new jar again. (The jar command is the preferred way to do this.)
However it's very bad practice to do this. Trust me, the amount of work you save now will be lost a hundredfold if this way of deploying becomes a habit. Unless there's a real crisis (your application doesn't even run or crashes every ten minutes for example), you should never ever do this.
If you use CVS, you should always tag your releases, but even if you haven't done that, you can check out the trunk as it was on the release date, create a branch from there, apply the change to the branch and rebuild your application.
It takes about ten minutes (plus compilation time) and it's a safe and proper method. You can launch the patched application in your test environment, test that it works and only deploy it afterwards.
Dropping a pre-compiled class file in an existing application can break the code in subtle ways that don't become apparent until several days later. Recompiling and retesting the application takes this risk away, leaving just the much smaller risk associated with any code change.
Yes, you very well can. make sure your new class compiles fine and then update the jar. jar -u is what you're looking for.

How to move only the current file with Eclipse and/or Ant?

I am working on a small team of web application developers. We edit JSPs in Eclipse on our own machines and then move them over to a shared application server to test the changes. I have an Ant script that will take ALL the JSPs on my machine and move them over to the application server, but will only overwrite JSPs if the ones on my machine are "newer". This works well most of the time, but not all of the time. Our update method doesn't preserve file change day/times, so it is possible that an Update on my machine will set the file day/time to now instead of when the file was actually last changed. If someone else worked on that file 1 hour ago (but hasn't committed the changes yet), then the older file on my PC will actually have a newer date. So when I run the Ant script it will overwrite their changes with an older file.
What I am looking for is an easy way to just move the file I am currently working on. Is there a way to specify the "current" file in an Ant script? Or an easy way to move the current file within Eclipse? Perhaps a good plugin to do this kind of stuff? I could go out to Windows Explorer to separately move the file, but I would much prefer to be able to do it from within Eclipse.
Add a target to your ant build file to copy a single jsp using a command line property definition as #matt b described.
Create a new external tool launch profile and use the "String Substitution Preferences" to pass in the reference to the active file in the editor (resource_name).
See Eclipse Help | Java Development User Guide | Reference | Preferences | Run/Debug | Launching | String Substitution
How would Ant know what file was "current"? It has no way of knowing.
You could pass the name of the file into your Ant script (by taking advantage of the fact that any arguments you pass into Ant with -D are automatically parameters in your script)...
ant -Dfile=myfile.jsp update
and have your script look something like...
<copy file=${myfile} todir="blah"/>
...but it would probably be a pain to constantly type in the name of the file on the commandline.
Honestly, the type of problem you've described are inevitable when you have multiple developers sharing an environment. I think that a better approach for you and your team long-term is to have each developer work/test on a local application server instance, before the code is promoted. This removes all headaches, bottlenecks, and scheduling trouble in sharing an app server with other people.
You should really use source control any time you have multiple people working on the same thing (well, you should use it any time regardless, but that's a different conversation). This way, when conflicts like this occur, the tool will know and make someone perform the merge so that no one's changes get lost. Then, the test server can run on a clean checkout from source, and each developer can also test the full application locally, because everyone's changes will be instantly available to them through the source repository.
I suggest you to use source control. I prefer Subversion. You can use CruiseControl to make the build automatically whenever someone commits new code.
The antrunner4e plugin is exactly what you are looking for -- see http://sourceforge.net/projects/antrunner4e/

Categories

Resources