Jump to content
xisto Community
xico

How To Implement Single Instance Application On Java

Recommended Posts

See the next few lines containing Java Code:

1. // imports   2. import sun.management.ConnectorAddressLink;     3. import sun.jvmstat.monitor.HostIdentifier;     4. import sun.jvmstat.monitor.Monitor;     5. import sun.jvmstat.monitor.MonitoredHost;     6. import sun.jvmstat.monitor.MonitoredVm;     7. import sun.jvmstat.monitor.MonitoredVmUtil;     8. import sun.jvmstat.monitor.MonitorException;     9. import sun.jvmstat.monitor.VmIdentifier;    10.     11. public static void main(String args[]) {    12.		 /* The method ManagementFactory.getRuntimeMXBean() returns an identifier with applcation PID  13.			 in the Sun JVM, but each jvm may have you own implementation.   14.			 So in anothers jvm, other than Sun, this code may not work., :(   15.		 */    16.		 RuntimeMXBean rt = ManagementFactory.getRuntimeMXBean();    17.		 final int runtimePid = Integer.parseInt(rt.getName().substring(0,rt.getName().indexOf("@")));    18.								   19.		 java.awt.EventQueue.invokeLater(new Runnable() {    20.			 public void run() {    21.				     22.				 // If exists another instance, show message and terminates the current instance.    23.				 // Otherwise starts application.    24.				 if (getMonitoredVMs(runtimePid))    25.				 {    26.					 new MainFrame().setVisible(true);    27.				 } else    28.					 JOptionPane.showMessageDialog(null,"There is another instance of this application running.");    29.				     30.			 }    31.		 });    32. }


This code above shows us how to implement a single instance application. But let me explain it.

The getMonitoredVMs(int processPid) method receives as paramter the current application PID, and catch the application name that is called from command line, for example, the application was started from c:\java\app\test.jar path, then the value variable is "c:\\java\\app\\teste.jar". This way, we will catch just application name on the line 17 of the code below.
After that, we search JVM for antoher process with the same name, if we found it and the application PID is different, it means that is the second application instance.

