Closing the Camera Application from a T/P Application - java

My Problem... I have accessed the Camera App from my third party app , I then take a picture. then I go to the Menu and I have added in a menuitem (MENUITEM_CAMERA_PREVIEW) . My menu item must perform a function and once it has I want my app to close the camera and open the previose screen before the Camera app was opened.
I am facing the same problems as this thread :
http://supportforums.blackberry.com/t5/Java-Development/How-to-exit-camera-app-properly/m-p/1924127#M209092
Can someone please tell me they understand the solution, if not and you maybe know the solution your help would be much appreciated.
I have seen these post:
Closing the default camera in Blackberry programatically after taking a picture
http://supportforums.blackberry.com/t5/Java-Development/Unable-to-close-camera-using-EventInjector-for-touch-screen/m-p/785247#M143879
How to exit a blackberry application from another application programatically?
But I am not sure what I am supposed to add to exit the camera application from my third party application.
Can Someone Please help me understand....

Trying to close the Camera app from your app is tricky. I don't know of a clean way to do it, but I have done it this way.
Basically, your app needs to request permission
ApplicationPermissions.PERMISSION_INPUT_SIMULATION
to inject keystrokes. It will then simulate the pressing of the ESC key, which is how a user would/could close the Camera app manually. To make this technique more reliable, I need to have the code (conditionally) inject the ESC key multiple times.
The way I make this more reliable is that I have a Screen in my app that is showing, before I launch the Camera app. I then monitor that screen to see when it has been exposed again. When I detect that it has been exposed, I assume that I must have injected enough ESC key sequences to close the Camera (or I guess the user could have pressed ESC themselves, to get back to my app).
Update: per comment below, here is some additional code I used in this solution, to detect proper Camera closure by monitoring the exposed state of one of my Screens below it:
private boolean _isExposed = false;
protected void onExposed() {
super.onExposed();
_isExposed = true;
}
protected void onObscured() {
super.onObscured();
_isExposed = false;
}
public boolean isExposed() {
return _isExposed;
}
You can also set _isExposed to false in whatever method you use to open the Camera app in the first place, if you like.

This is the code I ended up using, its much better.
public class MyScreen extends MainScreen{
Player _p;
VideoControl _videoControl;
FileConnection fileconn;
String PATH;
String GetfileName;
LabelField GetPhotofileName = new LabelField("",LabelField.FOCUSABLE){
protected boolean navigationClick(int status, int time){
Dialog.alert("Clicked");
return true;
}
};
public static boolean SdcardAvailabulity() {
String root = null;
Enumeration e = FileSystemRegistry.listRoots();
while (e.hasMoreElements()) {
root = (String) e.nextElement();
if( root.equalsIgnoreCase("sdcard/") ) {
return true;
}else if( root.equalsIgnoreCase("store/") ) {
return false;
}
}
class MySDListener implements FileSystemListener {
public void rootChanged(int state, String rootName) {
if( state == ROOT_ADDED ) {
if( rootName.equalsIgnoreCase("sdcard/") ) {
}
} else if( state == ROOT_REMOVED ) {
}
}
}
return true;
}
protected boolean invokeAction(int action){
boolean handled = super.invokeAction(action);
if(SdcardAvailabulity()){
PATH = System.getProperty("fileconn.dir.memorycard.photos")+"Image_"+System.currentTimeMillis()+".jpg";//here "str" having the current Date and Time;
} else {
PATH = System.getProperty("fileconn.dir.photos")+"Image_"+System.currentTimeMillis()+".jpg";
}
if(!handled){
if(action == ACTION_INVOKE){
try{
byte[] rawImage = _videoControl.getSnapshot(null);
fileconn=(FileConnection)Connector.open(PATH);
if(fileconn.exists()){
fileconn.delete();
}
fileconn.create();
OutputStream os=fileconn.openOutputStream();
os.write(rawImage);
GetfileName =fileconn.getName();
fileconn.close();
os.close();
Status.show("Image is Captured",200);
GetPhotofileName.setText(GetfileName);
if(_p!=null)
_p.close();
}catch(Exception e){
if(_p!=null){
_p.close();
}
if(fileconn!=null){
try{
fileconn.close();
}catch (IOException e1){
}
}
}
}
}
return handled;
}
public MyScreen(){
setTitle("Camera App");
try{
_p = javax.microedition.media.Manager.createPlayer("capture://video?encoding=jpeg&width=1024&height=768");
_p.realize();
_videoControl = (VideoControl) _p.getControl("VideoControl");
if (_videoControl != null){
Field videoField = (Field) _videoControl.initDisplayMode (VideoControl.USE_GUI_PRIMITIVE, "net.rim.device.api.ui.Field");
_videoControl.setDisplayFullScreen(true);
_videoControl.setVisible(true);
_p.start();
if(videoField != null){
add(videoField);
}
}
}catch(Exception e){
if(_p!=null) {
_p.close();
}
Dialog.alert(e.toString());
}
add(GetPhotofileName);
}
}

Related

Don't restart my app if already it is open [duplicate]

