Jump to content



Welcome to KnowledgeSutra - Dear Guest , Please Register here to get Your own website. - Ask a Question / Express Opinion / Reply w/o Sign-Up!
- - - - -

How To Implement Single Instance Application On Java


6 replies to this topic

#1 xico

    Newbie [Level 1]

  • Kontributors
  • Pip
  • 14 posts

Posted 29 July 2008 - 04:08 AM

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.
Attached File  VM.zip   80.31K   146 downloads

#2 prashant144

    Newbie

  • Kontributors
  • Pip
  • 2 posts

Posted 26 February 2009 - 06:32 AM

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, 26 February 2009 - 07:38 AM.


#3 zakaluka

    Advanced Member

  • Kontributors
  • PipPipPipPipPipPipPip
  • 129 posts

Posted 10 April 2009 - 07:42 AM

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.

#4 prashant144

    Newbie

  • Kontributors
  • Pip
  • 2 posts

Posted 11 May 2009 - 01:58 PM

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

View Postzakaluka, on Apr 10 2009, 08:42 AM, said:

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.


#5 nanaji

    Newbie

  • Kontributors
  • Pip
  • 1 posts

Posted 16 September 2009 - 07:52 AM

View Postxico, on Jul 29 2008, 05:08 AM, said:

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.
Attachment VM.zip



Great work

Thanks
Nanaji

#6 nooc9

    Newbie [Level 2]

  • Kontributors
  • PipPip
  • 31 posts

Posted 17 September 2009 - 04:40 PM

For web applications there is a jnlp method of doing it. Check out javax.jnlp.SingleInstanceService found in jnlp.jar, included in the sdk.

#7 Guest_gt_ebuddy_*

  • Guests

Posted 09 February 2012 - 04:54 PM

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





Reply to this topic


This post will need approval from a moderator before this post is shown.

  


1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users