Recently I started processing command-line arguments in one of my Java Swing applications (Xadrian) so the application can load files directly on startup. This allows connecting the application with some mime-type or file extension and load files into the application by double-clicking the files. But unfortunately this isn't really usable because everytime a new instance of the application is launched by the operating system. So I searched for some technique to prevent this and found two articles: The first one explains how to use a lock file to prevent a second application instance while the second one explains how to use a local server socket to do the same.
But both solutions are not enough for what I want to do. When I double-click some data file and the operating system tries to open this file with a second instance of the application then I want the data file to be opened with the first instance instead. So the second instance must give the command line arguments to the first instance.
I haven't found a library which already does this so I had to write my own library.
My requirements are:
- Must work correctly even when the JVM crashes.
- Must not conflict with other applications.
- Second instance must give command-line arguments to the first instance.
- First instance must decide if second instance is allowed to run or not.
My solution basically works like the socket server solution mentioned above but I'm using a random port number (To prevent conflicts with other applications) and a two-way communication between server and client. Here is a flow chart which explains how it works:
So the first instance searches for a free port number and starts a server socket on it. The port number is written to the preferences (java.util.prefs). When a client connects then the server sends the application ID (the fully qualified name of the application's main class) and waits for the list of arguments from the client. These arguments are fed to some event handlers which can process the arguments and decide whether the client is allowed to be started, too, or if it must exit. This decision is sent back to the client.
The second instance looks for the port number in the preferences. If there is none or if there is no server listening on the port then this is actually the first instance. If the first line read from the server is not the correct app id then also assume we are the first instance because there is some other application using the port. If the app id is correct then the command-line arguments are sent to the server and the response is read from it. Depending on this response the new application instance starts or exits.
That's it. You can find the finished library here.