Sometime I see many application such as msn, windows media player etc that are single instance applications (when user executes while application is running a new application instance will not created).
In C#, I use Mutex class for this but I don't know how to do this in Java.
I use the following method in the main method. This is the simplest, most robust, and least intrusive method I have seen so I thought that I'd share it.
private static boolean lockInstance(final String lockFile) {
try {
final File file = new File(lockFile);
final RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
final FileLock fileLock = randomAccessFile.getChannel().tryLock();
if (fileLock != null) {
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
try {
fileLock.release();
randomAccessFile.close();
file.delete();
} catch (Exception e) {
log.error("Unable to remove lock file: " + lockFile, e);
}
}
});
return true;
}
} catch (Exception e) {
log.error("Unable to create and/or lock file: " + lockFile, e);
}
return false;
}
If I believe this article, by :
having the first instance attempt to open a listening socket on the localhost interface. If it's able to open the socket, it is assumed that this is the first instance of the application to be launched. If not, the assumption is that an instance of this application is already running. The new instance must notify the existing instance that a launch was attempted, then exit. The existing instance takes over after receiving the notification and fires an event to the listener that handles the action.
Note: Ahe mentions in the comment that using InetAddress.getLocalHost() can be tricky:
it does not work as expected in DHCP-environment because address returned depends on whether the computer has network access.
Solution was to open connection with InetAddress.getByAddress(new byte[] {127, 0, 0, 1});
Probably related to bug 4435662.
I also found bug 4665037 which reports than Expected results of getLocalHost: return IP address of machine, vs. Actual results : return 127.0.0.1.
it is surprising to have getLocalHost return 127.0.0.1 on Linux but not on windows.
Or you may use ManagementFactory object. As explained here:
The getMonitoredVMs(int processPid) method receives as parameter 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\\test.jar". This way, we will catch just application name on the line 17 of the code below.
After that, we search JVM for another process with the same name, if we found it and the application PID is different, it means that is the second application instance.
JNLP offers also a SingleInstanceListener
If the app. has a GUI, launch it with JWS and use the SingleInstanceService.
Update
The Java Plug-In (required for both applets and JWS apps) was deprecated by Oracle and removed from the JDK. Browser manufacturers had already removed it from their browsers.
So this answer is defunct. Only leaving it here to warn people looking at old documentation.
You can use JUnique library. It provides support for running single-instance java application and is open-source.
http://www.sauronsoftware.it/projects/junique/
The JUnique library can be used to prevent a user to run at the same
time more instances of the same Java application.
JUnique implements locks and communication channels shared between all
the JVM instances launched by the same user.
public static void main(String[] args) {
String appId = "myapplicationid";
boolean alreadyRunning;
try {
JUnique.acquireLock(appId, new MessageHandler() {
public String handle(String message) {
// A brand new argument received! Handle it!
return null;
}
});
alreadyRunning = false;
} catch (AlreadyLockedException e) {
alreadyRunning = true;
}
if (!alreadyRunning) {
// Start sequence here
} else {
for (int i = 0; i < args.length; i++) {
JUnique.sendMessage(appId, args[0]));
}
}
}
Under the hood, it creates file locks in %USER_DATA%/.junique folder and creates a server socket at random port for each unique appId that allows sending/receiving messages between java applications.
I have found a solution, a bit cartoonish explanation, but still works in most cases. It uses the plain old lock file creating stuff, but in a quite different view:
http://javalandscape.blogspot.com/2008/07/single-instance-from-your-application.html
I think it will be a help to those with a strict firewall setting.
Yes this is a really decent answer for eclipse RCP eclipse single instance application
below is my code
in application.java
if(!isFileshipAlreadyRunning()){
MessageDialog.openError(display.getActiveShell(), "Fileship already running", "Another instance of this application is already running. Exiting.");
return IApplication.EXIT_OK;
}
private static boolean isFileshipAlreadyRunning() {
// socket concept is shown at http://www.rbgrn.net/content/43-java-single-application-instance
// but this one is really great
try {
final File file = new File("FileshipReserved.txt");
final RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
final FileLock fileLock = randomAccessFile.getChannel().tryLock();
if (fileLock != null) {
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
try {
fileLock.release();
randomAccessFile.close();
file.delete();
} catch (Exception e) {
//log.error("Unable to remove lock file: " + lockFile, e);
}
}
});
return true;
}
} catch (Exception e) {
// log.error("Unable to create and/or lock file: " + lockFile, e);
}
return false;
}
We use file locking for this (grab an exclusive lock on a magic file in the user's app data directory), but we are primarily interested in preventing multiple instances from ever running.
If you are trying to have the second instance pass command line args, etc... to the first instance, then using a socket connection on localhost will be killing two birds with one stone. General algorithm:
On launch, try to open listener on port XXXX on localhost
if fail, open a writer to that port on localhost and send the command line args, then shutdown
otherwise, listen on port XXXXX on localhost. When receive command line args, process them as if the app was launched with that command line.
On Windows, you can use launch4j.
A more generic way of limiting the number of instance's on a single machine, or even an entire network, is to use a multicast socket.
Using a multicast socket, enables you to broadcast a message to any amount of instances of your application, some of which can be on physically remote machines across a corporate network.
In this way you can enable many types of configurations, to control things like
One or Many instances per machine
One or Many instances per network (eg controlling installs on a client site)
Java's multicast support is via java.net package with MulticastSocket & DatagramSocket being the main tools.
Note: MulticastSocket's do not guarantee delivery of data packets, so you should use a tool built on top of multicast sockets like JGroups. JGroups does guarantee delivery of all data. It is one single jar file, with a very simple API.
JGroups has been around a while, and has some impressive usages in industry, for example it underpins JBoss's clustering mechanism do broadcast data to all instance of a cluster.
To use JGroups, to limit the number of instances of an app (on a machine or a network, lets say: to the number of licences a customer has bought) is conceptually very simple :
Upon startup of your application, each instance tries to join a named group eg "My Great App Group". You will have configured this group to allow 0, 1 or N members
When the group member count is greater than what you have configured for it.. your app should refuse to start up.
You can open a Memory Mapped File and then see if that file is OPEN already. if it is already open, you can return from main.
Other ways is to use lock files(standard unix practice). One more way is to put something into the clipboard when main starts after checking if something is already in the clipboard.
Else, you can open a socket in a listen mode(ServerSocket). First try to connect to hte socket ; if you cannot connect, then open a serversocket. if you connect, then you know that another instance is already running.
So, pretty much any system resource can be used for knowing that an app is running.
BR,
~A
ManagementFactory class supported in J2SE 5.0 or later detail
but now i use J2SE 1.4 and I found this one http://audiprimadhanty.wordpress.com/2008/06/30/ensuring-one-instance-of-application-running-at-one-time/ but I never test. What do you think about it?
The Unique4j library can be used for running a single instance of a Java application and pass messages. You can see it at https://github.com/prat-man/unique4j. It supports Java 1.6+.
It uses a combination of file locks and dynamic port locks to detect and communicate between instances with the primary goal of allowing only one instance to run.
Following is a simple example of the same:
import tk.pratanumandal.unique4j.Unique4j;
import tk.pratanumandal.unique4j.exception.Unique4jException;
public class Unique4jDemo {
// unique application ID
public static String APP_ID = "tk.pratanumandal.unique4j-mlsdvo-20191511-#j.6";
public static void main(String[] args) throws Unique4jException, InterruptedException {
// create unique instance
Unique4j unique = new Unique4j(APP_ID) {
#Override
public void receiveMessage(String message) {
// display received message from subsequent instance
System.out.println(message);
}
#Override
public String sendMessage() {
// send message to first instance
return "Hello World!";
}
};
// try to obtain lock
boolean lockFlag = unique.acquireLock();
// sleep the main thread for 30 seconds to simulate long running tasks
Thread.sleep(30000);
// try to free the lock before exiting program
boolean lockFreeFlag = unique.freeLock();
}
}
Disclaimer: I created and maintain Unique4j library.
I wrote a dedicated library for that https://sanyarnd.github.io/applocker
It is based on file-channel locking, so it will not block a port number, or deadlock application in case of power outage (channel is released once process is terminated).
Library is lightweight itself and has a fluent API.
It was inspired by http://www.sauronsoftware.it/projects/junique/, but it's based on file channels instead. And there are other extra new features.
You could try using the Preferences API. It is platform independent.
I used sockets for that and depending if the application is on the client side or server side the behavior is a bit different:
client side : if an instance already exists(I cannot listen on a specific port) I will pass the application parameters and exit(you may want to perform some actions in the previous instance) if not I will start the application.
server side : if an instance already exists I will print a message and exit, if not I will start the application.
public class SingleInstance {
public static final String LOCK = System.getProperty("user.home") + File.separator + "test.lock";
public static final String PIPE = System.getProperty("user.home") + File.separator + "test.pipe";
private static JFrame frame = null;
public static void main(String[] args) {
try {
FileChannel lockChannel = new RandomAccessFile(LOCK, "rw").getChannel();
FileLock flk = null;
try {
flk = lockChannel.tryLock();
} catch(Throwable t) {
t.printStackTrace();
}
if (flk == null || !flk.isValid()) {
System.out.println("alread running, leaving a message to pipe and quitting...");
FileChannel pipeChannel = null;
try {
pipeChannel = new RandomAccessFile(PIPE, "rw").getChannel();
MappedByteBuffer bb = pipeChannel.map(FileChannel.MapMode.READ_WRITE, 0, 1);
bb.put(0, (byte)1);
bb.force();
} catch (Throwable t) {
t.printStackTrace();
} finally {
if (pipeChannel != null) {
try {
pipeChannel.close();
} catch (Throwable t) {
t.printStackTrace();
}
}
}
System.exit(0);
}
//We do not release the lock and close the channel here,
// which will be done after the application crashes or closes normally.
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
createAndShowGUI();
}
}
);
FileChannel pipeChannel = null;
try {
pipeChannel = new RandomAccessFile(PIPE, "rw").getChannel();
MappedByteBuffer bb = pipeChannel.map(FileChannel.MapMode.READ_WRITE, 0, 1);
while (true) {
byte b = bb.get(0);
if (b > 0) {
bb.put(0, (byte)0);
bb.force();
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
frame.setExtendedState(JFrame.NORMAL);
frame.setAlwaysOnTop(true);
frame.toFront();
frame.setAlwaysOnTop(false);
}
}
);
}
Thread.sleep(1000);
}
} catch (Throwable t) {
t.printStackTrace();
} finally {
if (pipeChannel != null) {
try {
pipeChannel.close();
} catch (Throwable t) {
t.printStackTrace();
}
}
}
} catch(Throwable t) {
t.printStackTrace();
}
}
public static void createAndShowGUI() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 650);
frame.getContentPane().add(new JLabel("MAIN WINDOW",
SwingConstants.CENTER), BorderLayout.CENTER);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
EDIT: Instead of using this WatchService approach, a simple 1 second timer thread could be used to check if the indicatorFile.exists(). Delete it, then bring the application toFront().
EDIT: I would like to know why this was downvoted. It's the best solution I have seen so far. E.g. the server socket approach fails if another application happens to already be listening to the port.
Just download Microsoft Windows Sysinternals TCPView (or use netstat), start it, sort by "State", look for the line block that says "LISTENING", pick one whose remote address says your computer's name, put that port into your new-Socket()-solution. In my implementation of it, I can produce failure every time. And it's logical, because it's the very foundation of the approach. Or what am I not getting regarding how to implement this?
Please inform me if and how I am wrong about this!
My view - which I am asking you to disprove if possible - is that developers are being advised to use an approach in production code that will fail in at least 1 of about 60000 cases. And if this view happens to be correct, then it can absolutely not be that a solution presented that does not have this problem is downvoted and criticized for its amount of code.
Disadvantages of the socket approach in comparison:
Fails if the wrong lottery ticket (port number) is chosen.
Fails in multi user environment: Only one user can run the application at the same time. (My approach would have to be slightly changed to create the file(s) in the user tree, but that's trivial.)
Fails if firewall rules are too strict.
Makes suspicious users (which I did meet in the wild) wonder what shenanigans you're up to when your text editor is claiming a server socket.
I just had a nice idea for how to solve the new-instance-to-existing-instance Java communication problem in a way that should work on every system. So, I whipped up this class in about two hours. Works like a charm :D
It's based on Robert's file lock approach (also on this page), which I have used ever since. To tell the already running instance that another instance tried to start (but didn't) ... a file is created and immediately deleted, and the first instance uses the WatchService to detect this folder content change. I can't believe that apparently this is a new idea, given how fundamental the problem is.
This can easily be changed to just create and not delete the file, and then information can be put into it that the proper instance can evaluate, e.g. the command line arguments - and the proper instance can then perform the deletion. Personally, I only needed to know when to restore my application's window and send it to front.
Example use:
public static void main(final String[] args) {
// ENSURE SINGLE INSTANCE
if (!SingleInstanceChecker.INSTANCE.isOnlyInstance(Main::otherInstanceTriedToLaunch, false)) {
System.exit(0);
}
// launch rest of application here
System.out.println("Application starts properly because it's the only instance.");
}
private static void otherInstanceTriedToLaunch() {
// Restore your application window and bring it to front.
// But make sure your situation is apt: This method could be called at *any* time.
System.err.println("Deiconified because other instance tried to start.");
}
Here's the class:
package yourpackagehere;
import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileLock;
import java.nio.file.*;
/**
* SingleInstanceChecker v[(2), 2016-04-22 08:00 UTC] by dreamspace-president.com
* <p>
* (file lock single instance solution by Robert https://stackoverflow.com/a/2002948/3500521)
*/
public enum SingleInstanceChecker {
INSTANCE; // HAHA! The CONFUSION!
final public static int POLLINTERVAL = 1000;
final public static File LOCKFILE = new File("SINGLE_INSTANCE_LOCKFILE");
final public static File DETECTFILE = new File("EXTRA_INSTANCE_DETECTFILE");
private boolean hasBeenUsedAlready = false;
private WatchService watchService = null;
private RandomAccessFile randomAccessFileForLock = null;
private FileLock fileLock = null;
/**
* CAN ONLY BE CALLED ONCE.
* <p>
* Assumes that the program will close if FALSE is returned: The other-instance-tries-to-launch listener is not
* installed in that case.
* <p>
* Checks if another instance is already running (temp file lock / shutdownhook). Depending on the accessibility of
* the temp file the return value will be true or false. This approach even works even if the virtual machine
* process gets killed. On the next run, the program can even detect if it has shut down irregularly, because then
* the file will still exist. (Thanks to Robert https://stackoverflow.com/a/2002948/3500521 for that solution!)
* <p>
* Additionally, the method checks if another instance tries to start. In a crappy way, because as awesome as Java
* is, it lacks some fundamental features. Don't worry, it has only been 25 years, it'll sure come eventually.
*
* #param codeToRunIfOtherInstanceTriesToStart Can be null. If not null and another instance tries to start (which
* changes the detect-file), the code will be executed. Could be used to
* bring the current (=old=only) instance to front. If null, then the
* watcher will not be installed at all, nor will the trigger file be
* created. (Null means that you just don't want to make use of this
* half of the class' purpose, but then you would be better advised to
* just use the 24 line method by Robert.)
* <p>
* BE CAREFUL with the code: It will potentially be called until the
* very last moment of the program's existence, so if you e.g. have a
* shutdown procedure or a window that would be brought to front, check
* if the procedure has not been triggered yet or if the window still
* exists / hasn't been disposed of yet. Or edit this class to be more
* comfortable. This would e.g. allow you to remove some crappy
* comments. Attribution would be nice, though.
* #param executeOnAWTEventDispatchThread Convenience function. If false, the code will just be executed. If
* true, it will be detected if we're currently on that thread. If so,
* the code will just be executed. If not so, the code will be run via
* SwingUtilities.invokeLater().
* #return if this is the only instance
*/
public boolean isOnlyInstance(final Runnable codeToRunIfOtherInstanceTriesToStart, final boolean executeOnAWTEventDispatchThread) {
if (hasBeenUsedAlready) {
throw new IllegalStateException("This class/method can only be used once, which kinda makes sense if you think about it.");
}
hasBeenUsedAlready = true;
final boolean ret = canLockFileBeCreatedAndLocked();
if (codeToRunIfOtherInstanceTriesToStart != null) {
if (ret) {
// Only if this is the only instance, it makes sense to install a watcher for additional instances.
installOtherInstanceLaunchAttemptWatcher(codeToRunIfOtherInstanceTriesToStart, executeOnAWTEventDispatchThread);
} else {
// Only if this is NOT the only instance, it makes sense to create&delete the trigger file that will effect notification of the other instance.
//
// Regarding "codeToRunIfOtherInstanceTriesToStart != null":
// While creation/deletion of the file concerns THE OTHER instance of the program,
// making it dependent on the call made in THIS instance makes sense
// because the code executed is probably the same.
createAndDeleteOtherInstanceWatcherTriggerFile();
}
}
optionallyInstallShutdownHookThatCleansEverythingUp();
return ret;
}
private void createAndDeleteOtherInstanceWatcherTriggerFile() {
try {
final RandomAccessFile randomAccessFileForDetection = new RandomAccessFile(DETECTFILE, "rw");
randomAccessFileForDetection.close();
Files.deleteIfExists(DETECTFILE.toPath()); // File is created and then instantly deleted. Not a problem for the WatchService :)
} catch (Exception e) {
e.printStackTrace();
}
}
private boolean canLockFileBeCreatedAndLocked() {
try {
randomAccessFileForLock = new RandomAccessFile(LOCKFILE, "rw");
fileLock = randomAccessFileForLock.getChannel().tryLock();
return fileLock != null;
} catch (Exception e) {
return false;
}
}
private void installOtherInstanceLaunchAttemptWatcher(final Runnable codeToRunIfOtherInstanceTriesToStart, final boolean executeOnAWTEventDispatchThread) {
// PREPARE WATCHSERVICE AND STUFF
try {
watchService = FileSystems.getDefault().newWatchService();
} catch (IOException e) {
e.printStackTrace();
return;
}
final File appFolder = new File("").getAbsoluteFile(); // points to current folder
final Path appFolderWatchable = appFolder.toPath();
// REGISTER CURRENT FOLDER FOR WATCHING FOR FILE DELETIONS
try {
appFolderWatchable.register(watchService, StandardWatchEventKinds.ENTRY_DELETE);
} catch (IOException e) {
e.printStackTrace();
return;
}
// INSTALL WATCHER THAT LOOKS IF OUR detectFile SHOWS UP IN THE DIRECTORY CHANGES. IF THERE'S A CHANGE, ANOTHER INSTANCE TRIED TO START, SO NOTIFY THE CURRENT ONE OF THAT.
final Thread t = new Thread(() -> watchForDirectoryChangesOnExtraThread(codeToRunIfOtherInstanceTriesToStart, executeOnAWTEventDispatchThread));
t.setDaemon(true);
t.setName("directory content change watcher");
t.start();
}
private void optionallyInstallShutdownHookThatCleansEverythingUp() {
if (fileLock == null && randomAccessFileForLock == null && watchService == null) {
return;
}
final Thread shutdownHookThread = new Thread(() -> {
try {
if (fileLock != null) {
fileLock.release();
}
if (randomAccessFileForLock != null) {
randomAccessFileForLock.close();
}
Files.deleteIfExists(LOCKFILE.toPath());
} catch (Exception ignore) {
}
if (watchService != null) {
try {
watchService.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
Runtime.getRuntime().addShutdownHook(shutdownHookThread);
}
private void watchForDirectoryChangesOnExtraThread(final Runnable codeToRunIfOtherInstanceTriesToStart, final boolean executeOnAWTEventDispatchThread) {
while (true) { // To eternity and beyond! Until the universe shuts down. (Should be a volatile boolean, but this class only has absolutely required features.)
try {
Thread.sleep(POLLINTERVAL);
} catch (InterruptedException e) {
e.printStackTrace();
}
final WatchKey wk;
try {
wk = watchService.poll();
} catch (ClosedWatchServiceException e) {
// This situation would be normal if the watcher has been closed, but our application never does that.
e.printStackTrace();
return;
}
if (wk == null || !wk.isValid()) {
continue;
}
for (WatchEvent<?> we : wk.pollEvents()) {
final WatchEvent.Kind<?> kind = we.kind();
if (kind == StandardWatchEventKinds.OVERFLOW) {
System.err.println("OVERFLOW of directory change events!");
continue;
}
final WatchEvent<Path> watchEvent = (WatchEvent<Path>) we;
final File file = watchEvent.context().toFile();
if (file.equals(DETECTFILE)) {
if (!executeOnAWTEventDispatchThread || SwingUtilities.isEventDispatchThread()) {
codeToRunIfOtherInstanceTriesToStart.run();
} else {
SwingUtilities.invokeLater(codeToRunIfOtherInstanceTriesToStart);
}
break;
} else {
System.err.println("THIS IS THE FILE THAT WAS DELETED: " + file);
}
}
wk.reset();
}
}
}

Android using a runtime strategy to support different API level?

I have a small functionality. Switching on the torch and keeping it on, till the user switches it off from my app or my app exits. Using :
params = camera.getParameters();
if (params.getFlashMode().equals(Parameters.FLASH_MODE_TORCH)) {
isFlashOn = true;
return;
}
params.setFlashMode(Parameters.FLASH_MODE_TORCH);
camera.setParameters(params);
camera.startPreview();
And to switch off :
if (params.getFlashMode().equals(Parameters.FLASH_MODE_OFF)) {
isFlashOn = false;
return;
}
params.setFlashMode(Parameters.FLASH_MODE_OFF);
camera.setParameters(params);
camera.stopPreview();
But I notice that this is not very robust. Works fine the first time, but after that (especially on my API levle 22 phone) might not work. I was thinking of testing with the android.hardware.camera2 as suggested here
Plan to use if (android.os.Build.VERSION.SDK_INT >20) and a strategy (a base interface implemented by two classes, one using old API and one the new camera2 API.
Is this safe on all devices? I saw that we can do it for android classes, but is it okay for our own classes too? Or are there devices which scan all our code and reject it if it has code that refers to API it does not know about?
I do not want to make two APKs as its a small functionality.
I make sure flash is available like this , not tested on all devices but in an emulator by Genymotion app did not crash.
public boolean torchInit() {
try {
PackageManager pm = app.getPackageManager();
// First check if device supports flashlight
boolean hasFlash = pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH);
if (!hasFlash) {
Toast.makeText(app, "Flash not found or can\'t get hold of it. No torch", Toast.LENGTH_LONG).show();
return false;
}
camera = Camera.open();
Camera.Parameters params = camera.getParameters();
Log.i(LogId, "camera params flash: " + params.getFlashMode());
return true;
} catch (Throwable e) {
Log.e(LogId, "cameraFlashSetup " + e, e);
Toast.makeText(app, "Flash error, no torch. Description : " + e, Toast.LENGTH_LONG).show();
camera = null;
}
return false;
}
The flash interface to change between the two classes is :
public abstract class TorchInterface {
protected AppCompatActivity app;
public void init(AppCompatActivity ap){
app = ap;
}
public abstract boolean torchInit();
public boolean torchReInit(){
return torchInit();//if re init is not different than init
}
public abstract boolean torchOn();
public abstract boolean torchOff();
}
Update: new code worked but only if I:
mBuilder = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
Instead of:
mBuilder = camera.createCaptureRequest(CameraDevice.TEMPLATE_MANUAL);
But then switches on flash as soon as init the app. I was going to chuck it, then realised on my Camera2Impl I can :
public boolean torchInit() {
//do nothing on usual init that app calls on create
return true;
}
And instead do the init on torch on (flash on):
public boolean torchOn() {
//if not in it, try first 3 times
if(mBuilder == null || mSession == null){
if(firstFewTimesTorchOn > 0){
firstFewTimesTorchOn--;
torchInit2();
try{
Thread.sleep(150);
}catch(Exception e){}
if(mBuilder == null || mSession == null) {
return false;
}
}
}
try {
mBuilder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_TORCH);//and etc
Android devices do not "scan" code - compiler does. Therefore, I don't see any issue with your idea. On contrary - using Strategy pattern is way better then if-else all over the code.
Something along these lines should work:
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
mFlashlightStrategy = new PostLollipopStrategy();
} else {
mFlashlightStrategy = new PreLollipopStrategy();
}
Is this safe on all devices?
Why dont't you put one check whether flash is available or not.
context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH);
which will return true if a flash is available, false if not. You can write your further code in true block.

Changing Flash setting of Android Camera 2 at runtime

Basically, what I am trying to do is change the CONTROL_AE_MODE by button click in the app. The user can use AUTO flash(ON_AUTO_FLASH), turn if ON(ON_ALWAYS_FLASH), or OFF(CONTROL_AE_MODE_OFF).
In this example: https://github.com/googlesamples/android-Camera2Basic/blob/master/Application/src/main/java/com/example/android/camera2basic/Camera2BasicFragment.java
Line 818, they set the flash once:
// Use the same AE and AF modes as the preview.
captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
setAutoFlash(captureBuilder);
// Orientation
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
CameraCaptureSession.CaptureCallback CaptureCallback
= new CameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureCompleted(#NonNull CameraCaptureSession session,
#NonNull CaptureRequest request,
#NonNull TotalCaptureResult result) {
showToast("Saved: " + mFile);
Log.d(TAG, mFile.toString());
unlockFocus();
}
};
mCaptureSession.stopRepeating();
mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);
And then builds the CaptureSession at line 840.
Is there a way to change the CONTROL_AE_MODE after the preview is made?
I have tried remaking the session, which kinda worked:
if(flashMode == CameraView.CAMERA_FLASH_ON){
Log.e("CAMERA 2", "FLASH ON");
mPreviewCaptureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
}else if(flashMode == CameraView.CAMERA_FLASH_OFF){
Log.e("CAMERA 2", "FLASH OFF");
mPreviewCaptureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF);
}else if(flashMode == CameraView.CAMERA_FLASH_AUTO){
Log.e("CAMERA 2", "FLASH AUTO");
mPreviewCaptureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
}
mFlashMode = flashMode;
if (mCameraCaptureSession != null) {
mCameraCaptureSession.close();
mCameraCaptureSession = null;
}
createCameraPreviewSession();
For some reason, CONTROL_AE_MODE_OFF would turn the whole preview black.
I tried looking in the docs for methods to update but haven't found anything.
Any tutorials or docs is much appreciated.
As mentioned by #cyborg86pl when switching flash modes you should not switch CONTROL_AE_MODE . Instead you can switch between FLASH_MODEĀ“s. Here is a working example for my case:
when (currentFlashState) {
FlashState.AUTO -> {
previewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH)
}
FlashState.ON -> {
previewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON)
previewRequestBuilder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_TORCH)
}
FlashState.OFF -> {
previewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON)
previewRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF)
}
}
previewRequest = previewRequestBuilder.build()
captureSession.setRepeatingRequest(previewRequest, captureCallback, backgroundHandler)
I don't know why your preview turn black, but you don't need to close capture session manually. From .close() method's docs:
Using createCaptureSession(List , CameraCaptureSession.StateCallback,
Handler) directly without closing is the recommended approach for
quickly switching to a new session, since unchanged target outputs can
be reused more efficiently.
So you can reuse existing CaptureRequest.Builder, set your changed value, build new PreviewRequest and just start new session with this new request, like this:
try {
// Change some capture settings
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
// Build new request (we can't just edit existing one, as it is immutable)
mPreviewRequest = mPreviewRequestBuilder.build();
// Set new repeating request with our changed one
mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
It will be much faster (almost without any visible freeze of preview).
What you want is disabling flash, not auto-exposure (AE), thus you want to use CONTROL_AE_MODE_ON rather than CONTROL_AE_MODE_OFF.
As mentioned in the documentation:
CONTROL_AE_MODE_ON
The camera device's autoexposure routine is active, with no flash control.

java system tray duplication or same application runs multiply parallely [duplicate]

Sometime I see many application such as msn, windows media player etc that are single instance applications (when user executes while application is running a new application instance will not created).
In C#, I use Mutex class for this but I don't know how to do this in Java.
I use the following method in the main method. This is the simplest, most robust, and least intrusive method I have seen so I thought that I'd share it.
private static boolean lockInstance(final String lockFile) {
try {
final File file = new File(lockFile);
final RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
final FileLock fileLock = randomAccessFile.getChannel().tryLock();
if (fileLock != null) {
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
try {
fileLock.release();
randomAccessFile.close();
file.delete();
} catch (Exception e) {
log.error("Unable to remove lock file: " + lockFile, e);
}
}
});
return true;
}
} catch (Exception e) {
log.error("Unable to create and/or lock file: " + lockFile, e);
}
return false;
}
If I believe this article, by :
having the first instance attempt to open a listening socket on the localhost interface. If it's able to open the socket, it is assumed that this is the first instance of the application to be launched. If not, the assumption is that an instance of this application is already running. The new instance must notify the existing instance that a launch was attempted, then exit. The existing instance takes over after receiving the notification and fires an event to the listener that handles the action.
Note: Ahe mentions in the comment that using InetAddress.getLocalHost() can be tricky:
it does not work as expected in DHCP-environment because address returned depends on whether the computer has network access.
Solution was to open connection with InetAddress.getByAddress(new byte[] {127, 0, 0, 1});
Probably related to bug 4435662.
I also found bug 4665037 which reports than Expected results of getLocalHost: return IP address of machine, vs. Actual results : return 127.0.0.1.
it is surprising to have getLocalHost return 127.0.0.1 on Linux but not on windows.
Or you may use ManagementFactory object. As explained here:
The getMonitoredVMs(int processPid) method receives as parameter 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\\test.jar". This way, we will catch just application name on the line 17 of the code below.
After that, we search JVM for another process with the same name, if we found it and the application PID is different, it means that is the second application instance.
JNLP offers also a SingleInstanceListener
If the app. has a GUI, launch it with JWS and use the SingleInstanceService.
Update
The Java Plug-In (required for both applets and JWS apps) was deprecated by Oracle and removed from the JDK. Browser manufacturers had already removed it from their browsers.
So this answer is defunct. Only leaving it here to warn people looking at old documentation.
You can use JUnique library. It provides support for running single-instance java application and is open-source.
http://www.sauronsoftware.it/projects/junique/
The JUnique library can be used to prevent a user to run at the same
time more instances of the same Java application.
JUnique implements locks and communication channels shared between all
the JVM instances launched by the same user.
public static void main(String[] args) {
String appId = "myapplicationid";
boolean alreadyRunning;
try {
JUnique.acquireLock(appId, new MessageHandler() {
public String handle(String message) {
// A brand new argument received! Handle it!
return null;
}
});
alreadyRunning = false;
} catch (AlreadyLockedException e) {
alreadyRunning = true;
}
if (!alreadyRunning) {
// Start sequence here
} else {
for (int i = 0; i < args.length; i++) {
JUnique.sendMessage(appId, args[0]));
}
}
}
Under the hood, it creates file locks in %USER_DATA%/.junique folder and creates a server socket at random port for each unique appId that allows sending/receiving messages between java applications.
I have found a solution, a bit cartoonish explanation, but still works in most cases. It uses the plain old lock file creating stuff, but in a quite different view:
http://javalandscape.blogspot.com/2008/07/single-instance-from-your-application.html
I think it will be a help to those with a strict firewall setting.
Yes this is a really decent answer for eclipse RCP eclipse single instance application
below is my code
in application.java
if(!isFileshipAlreadyRunning()){
MessageDialog.openError(display.getActiveShell(), "Fileship already running", "Another instance of this application is already running. Exiting.");
return IApplication.EXIT_OK;
}
private static boolean isFileshipAlreadyRunning() {
// socket concept is shown at http://www.rbgrn.net/content/43-java-single-application-instance
// but this one is really great
try {
final File file = new File("FileshipReserved.txt");
final RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
final FileLock fileLock = randomAccessFile.getChannel().tryLock();
if (fileLock != null) {
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
try {
fileLock.release();
randomAccessFile.close();
file.delete();
} catch (Exception e) {
//log.error("Unable to remove lock file: " + lockFile, e);
}
}
});
return true;
}
} catch (Exception e) {
// log.error("Unable to create and/or lock file: " + lockFile, e);
}
return false;
}
We use file locking for this (grab an exclusive lock on a magic file in the user's app data directory), but we are primarily interested in preventing multiple instances from ever running.
If you are trying to have the second instance pass command line args, etc... to the first instance, then using a socket connection on localhost will be killing two birds with one stone. General algorithm:
On launch, try to open listener on port XXXX on localhost
if fail, open a writer to that port on localhost and send the command line args, then shutdown
otherwise, listen on port XXXXX on localhost. When receive command line args, process them as if the app was launched with that command line.
On Windows, you can use launch4j.
A more generic way of limiting the number of instance's on a single machine, or even an entire network, is to use a multicast socket.
Using a multicast socket, enables you to broadcast a message to any amount of instances of your application, some of which can be on physically remote machines across a corporate network.
In this way you can enable many types of configurations, to control things like
One or Many instances per machine
One or Many instances per network (eg controlling installs on a client site)
Java's multicast support is via java.net package with MulticastSocket & DatagramSocket being the main tools.
Note: MulticastSocket's do not guarantee delivery of data packets, so you should use a tool built on top of multicast sockets like JGroups. JGroups does guarantee delivery of all data. It is one single jar file, with a very simple API.
JGroups has been around a while, and has some impressive usages in industry, for example it underpins JBoss's clustering mechanism do broadcast data to all instance of a cluster.
To use JGroups, to limit the number of instances of an app (on a machine or a network, lets say: to the number of licences a customer has bought) is conceptually very simple :
Upon startup of your application, each instance tries to join a named group eg "My Great App Group". You will have configured this group to allow 0, 1 or N members
When the group member count is greater than what you have configured for it.. your app should refuse to start up.
You can open a Memory Mapped File and then see if that file is OPEN already. if it is already open, you can return from main.
Other ways is to use lock files(standard unix practice). One more way is to put something into the clipboard when main starts after checking if something is already in the clipboard.
Else, you can open a socket in a listen mode(ServerSocket). First try to connect to hte socket ; if you cannot connect, then open a serversocket. if you connect, then you know that another instance is already running.
So, pretty much any system resource can be used for knowing that an app is running.
BR,
~A
ManagementFactory class supported in J2SE 5.0 or later detail
but now i use J2SE 1.4 and I found this one http://audiprimadhanty.wordpress.com/2008/06/30/ensuring-one-instance-of-application-running-at-one-time/ but I never test. What do you think about it?
The Unique4j library can be used for running a single instance of a Java application and pass messages. You can see it at https://github.com/prat-man/unique4j. It supports Java 1.6+.
It uses a combination of file locks and dynamic port locks to detect and communicate between instances with the primary goal of allowing only one instance to run.
Following is a simple example of the same:
import tk.pratanumandal.unique4j.Unique4j;
import tk.pratanumandal.unique4j.exception.Unique4jException;
public class Unique4jDemo {
// unique application ID
public static String APP_ID = "tk.pratanumandal.unique4j-mlsdvo-20191511-#j.6";
public static void main(String[] args) throws Unique4jException, InterruptedException {
// create unique instance
Unique4j unique = new Unique4j(APP_ID) {
#Override
public void receiveMessage(String message) {
// display received message from subsequent instance
System.out.println(message);
}
#Override
public String sendMessage() {
// send message to first instance
return "Hello World!";
}
};
// try to obtain lock
boolean lockFlag = unique.acquireLock();
// sleep the main thread for 30 seconds to simulate long running tasks
Thread.sleep(30000);
// try to free the lock before exiting program
boolean lockFreeFlag = unique.freeLock();
}
}
Disclaimer: I created and maintain Unique4j library.
I wrote a dedicated library for that https://sanyarnd.github.io/applocker
It is based on file-channel locking, so it will not block a port number, or deadlock application in case of power outage (channel is released once process is terminated).
Library is lightweight itself and has a fluent API.
It was inspired by http://www.sauronsoftware.it/projects/junique/, but it's based on file channels instead. And there are other extra new features.
You could try using the Preferences API. It is platform independent.
I used sockets for that and depending if the application is on the client side or server side the behavior is a bit different:
client side : if an instance already exists(I cannot listen on a specific port) I will pass the application parameters and exit(you may want to perform some actions in the previous instance) if not I will start the application.
server side : if an instance already exists I will print a message and exit, if not I will start the application.
public class SingleInstance {
public static final String LOCK = System.getProperty("user.home") + File.separator + "test.lock";
public static final String PIPE = System.getProperty("user.home") + File.separator + "test.pipe";
private static JFrame frame = null;
public static void main(String[] args) {
try {
FileChannel lockChannel = new RandomAccessFile(LOCK, "rw").getChannel();
FileLock flk = null;
try {
flk = lockChannel.tryLock();
} catch(Throwable t) {
t.printStackTrace();
}
if (flk == null || !flk.isValid()) {
System.out.println("alread running, leaving a message to pipe and quitting...");
FileChannel pipeChannel = null;
try {
pipeChannel = new RandomAccessFile(PIPE, "rw").getChannel();
MappedByteBuffer bb = pipeChannel.map(FileChannel.MapMode.READ_WRITE, 0, 1);
bb.put(0, (byte)1);
bb.force();
} catch (Throwable t) {
t.printStackTrace();
} finally {
if (pipeChannel != null) {
try {
pipeChannel.close();
} catch (Throwable t) {
t.printStackTrace();
}
}
}
System.exit(0);
}
//We do not release the lock and close the channel here,
// which will be done after the application crashes or closes normally.
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
createAndShowGUI();
}
}
);
FileChannel pipeChannel = null;
try {
pipeChannel = new RandomAccessFile(PIPE, "rw").getChannel();
MappedByteBuffer bb = pipeChannel.map(FileChannel.MapMode.READ_WRITE, 0, 1);
while (true) {
byte b = bb.get(0);
if (b > 0) {
bb.put(0, (byte)0);
bb.force();
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
frame.setExtendedState(JFrame.NORMAL);
frame.setAlwaysOnTop(true);
frame.toFront();
frame.setAlwaysOnTop(false);
}
}
);
}
Thread.sleep(1000);
}
} catch (Throwable t) {
t.printStackTrace();
} finally {
if (pipeChannel != null) {
try {
pipeChannel.close();
} catch (Throwable t) {
t.printStackTrace();
}
}
}
} catch(Throwable t) {
t.printStackTrace();
}
}
public static void createAndShowGUI() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 650);
frame.getContentPane().add(new JLabel("MAIN WINDOW",
SwingConstants.CENTER), BorderLayout.CENTER);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
EDIT: Instead of using this WatchService approach, a simple 1 second timer thread could be used to check if the indicatorFile.exists(). Delete it, then bring the application toFront().
EDIT: I would like to know why this was downvoted. It's the best solution I have seen so far. E.g. the server socket approach fails if another application happens to already be listening to the port.
Just download Microsoft Windows Sysinternals TCPView (or use netstat), start it, sort by "State", look for the line block that says "LISTENING", pick one whose remote address says your computer's name, put that port into your new-Socket()-solution. In my implementation of it, I can produce failure every time. And it's logical, because it's the very foundation of the approach. Or what am I not getting regarding how to implement this?
Please inform me if and how I am wrong about this!
My view - which I am asking you to disprove if possible - is that developers are being advised to use an approach in production code that will fail in at least 1 of about 60000 cases. And if this view happens to be correct, then it can absolutely not be that a solution presented that does not have this problem is downvoted and criticized for its amount of code.
Disadvantages of the socket approach in comparison:
Fails if the wrong lottery ticket (port number) is chosen.
Fails in multi user environment: Only one user can run the application at the same time. (My approach would have to be slightly changed to create the file(s) in the user tree, but that's trivial.)
Fails if firewall rules are too strict.
Makes suspicious users (which I did meet in the wild) wonder what shenanigans you're up to when your text editor is claiming a server socket.
I just had a nice idea for how to solve the new-instance-to-existing-instance Java communication problem in a way that should work on every system. So, I whipped up this class in about two hours. Works like a charm :D
It's based on Robert's file lock approach (also on this page), which I have used ever since. To tell the already running instance that another instance tried to start (but didn't) ... a file is created and immediately deleted, and the first instance uses the WatchService to detect this folder content change. I can't believe that apparently this is a new idea, given how fundamental the problem is.
This can easily be changed to just create and not delete the file, and then information can be put into it that the proper instance can evaluate, e.g. the command line arguments - and the proper instance can then perform the deletion. Personally, I only needed to know when to restore my application's window and send it to front.
Example use:
public static void main(final String[] args) {
// ENSURE SINGLE INSTANCE
if (!SingleInstanceChecker.INSTANCE.isOnlyInstance(Main::otherInstanceTriedToLaunch, false)) {
System.exit(0);
}
// launch rest of application here
System.out.println("Application starts properly because it's the only instance.");
}
private static void otherInstanceTriedToLaunch() {
// Restore your application window and bring it to front.
// But make sure your situation is apt: This method could be called at *any* time.
System.err.println("Deiconified because other instance tried to start.");
}
Here's the class:
package yourpackagehere;
import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileLock;
import java.nio.file.*;
/**
* SingleInstanceChecker v[(2), 2016-04-22 08:00 UTC] by dreamspace-president.com
* <p>
* (file lock single instance solution by Robert https://stackoverflow.com/a/2002948/3500521)
*/
public enum SingleInstanceChecker {
INSTANCE; // HAHA! The CONFUSION!
final public static int POLLINTERVAL = 1000;
final public static File LOCKFILE = new File("SINGLE_INSTANCE_LOCKFILE");
final public static File DETECTFILE = new File("EXTRA_INSTANCE_DETECTFILE");
private boolean hasBeenUsedAlready = false;
private WatchService watchService = null;
private RandomAccessFile randomAccessFileForLock = null;
private FileLock fileLock = null;
/**
* CAN ONLY BE CALLED ONCE.
* <p>
* Assumes that the program will close if FALSE is returned: The other-instance-tries-to-launch listener is not
* installed in that case.
* <p>
* Checks if another instance is already running (temp file lock / shutdownhook). Depending on the accessibility of
* the temp file the return value will be true or false. This approach even works even if the virtual machine
* process gets killed. On the next run, the program can even detect if it has shut down irregularly, because then
* the file will still exist. (Thanks to Robert https://stackoverflow.com/a/2002948/3500521 for that solution!)
* <p>
* Additionally, the method checks if another instance tries to start. In a crappy way, because as awesome as Java
* is, it lacks some fundamental features. Don't worry, it has only been 25 years, it'll sure come eventually.
*
* #param codeToRunIfOtherInstanceTriesToStart Can be null. If not null and another instance tries to start (which
* changes the detect-file), the code will be executed. Could be used to
* bring the current (=old=only) instance to front. If null, then the
* watcher will not be installed at all, nor will the trigger file be
* created. (Null means that you just don't want to make use of this
* half of the class' purpose, but then you would be better advised to
* just use the 24 line method by Robert.)
* <p>
* BE CAREFUL with the code: It will potentially be called until the
* very last moment of the program's existence, so if you e.g. have a
* shutdown procedure or a window that would be brought to front, check
* if the procedure has not been triggered yet or if the window still
* exists / hasn't been disposed of yet. Or edit this class to be more
* comfortable. This would e.g. allow you to remove some crappy
* comments. Attribution would be nice, though.
* #param executeOnAWTEventDispatchThread Convenience function. If false, the code will just be executed. If
* true, it will be detected if we're currently on that thread. If so,
* the code will just be executed. If not so, the code will be run via
* SwingUtilities.invokeLater().
* #return if this is the only instance
*/
public boolean isOnlyInstance(final Runnable codeToRunIfOtherInstanceTriesToStart, final boolean executeOnAWTEventDispatchThread) {
if (hasBeenUsedAlready) {
throw new IllegalStateException("This class/method can only be used once, which kinda makes sense if you think about it.");
}
hasBeenUsedAlready = true;
final boolean ret = canLockFileBeCreatedAndLocked();
if (codeToRunIfOtherInstanceTriesToStart != null) {
if (ret) {
// Only if this is the only instance, it makes sense to install a watcher for additional instances.
installOtherInstanceLaunchAttemptWatcher(codeToRunIfOtherInstanceTriesToStart, executeOnAWTEventDispatchThread);
} else {
// Only if this is NOT the only instance, it makes sense to create&delete the trigger file that will effect notification of the other instance.
//
// Regarding "codeToRunIfOtherInstanceTriesToStart != null":
// While creation/deletion of the file concerns THE OTHER instance of the program,
// making it dependent on the call made in THIS instance makes sense
// because the code executed is probably the same.
createAndDeleteOtherInstanceWatcherTriggerFile();
}
}
optionallyInstallShutdownHookThatCleansEverythingUp();
return ret;
}
private void createAndDeleteOtherInstanceWatcherTriggerFile() {
try {
final RandomAccessFile randomAccessFileForDetection = new RandomAccessFile(DETECTFILE, "rw");
randomAccessFileForDetection.close();
Files.deleteIfExists(DETECTFILE.toPath()); // File is created and then instantly deleted. Not a problem for the WatchService :)
} catch (Exception e) {
e.printStackTrace();
}
}
private boolean canLockFileBeCreatedAndLocked() {
try {
randomAccessFileForLock = new RandomAccessFile(LOCKFILE, "rw");
fileLock = randomAccessFileForLock.getChannel().tryLock();
return fileLock != null;
} catch (Exception e) {
return false;
}
}
private void installOtherInstanceLaunchAttemptWatcher(final Runnable codeToRunIfOtherInstanceTriesToStart, final boolean executeOnAWTEventDispatchThread) {
// PREPARE WATCHSERVICE AND STUFF
try {
watchService = FileSystems.getDefault().newWatchService();
} catch (IOException e) {
e.printStackTrace();
return;
}
final File appFolder = new File("").getAbsoluteFile(); // points to current folder
final Path appFolderWatchable = appFolder.toPath();
// REGISTER CURRENT FOLDER FOR WATCHING FOR FILE DELETIONS
try {
appFolderWatchable.register(watchService, StandardWatchEventKinds.ENTRY_DELETE);
} catch (IOException e) {
e.printStackTrace();
return;
}
// INSTALL WATCHER THAT LOOKS IF OUR detectFile SHOWS UP IN THE DIRECTORY CHANGES. IF THERE'S A CHANGE, ANOTHER INSTANCE TRIED TO START, SO NOTIFY THE CURRENT ONE OF THAT.
final Thread t = new Thread(() -> watchForDirectoryChangesOnExtraThread(codeToRunIfOtherInstanceTriesToStart, executeOnAWTEventDispatchThread));
t.setDaemon(true);
t.setName("directory content change watcher");
t.start();
}
private void optionallyInstallShutdownHookThatCleansEverythingUp() {
if (fileLock == null && randomAccessFileForLock == null && watchService == null) {
return;
}
final Thread shutdownHookThread = new Thread(() -> {
try {
if (fileLock != null) {
fileLock.release();
}
if (randomAccessFileForLock != null) {
randomAccessFileForLock.close();
}
Files.deleteIfExists(LOCKFILE.toPath());
} catch (Exception ignore) {
}
if (watchService != null) {
try {
watchService.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
Runtime.getRuntime().addShutdownHook(shutdownHookThread);
}
private void watchForDirectoryChangesOnExtraThread(final Runnable codeToRunIfOtherInstanceTriesToStart, final boolean executeOnAWTEventDispatchThread) {
while (true) { // To eternity and beyond! Until the universe shuts down. (Should be a volatile boolean, but this class only has absolutely required features.)
try {
Thread.sleep(POLLINTERVAL);
} catch (InterruptedException e) {
e.printStackTrace();
}
final WatchKey wk;
try {
wk = watchService.poll();
} catch (ClosedWatchServiceException e) {
// This situation would be normal if the watcher has been closed, but our application never does that.
e.printStackTrace();
return;
}
if (wk == null || !wk.isValid()) {
continue;
}
for (WatchEvent<?> we : wk.pollEvents()) {
final WatchEvent.Kind<?> kind = we.kind();
if (kind == StandardWatchEventKinds.OVERFLOW) {
System.err.println("OVERFLOW of directory change events!");
continue;
}
final WatchEvent<Path> watchEvent = (WatchEvent<Path>) we;
final File file = watchEvent.context().toFile();
if (file.equals(DETECTFILE)) {
if (!executeOnAWTEventDispatchThread || SwingUtilities.isEventDispatchThread()) {
codeToRunIfOtherInstanceTriesToStart.run();
} else {
SwingUtilities.invokeLater(codeToRunIfOtherInstanceTriesToStart);
}
break;
} else {
System.err.println("THIS IS THE FILE THAT WAS DELETED: " + file);
}
}
wk.reset();
}
}
}

How to implement a single instance Java application?

Sometime I see many application such as msn, windows media player etc that are single instance applications (when user executes while application is running a new application instance will not created).
In C#, I use Mutex class for this but I don't know how to do this in Java.
I use the following method in the main method. This is the simplest, most robust, and least intrusive method I have seen so I thought that I'd share it.
private static boolean lockInstance(final String lockFile) {
try {
final File file = new File(lockFile);
final RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
final FileLock fileLock = randomAccessFile.getChannel().tryLock();
if (fileLock != null) {
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
try {
fileLock.release();
randomAccessFile.close();
file.delete();
} catch (Exception e) {
log.error("Unable to remove lock file: " + lockFile, e);
}
}
});
return true;
}
} catch (Exception e) {
log.error("Unable to create and/or lock file: " + lockFile, e);
}
return false;
}
If I believe this article, by :
having the first instance attempt to open a listening socket on the localhost interface. If it's able to open the socket, it is assumed that this is the first instance of the application to be launched. If not, the assumption is that an instance of this application is already running. The new instance must notify the existing instance that a launch was attempted, then exit. The existing instance takes over after receiving the notification and fires an event to the listener that handles the action.
Note: Ahe mentions in the comment that using InetAddress.getLocalHost() can be tricky:
it does not work as expected in DHCP-environment because address returned depends on whether the computer has network access.
Solution was to open connection with InetAddress.getByAddress(new byte[] {127, 0, 0, 1});
Probably related to bug 4435662.
I also found bug 4665037 which reports than Expected results of getLocalHost: return IP address of machine, vs. Actual results : return 127.0.0.1.
it is surprising to have getLocalHost return 127.0.0.1 on Linux but not on windows.
Or you may use ManagementFactory object. As explained here:
The getMonitoredVMs(int processPid) method receives as parameter 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\\test.jar". This way, we will catch just application name on the line 17 of the code below.
After that, we search JVM for another process with the same name, if we found it and the application PID is different, it means that is the second application instance.
JNLP offers also a SingleInstanceListener
If the app. has a GUI, launch it with JWS and use the SingleInstanceService.
Update
The Java Plug-In (required for both applets and JWS apps) was deprecated by Oracle and removed from the JDK. Browser manufacturers had already removed it from their browsers.
So this answer is defunct. Only leaving it here to warn people looking at old documentation.
You can use JUnique library. It provides support for running single-instance java application and is open-source.
http://www.sauronsoftware.it/projects/junique/
The JUnique library can be used to prevent a user to run at the same
time more instances of the same Java application.
JUnique implements locks and communication channels shared between all
the JVM instances launched by the same user.
public static void main(String[] args) {
String appId = "myapplicationid";
boolean alreadyRunning;
try {
JUnique.acquireLock(appId, new MessageHandler() {
public String handle(String message) {
// A brand new argument received! Handle it!
return null;
}
});
alreadyRunning = false;
} catch (AlreadyLockedException e) {
alreadyRunning = true;
}
if (!alreadyRunning) {
// Start sequence here
} else {
for (int i = 0; i < args.length; i++) {
JUnique.sendMessage(appId, args[0]));
}
}
}
Under the hood, it creates file locks in %USER_DATA%/.junique folder and creates a server socket at random port for each unique appId that allows sending/receiving messages between java applications.
I have found a solution, a bit cartoonish explanation, but still works in most cases. It uses the plain old lock file creating stuff, but in a quite different view:
http://javalandscape.blogspot.com/2008/07/single-instance-from-your-application.html
I think it will be a help to those with a strict firewall setting.
Yes this is a really decent answer for eclipse RCP eclipse single instance application
below is my code
in application.java
if(!isFileshipAlreadyRunning()){
MessageDialog.openError(display.getActiveShell(), "Fileship already running", "Another instance of this application is already running. Exiting.");
return IApplication.EXIT_OK;
}
private static boolean isFileshipAlreadyRunning() {
// socket concept is shown at http://www.rbgrn.net/content/43-java-single-application-instance
// but this one is really great
try {
final File file = new File("FileshipReserved.txt");
final RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
final FileLock fileLock = randomAccessFile.getChannel().tryLock();
if (fileLock != null) {
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
try {
fileLock.release();
randomAccessFile.close();
file.delete();
} catch (Exception e) {
//log.error("Unable to remove lock file: " + lockFile, e);
}
}
});
return true;
}
} catch (Exception e) {
// log.error("Unable to create and/or lock file: " + lockFile, e);
}
return false;
}
We use file locking for this (grab an exclusive lock on a magic file in the user's app data directory), but we are primarily interested in preventing multiple instances from ever running.
If you are trying to have the second instance pass command line args, etc... to the first instance, then using a socket connection on localhost will be killing two birds with one stone. General algorithm:
On launch, try to open listener on port XXXX on localhost
if fail, open a writer to that port on localhost and send the command line args, then shutdown
otherwise, listen on port XXXXX on localhost. When receive command line args, process them as if the app was launched with that command line.
On Windows, you can use launch4j.
A more generic way of limiting the number of instance's on a single machine, or even an entire network, is to use a multicast socket.
Using a multicast socket, enables you to broadcast a message to any amount of instances of your application, some of which can be on physically remote machines across a corporate network.
In this way you can enable many types of configurations, to control things like
One or Many instances per machine
One or Many instances per network (eg controlling installs on a client site)
Java's multicast support is via java.net package with MulticastSocket & DatagramSocket being the main tools.
Note: MulticastSocket's do not guarantee delivery of data packets, so you should use a tool built on top of multicast sockets like JGroups. JGroups does guarantee delivery of all data. It is one single jar file, with a very simple API.
JGroups has been around a while, and has some impressive usages in industry, for example it underpins JBoss's clustering mechanism do broadcast data to all instance of a cluster.
To use JGroups, to limit the number of instances of an app (on a machine or a network, lets say: to the number of licences a customer has bought) is conceptually very simple :
Upon startup of your application, each instance tries to join a named group eg "My Great App Group". You will have configured this group to allow 0, 1 or N members
When the group member count is greater than what you have configured for it.. your app should refuse to start up.
You can open a Memory Mapped File and then see if that file is OPEN already. if it is already open, you can return from main.
Other ways is to use lock files(standard unix practice). One more way is to put something into the clipboard when main starts after checking if something is already in the clipboard.
Else, you can open a socket in a listen mode(ServerSocket). First try to connect to hte socket ; if you cannot connect, then open a serversocket. if you connect, then you know that another instance is already running.
So, pretty much any system resource can be used for knowing that an app is running.
BR,
~A
ManagementFactory class supported in J2SE 5.0 or later detail
but now i use J2SE 1.4 and I found this one http://audiprimadhanty.wordpress.com/2008/06/30/ensuring-one-instance-of-application-running-at-one-time/ but I never test. What do you think about it?
The Unique4j library can be used for running a single instance of a Java application and pass messages. You can see it at https://github.com/prat-man/unique4j. It supports Java 1.6+.
It uses a combination of file locks and dynamic port locks to detect and communicate between instances with the primary goal of allowing only one instance to run.
Following is a simple example of the same:
import tk.pratanumandal.unique4j.Unique4j;
import tk.pratanumandal.unique4j.exception.Unique4jException;
public class Unique4jDemo {
// unique application ID
public static String APP_ID = "tk.pratanumandal.unique4j-mlsdvo-20191511-#j.6";
public static void main(String[] args) throws Unique4jException, InterruptedException {
// create unique instance
Unique4j unique = new Unique4j(APP_ID) {
#Override
public void receiveMessage(String message) {
// display received message from subsequent instance
System.out.println(message);
}
#Override
public String sendMessage() {
// send message to first instance
return "Hello World!";
}
};
// try to obtain lock
boolean lockFlag = unique.acquireLock();
// sleep the main thread for 30 seconds to simulate long running tasks
Thread.sleep(30000);
// try to free the lock before exiting program
boolean lockFreeFlag = unique.freeLock();
}
}
Disclaimer: I created and maintain Unique4j library.
I wrote a dedicated library for that https://sanyarnd.github.io/applocker
It is based on file-channel locking, so it will not block a port number, or deadlock application in case of power outage (channel is released once process is terminated).
Library is lightweight itself and has a fluent API.
It was inspired by http://www.sauronsoftware.it/projects/junique/, but it's based on file channels instead. And there are other extra new features.
You could try using the Preferences API. It is platform independent.
I used sockets for that and depending if the application is on the client side or server side the behavior is a bit different:
client side : if an instance already exists(I cannot listen on a specific port) I will pass the application parameters and exit(you may want to perform some actions in the previous instance) if not I will start the application.
server side : if an instance already exists I will print a message and exit, if not I will start the application.
public class SingleInstance {
public static final String LOCK = System.getProperty("user.home") + File.separator + "test.lock";
public static final String PIPE = System.getProperty("user.home") + File.separator + "test.pipe";
private static JFrame frame = null;
public static void main(String[] args) {
try {
FileChannel lockChannel = new RandomAccessFile(LOCK, "rw").getChannel();
FileLock flk = null;
try {
flk = lockChannel.tryLock();
} catch(Throwable t) {
t.printStackTrace();
}
if (flk == null || !flk.isValid()) {
System.out.println("alread running, leaving a message to pipe and quitting...");
FileChannel pipeChannel = null;
try {
pipeChannel = new RandomAccessFile(PIPE, "rw").getChannel();
MappedByteBuffer bb = pipeChannel.map(FileChannel.MapMode.READ_WRITE, 0, 1);
bb.put(0, (byte)1);
bb.force();
} catch (Throwable t) {
t.printStackTrace();
} finally {
if (pipeChannel != null) {
try {
pipeChannel.close();
} catch (Throwable t) {
t.printStackTrace();
}
}
}
System.exit(0);
}
//We do not release the lock and close the channel here,
// which will be done after the application crashes or closes normally.
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
createAndShowGUI();
}
}
);
FileChannel pipeChannel = null;
try {
pipeChannel = new RandomAccessFile(PIPE, "rw").getChannel();
MappedByteBuffer bb = pipeChannel.map(FileChannel.MapMode.READ_WRITE, 0, 1);
while (true) {
byte b = bb.get(0);
if (b > 0) {
bb.put(0, (byte)0);
bb.force();
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
frame.setExtendedState(JFrame.NORMAL);
frame.setAlwaysOnTop(true);
frame.toFront();
frame.setAlwaysOnTop(false);
}
}
);
}
Thread.sleep(1000);
}
} catch (Throwable t) {
t.printStackTrace();
} finally {
if (pipeChannel != null) {
try {
pipeChannel.close();
} catch (Throwable t) {
t.printStackTrace();
}
}
}
} catch(Throwable t) {
t.printStackTrace();
}
}
public static void createAndShowGUI() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 650);
frame.getContentPane().add(new JLabel("MAIN WINDOW",
SwingConstants.CENTER), BorderLayout.CENTER);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
EDIT: Instead of using this WatchService approach, a simple 1 second timer thread could be used to check if the indicatorFile.exists(). Delete it, then bring the application toFront().
EDIT: I would like to know why this was downvoted. It's the best solution I have seen so far. E.g. the server socket approach fails if another application happens to already be listening to the port.
Just download Microsoft Windows Sysinternals TCPView (or use netstat), start it, sort by "State", look for the line block that says "LISTENING", pick one whose remote address says your computer's name, put that port into your new-Socket()-solution. In my implementation of it, I can produce failure every time. And it's logical, because it's the very foundation of the approach. Or what am I not getting regarding how to implement this?
Please inform me if and how I am wrong about this!
My view - which I am asking you to disprove if possible - is that developers are being advised to use an approach in production code that will fail in at least 1 of about 60000 cases. And if this view happens to be correct, then it can absolutely not be that a solution presented that does not have this problem is downvoted and criticized for its amount of code.
Disadvantages of the socket approach in comparison:
Fails if the wrong lottery ticket (port number) is chosen.
Fails in multi user environment: Only one user can run the application at the same time. (My approach would have to be slightly changed to create the file(s) in the user tree, but that's trivial.)
Fails if firewall rules are too strict.
Makes suspicious users (which I did meet in the wild) wonder what shenanigans you're up to when your text editor is claiming a server socket.
I just had a nice idea for how to solve the new-instance-to-existing-instance Java communication problem in a way that should work on every system. So, I whipped up this class in about two hours. Works like a charm :D
It's based on Robert's file lock approach (also on this page), which I have used ever since. To tell the already running instance that another instance tried to start (but didn't) ... a file is created and immediately deleted, and the first instance uses the WatchService to detect this folder content change. I can't believe that apparently this is a new idea, given how fundamental the problem is.
This can easily be changed to just create and not delete the file, and then information can be put into it that the proper instance can evaluate, e.g. the command line arguments - and the proper instance can then perform the deletion. Personally, I only needed to know when to restore my application's window and send it to front.
Example use:
public static void main(final String[] args) {
// ENSURE SINGLE INSTANCE
if (!SingleInstanceChecker.INSTANCE.isOnlyInstance(Main::otherInstanceTriedToLaunch, false)) {
System.exit(0);
}
// launch rest of application here
System.out.println("Application starts properly because it's the only instance.");
}
private static void otherInstanceTriedToLaunch() {
// Restore your application window and bring it to front.
// But make sure your situation is apt: This method could be called at *any* time.
System.err.println("Deiconified because other instance tried to start.");
}
Here's the class:
package yourpackagehere;
import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileLock;
import java.nio.file.*;
/**
* SingleInstanceChecker v[(2), 2016-04-22 08:00 UTC] by dreamspace-president.com
* <p>
* (file lock single instance solution by Robert https://stackoverflow.com/a/2002948/3500521)
*/
public enum SingleInstanceChecker {
INSTANCE; // HAHA! The CONFUSION!
final public static int POLLINTERVAL = 1000;
final public static File LOCKFILE = new File("SINGLE_INSTANCE_LOCKFILE");
final public static File DETECTFILE = new File("EXTRA_INSTANCE_DETECTFILE");
private boolean hasBeenUsedAlready = false;
private WatchService watchService = null;
private RandomAccessFile randomAccessFileForLock = null;
private FileLock fileLock = null;
/**
* CAN ONLY BE CALLED ONCE.
* <p>
* Assumes that the program will close if FALSE is returned: The other-instance-tries-to-launch listener is not
* installed in that case.
* <p>
* Checks if another instance is already running (temp file lock / shutdownhook). Depending on the accessibility of
* the temp file the return value will be true or false. This approach even works even if the virtual machine
* process gets killed. On the next run, the program can even detect if it has shut down irregularly, because then
* the file will still exist. (Thanks to Robert https://stackoverflow.com/a/2002948/3500521 for that solution!)
* <p>
* Additionally, the method checks if another instance tries to start. In a crappy way, because as awesome as Java
* is, it lacks some fundamental features. Don't worry, it has only been 25 years, it'll sure come eventually.
*
* #param codeToRunIfOtherInstanceTriesToStart Can be null. If not null and another instance tries to start (which
* changes the detect-file), the code will be executed. Could be used to
* bring the current (=old=only) instance to front. If null, then the
* watcher will not be installed at all, nor will the trigger file be
* created. (Null means that you just don't want to make use of this
* half of the class' purpose, but then you would be better advised to
* just use the 24 line method by Robert.)
* <p>
* BE CAREFUL with the code: It will potentially be called until the
* very last moment of the program's existence, so if you e.g. have a
* shutdown procedure or a window that would be brought to front, check
* if the procedure has not been triggered yet or if the window still
* exists / hasn't been disposed of yet. Or edit this class to be more
* comfortable. This would e.g. allow you to remove some crappy
* comments. Attribution would be nice, though.
* #param executeOnAWTEventDispatchThread Convenience function. If false, the code will just be executed. If
* true, it will be detected if we're currently on that thread. If so,
* the code will just be executed. If not so, the code will be run via
* SwingUtilities.invokeLater().
* #return if this is the only instance
*/
public boolean isOnlyInstance(final Runnable codeToRunIfOtherInstanceTriesToStart, final boolean executeOnAWTEventDispatchThread) {
if (hasBeenUsedAlready) {
throw new IllegalStateException("This class/method can only be used once, which kinda makes sense if you think about it.");
}
hasBeenUsedAlready = true;
final boolean ret = canLockFileBeCreatedAndLocked();
if (codeToRunIfOtherInstanceTriesToStart != null) {
if (ret) {
// Only if this is the only instance, it makes sense to install a watcher for additional instances.
installOtherInstanceLaunchAttemptWatcher(codeToRunIfOtherInstanceTriesToStart, executeOnAWTEventDispatchThread);
} else {
// Only if this is NOT the only instance, it makes sense to create&delete the trigger file that will effect notification of the other instance.
//
// Regarding "codeToRunIfOtherInstanceTriesToStart != null":
// While creation/deletion of the file concerns THE OTHER instance of the program,
// making it dependent on the call made in THIS instance makes sense
// because the code executed is probably the same.
createAndDeleteOtherInstanceWatcherTriggerFile();
}
}
optionallyInstallShutdownHookThatCleansEverythingUp();
return ret;
}
private void createAndDeleteOtherInstanceWatcherTriggerFile() {
try {
final RandomAccessFile randomAccessFileForDetection = new RandomAccessFile(DETECTFILE, "rw");
randomAccessFileForDetection.close();
Files.deleteIfExists(DETECTFILE.toPath()); // File is created and then instantly deleted. Not a problem for the WatchService :)
} catch (Exception e) {
e.printStackTrace();
}
}
private boolean canLockFileBeCreatedAndLocked() {
try {
randomAccessFileForLock = new RandomAccessFile(LOCKFILE, "rw");
fileLock = randomAccessFileForLock.getChannel().tryLock();
return fileLock != null;
} catch (Exception e) {
return false;
}
}
private void installOtherInstanceLaunchAttemptWatcher(final Runnable codeToRunIfOtherInstanceTriesToStart, final boolean executeOnAWTEventDispatchThread) {
// PREPARE WATCHSERVICE AND STUFF
try {
watchService = FileSystems.getDefault().newWatchService();
} catch (IOException e) {
e.printStackTrace();
return;
}
final File appFolder = new File("").getAbsoluteFile(); // points to current folder
final Path appFolderWatchable = appFolder.toPath();
// REGISTER CURRENT FOLDER FOR WATCHING FOR FILE DELETIONS
try {
appFolderWatchable.register(watchService, StandardWatchEventKinds.ENTRY_DELETE);
} catch (IOException e) {
e.printStackTrace();
return;
}
// INSTALL WATCHER THAT LOOKS IF OUR detectFile SHOWS UP IN THE DIRECTORY CHANGES. IF THERE'S A CHANGE, ANOTHER INSTANCE TRIED TO START, SO NOTIFY THE CURRENT ONE OF THAT.
final Thread t = new Thread(() -> watchForDirectoryChangesOnExtraThread(codeToRunIfOtherInstanceTriesToStart, executeOnAWTEventDispatchThread));
t.setDaemon(true);
t.setName("directory content change watcher");
t.start();
}
private void optionallyInstallShutdownHookThatCleansEverythingUp() {
if (fileLock == null && randomAccessFileForLock == null && watchService == null) {
return;
}
final Thread shutdownHookThread = new Thread(() -> {
try {
if (fileLock != null) {
fileLock.release();
}
if (randomAccessFileForLock != null) {
randomAccessFileForLock.close();
}
Files.deleteIfExists(LOCKFILE.toPath());
} catch (Exception ignore) {
}
if (watchService != null) {
try {
watchService.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
Runtime.getRuntime().addShutdownHook(shutdownHookThread);
}
private void watchForDirectoryChangesOnExtraThread(final Runnable codeToRunIfOtherInstanceTriesToStart, final boolean executeOnAWTEventDispatchThread) {
while (true) { // To eternity and beyond! Until the universe shuts down. (Should be a volatile boolean, but this class only has absolutely required features.)
try {
Thread.sleep(POLLINTERVAL);
} catch (InterruptedException e) {
e.printStackTrace();
}
final WatchKey wk;
try {
wk = watchService.poll();
} catch (ClosedWatchServiceException e) {
// This situation would be normal if the watcher has been closed, but our application never does that.
e.printStackTrace();
return;
}
if (wk == null || !wk.isValid()) {
continue;
}
for (WatchEvent<?> we : wk.pollEvents()) {
final WatchEvent.Kind<?> kind = we.kind();
if (kind == StandardWatchEventKinds.OVERFLOW) {
System.err.println("OVERFLOW of directory change events!");
continue;
}
final WatchEvent<Path> watchEvent = (WatchEvent<Path>) we;
final File file = watchEvent.context().toFile();
if (file.equals(DETECTFILE)) {
if (!executeOnAWTEventDispatchThread || SwingUtilities.isEventDispatchThread()) {
codeToRunIfOtherInstanceTriesToStart.run();
} else {
SwingUtilities.invokeLater(codeToRunIfOtherInstanceTriesToStart);
}
break;
} else {
System.err.println("THIS IS THE FILE THAT WAS DELETED: " + file);
}
}
wk.reset();
}
}
}

Categories