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.
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.
We are using Tomcat to deploy our Vaadin-Application. No problems there.
What we would like to do, though, is to execute java-code without redeploying our application. For example: we would like to give the end-user the possibility to add code to our program. So every time a button is pressed the end-user code gets executed as well. (e.g. add extra logging functionality, inform a different user via mail….).
It would also be fine, if the end-user could only use certain classes/methods. e.g.:
this.sendMail(“abc#yxz.com”)
Is this possible? I would appreciate it if anyone could give me a starting point where to look.
Thanks in advance,
Stephanie
I would have a look at BeanShell. This is used in a number of IDEs to add code in running programs.
I've been searching for days but I have not found a clear answer. How would I go about writing a small jar file to give to my users that simply gets a jar file from a URL (with multiple classes in it) and run it. It would be great if the end user never actually has the jar on his computer at anytime. I am doing this as a small security measure.
If the user is going to execute your code, it must exist on their computer. It's just the way it works.
If you wanted to re-write your code to perform most of the work on your servers, that'd be one mechanism to combat piracy, but it does mean that you need to duplicate all the input verification checks: perform them once on the client side, for reasonable response time, and again on your own servers, to ensure that your users aren't trying to use your services improperly.
Another mechanism would be to run a VNC server on your servers, and ask your users to VNC in. The software executes completely on your servers. It is a draconian step though, one your users will likely detest.
I am not sure how you'd go about it, but I know that using Maven allows you to access things without having the jar locally. You can just specify the URL. So maybe look into how they do their repositories.
Another option would be to encrypt your JAR file and write a custom class loader that decrypts it on the fly on client machines. This won't prevent a power user from attaching a debugger to the JVM and examining your byte code, but it prevents the typical user from having access to your code.
I made up an applet to auto dial a contacts number via our phone system switchvox, as well as log the call information into our CRM, salesforce. The issue I am running into is that unless I use the separate JVM parameter things get screwy.
For example say they have multiple tabs open for multiple contacts, thus multiple applets running in the same jvm. Without the separate jvm parameter sometimes it will dial a number from another tab. I pass the number via the parameter tags and I have even tried passing the number by calling a JS method from the applet with still no luck.
Since our crm is cloud based people like to have multiple tabs open, but do not like seeing multiple java icons down below, go figure. Anybody have this issue before, and/or have a workaround without the separate jvms.
It is hard to say without looking at your applet's code.
But I would hazard a guess that your code is putting some of its mutable state in statics, and occasionally one instance of the applet is interfering with another via the statics.
If you have any shared mutable statics in your applet, ideally you should get rid of them. Or if the state really needs to be shared by multiple instances of the applet, make sure that all accesses are properly synchronized.
Statics are shared among the applets since they're all running in the same VM. You could try the classloader_cache="false" applet option and still share the VM. I am not sure whether this option applies only on applet startup, however, as I haven't had success with it working all the time.
The best bet is to get rid of statics or use separate_jvm.
I have a small test class that I want to run on a particular jvm that's already up and running (basically it's an web application running on Tomcat) . The reason I want to do this is I want to execute a small test class (with the main method and all) within that jvm so that I get the same environment (loaded and initialized classes) for my test class.
Is it possible to indicate that ,say through a jvm parameter, that it should not initialize a new vm to execute my class but instead go and execute on the remote vm and show me the result here, on my console. So the local jvm acts as a kind of thin proxy ?
I am not aware in case there are some tools that should make this possible .Also heard somewhere that java 6 jvm comes with an option like this , is that true ?
Please help me.
Thanks,
After reading this question and the answers, I decided to roll my own little utility: remoteJunit
It is lightweight and dynamically loads classes from the client to the server JVM. It uses HTTP for communication.
You might want to take a look at btrace. It allows you to run code in an already started JVM provided you don't change the state of the variables inside that JVM. With this kind of tracing, you might be able solve your problem in a different way. Not by running extra code in form of a new class but by adding safe code to and existing class running inside a JVM.
For instance, you might System.out.println the name of the file when there is a call to File.exists.
You might find JMX useful. Register an MBean in the server process. Invoke it with visualvm (or jconsole). (tutorial) Never tried it myself, mind.
RMI would also do the magic.
http://java.sun.com/javase/6/docs/technotes/guides/rmi/index.html
Make your web application start an RMI registry and register your service
beans there.
Then in other JVM you can run a program that queries the RMI registry
started by your web application for the services you want to verify
and you are done.
I assume "small test class" is basically some debugging code you want to run to monitor your real application, which is deployed remotely on a Tomcat. If this is the case, you should connect your Eclipse debugger remotely to the Tomcat instance, so you can set a breakpoint at interesting locations and then use the Display view of Eclipse to run any arbitrary code you might need to perform advanced debugging code. As java supports Hot Code Replacement using the debug mechanism, you can also change existing code on the remote side with new code at runtime.