1. private static boolean getMonitoredVMs(int processPid) {     2.		 MonitoredHost host;     3.		 Set vms;     4.		 try {     5.			 host = MonitoredHost.getMonitoredHost(new HostIdentifier((String)null));     6.			 vms = host.activeVms();     7.		 } catch (java.net.URISyntaxException sx) {     8.			 throw new InternalError(sx.getMessage());     9.		 } catch (MonitorException mx) {    10.			 throw new InternalError(mx.getMessage());    11.		 }    12.		 MonitoredVm mvm = null;    13.		 String processName = null;    14.		 try{    15.			 mvm = host.getMonitoredVm(new VmIdentifier(String.valueOf(processPid)));    16.			 processName = MonitoredVmUtil.commandLine(mvm);    17.			 processName = processName.substring(processName.lastIndexOf("\\") + 1,processName.length());    18.			 mvm.detach();    19.		 } catch (Exception ex) {    20.			     21.		 }    22.		// This line is just to verify the process name. It can be removed.   23.		 JOptionPane.showMessageDialog(null,processName);    24.		 for (Object vmid: vms) {    25.			 if (vmid instanceof Integer) {    26.				 int pid = ((Integer) vmid).intValue();    27.				 String name = vmid.toString(); // default to pid if name not available    28.				 try {    29.					  mvm = host.getMonitoredVm(new VmIdentifier(name));    30.					  // use the command line as the display name    31.					  name =  MonitoredVmUtil.commandLine(mvm);    32.					  name = name.substring(name.lastIndexOf("\\")+1,name.length());    33.					  mvm.detach();    34.					  if ((name.equalsIgnoreCase(processName)) && (processPid != pid))    35.						  return false;    36.				 } catch (Exception x) {    37.					  // ignore    38.				 }    39.			 }    40.		 }    41.		     42.		 return true;    43. }
The problem of all this code are the imports, that are defined only in the file tools.jar file and has a size of 11MB. But to solve this problem, I have unpacked this file and a packed a new file called VM.ZIP only with the necessary classes, and it has a size of just 81kb.

PS: When you're debbuging the code, the processName variable will be assigned to Class Main project, for example, the name of its class is Principal and is in the package com.main, then the variable processName will be assigned as "com.main.Principal." To test you have to open another instance of Debug and it will work.
In the release case, it will be showed the application name as we can see in the line code JOptionPane.showMessageDialog(null,processName).


Below the file attached VM.zip.
VM.zip

Share this post


Link to post
Share on other sites

Hi,

Its very nice yar.
I also want the same thing but i use some different technique.

1. I make a ServerSocket object and capture a port say 1111
If again on another instance you are trying to make a same object then it
is giving you error because your 1111 port is captured by 1st instance.

So easily you can track and throw a error to user.
Its very simple and effective too.

Just follow the link for all codes.

Single instance aaplicaion in JAVA

2. Another method is make a txt file with one instance and delete while exiting.
On next time just check if file is existing then any instance is running.
And you can track the error.
For being effective do not create file in C partition.

Edited by prashant144 (see edit history)

Share this post


Link to post
Share on other sites

I've used the lock method described by Prashant. The only problem is that the file has to be deleted manually if the application crashes without removing the lock.The benefit is that this technique works on every operating system and platform, with any java toolkit. I had a problem with capturing certain ports on unix, especially with certain firewalls running in the background.Regards,z.

Share this post


Link to post
Share on other sites

Hi Zakuluka,

I am not tested in unix.
If you have problem in capturing port then just make unique port like 99999 something like that
which nobody use.


thanks

I've used the lock method described by Prashant. The only problem is that the file has to be deleted manually if the application crashes without removing the lock.
The benefit is that this technique works on every operating system and platform, with any java toolkit. I had a problem with capturing certain ports on unix, especially with certain firewalls running in the background.

Regards,

z.


Share this post


Link to post
Share on other sites

See the next few lines containing Java Code:

1. // imports   2. import sun.management.ConnectorAddressLink;     3. import sun.jvmstat.monitor.HostIdentifier;     4. import sun.jvmstat.monitor.Monitor;     5. import sun.jvmstat.monitor.MonitoredHost;     6. import sun.jvmstat.monitor.MonitoredVm;     7. import sun.jvmstat.monitor.MonitoredVmUtil;     8. import sun.jvmstat.monitor.MonitorException;     9. import sun.jvmstat.monitor.VmIdentifier;    10.     11. public static void main(String args[]) {    12.		 /* The method ManagementFactory.getRuntimeMXBean() returns an identifier with applcation PID  13.			 in the Sun JVM, but each jvm may have you own implementation.   14.			 So in anothers jvm, other than Sun, this code may not work., :(   15.		 */    16.		 RuntimeMXBean rt = ManagementFactory.getRuntimeMXBean();    17.		 final int runtimePid = Integer.parseInt(rt.getName().substring(0,rt.getName().indexOf("@")));    18.								   19.		 java.awt.EventQueue.invokeLater(new Runnable() {    20.			 public void run() {    21.				     22.				 // If exists another instance, show message and terminates the current instance.    23.				 // Otherwise starts application.    24.				 if (getMonitoredVMs(runtimePid))    25.				 {    26.					 new MainFrame().setVisible(true);    27.				 } else    28.					 JOptionPane.showMessageDialog(null,"There is another instance of this application running.");    29.				     30.			 }    31.		 });    32. }


This code above shows us how to implement a single instance application. But let me explain it.

The getMonitoredVMs(int processPid) method receives as paramter the current application PID, and catch the application name that is called from command line, for example, the application was started from c:\java\app\test.jar path, then the value variable is "c:\\java\\app\\teste.jar". This way, we will catch just application name on the line 17 of the code below.
After that, we search JVM for antoher process with the same name, if we found it and the application PID is different, it means that is the second application instance.

1. private static boolean getMonitoredVMs(int processPid) {     2.		 MonitoredHost host;     3.		 Set vms;     4.		 try {     5.			 host = MonitoredHost.getMonitoredHost(new HostIdentifier((String)null));     6.			 vms = host.activeVms();     7.		 } catch (java.net.URISyntaxException sx) {     8.			 throw new InternalError(sx.getMessage());     9.		 } catch (MonitorException mx) {    10.			 throw new InternalError(mx.getMessage());    11.		 }    12.		 MonitoredVm mvm = null;    13.		 String processName = null;    14.		 try{    15.			 mvm = host.getMonitoredVm(new VmIdentifier(String.valueOf(processPid)));    16.			 processName = MonitoredVmUtil.commandLine(mvm);    17.			 processName = processName.substring(processName.lastIndexOf("\\") + 1,processName.length());    18.			 mvm.detach();    19.		 } catch (Exception ex) {    20.			     21.		 }    22.		// This line is just to verify the process name. It can be removed.   23.		 JOptionPane.showMessageDialog(null,processName);    24.		 for (Object vmid: vms) {    25.			 if (vmid instanceof Integer) {    26.				 int pid = ((Integer) vmid).intValue();    27.				 String name = vmid.toString(); // default to pid if name not available    28.				 try {    29.					  mvm = host.getMonitoredVm(new VmIdentifier(name));    30.					  // use the command line as the display name    31.					  name =  MonitoredVmUtil.commandLine(mvm);    32.					  name = name.substring(name.lastIndexOf("\\")+1,name.length());    33.					  mvm.detach();    34.					  if ((name.equalsIgnoreCase(processName)) && (processPid != pid))    35.						  return false;    36.				 } catch (Exception x) {    37.					  // ignore    38.				 }    39.			 }    40.		 }    41.		     42.		 return true;    43. }
The problem of all this code are the imports, that are defined only in the file tools.jar file and has a size of 11MB. But to solve this problem, I have unpacked this file and a packed a new file called VM.ZIP only with the necessary classes, and it has a size of just 81kb.

PS: When you're debbuging the code, the processName variable will be assigned to Class Main project, for example, the name of its class is Principal and is in the package com.main, then the variable processName will be assigned as "com.main.Principal." To test you have to open another instance of Debug and it will work.
In the release case, it will be showed the application name as we can see in the line code JOptionPane.showMessageDialog(null,processName).


Below the file attached VM.zip.
VM.zip



Great work

Thanks
Nanaji

Share this post


Link to post
Share on other sites

here is full working code for achieving single instance of application in java :

How it works

New instance of application tries to connect to a specific ServerSocket (localhost, port#) to detect running applications. And a running application must have a ServerThread to detect possible run of new instance of the same application

The main Logic in steps

 

Find existing server socket running on localhost

If found(another instance was already running) --> exit current instance of application

else --

 

start a new Server thread to detect run of future applications

and start the application

Share this post


Link to post
Share on other sites

Hey Xico,

 

First of all thanks for the code. I have implemented the same in my app. It's perfectly working for all windows os except windows 7. Can you please help me out in the same.

Share this post


Link to post
Share on other sites

I am facing issues on windows 7. This isn't working. However after installing netbeans it works. Also if I uninstall netbeans it still works. What's this mystery?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...

Important Information

Terms of Use | Privacy Policy | Guidelines | We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.