Class SingleInstanceManager
USAGE: Start by invoking the tryAcquireLock(...) method. This will return true if the lock was acquired - that means that this instance will be considered the "primary" instance. You can optionally specify a port number to use. (Locks are acquired by binding a server socket to a specific TCP port on localhost). You should supply an implementation of the ArgsListener interface to receive any command-line arguments sent from new instances and process them. If tryAcquireLock(...) returns false, then another instance is already running, and you should send your arguments to it using the sendArgsToRunningInstance(...) method, and then immediately exit. For example:
// In your application startup:
SingleInstanceManager instanceManager = SingleInstanceManager.getInstance();
if (instanceManager.tryAcquireLock(args -> handleStartArgs(args))) {
// This is the primary instance - continue your usual startup
}
else {
// Another instance is already running - send args and exit
instanceManager.sendArgsToRunningInstance(args);
// If sendArgsToRunningInstance fails, an error dialog will be shown.
// Otherwise, it might not be obvious to the user what just happened.
System.exit(0);
}
In your primary instance, implement the handleStartArgs(...) method to process any arguments received from new instances. Note that this method will be invoked on the Swing Event Dispatch Thread (EDT), so you can safely update your UI from there.
Cleanup: This class registers a JVM shutdown hook to invoke release() automatically when the JVM shuts down. Callers also have the option of invoking release() manually to explicitly release the lock and close the server socket. The release() method is idempotent and thread safe, so it is safe to call it multiple times.
- Since:
- swing-extras 2.6
- Author:
- scorbo2 (with copilot/claude)
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic interfaceInvoked when startup arguments are received from a new instance. -
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final intThe port number should be something that is unlikely to conflict with any other application. -
Method Summary
Modifier and TypeMethodDescriptionstatic SingleInstanceManagerReturns the singleton instance of SingleInstanceManager.intReturns the port number this instance is listening on.booleanReports whether this instance is currently the primary instance and is currently listening for new instance connections.booleanReports whether an error dialog should be shown if sending arguments to the running instance fails.voidrelease()Release the lock on shutdown.voidsendArgsToRunningInstance(String[] args) Sends the given arguments to the running instance.voidsetShowErrorDialogOnArgSendFailure(boolean showErrorDialogOnArgSendFailure) Controls whether or not an error dialog is shown in the case where sending arguments to the running instance fails.booleanAttempts to start as primary instance.booleantryAcquireLock(SingleInstanceManager.ArgsListener listener, int port) Attempts to start as primary instance using the specified port.
-
Field Details
-
DEFAULT_PORT
public static final int DEFAULT_PORTThe port number should be something that is unlikely to conflict with any other application. Just pick a random high number. Callers can override this default by calling tryAcquireLock with a different port.- See Also:
-
-
Method Details
-
getInstance
Returns the singleton instance of SingleInstanceManager. -
tryAcquireLock
Attempts to start as primary instance. Returns true if this is the primary instance, false if another instance is already running. -
tryAcquireLock
Attempts to start as primary instance using the specified port. Returns true if this is the primary instance, false if another instance is already running.- Parameters:
listener- the listener to be notified when arguments are received from new instancesport- the port number to use (must be between 1024 and 65535, non-privileged ports only)- Returns:
- true if this is the primary instance, false otherwise
- Throws:
IllegalArgumentException- if the port is outside the valid range or is a privileged port
-
sendArgsToRunningInstance
Sends the given arguments to the running instance. Will log an exception if unable to connect. -
isListening
public boolean isListening()Reports whether this instance is currently the primary instance and is currently listening for new instance connections. -
getListeningPort
public int getListeningPort()Returns the port number this instance is listening on. Useful for logging or diagnostics. -
isShowErrorDialogOnArgSendFailure
public boolean isShowErrorDialogOnArgSendFailure()Reports whether an error dialog should be shown if sending arguments to the running instance fails. -
setShowErrorDialogOnArgSendFailure
public void setShowErrorDialogOnArgSendFailure(boolean showErrorDialogOnArgSendFailure) Controls whether or not an error dialog is shown in the case where sending arguments to the running instance fails. The default value is true, because otherwise it may not be obvious to the user what went wrong if the second instance fails to send its args. This is here largely for unit testing purposes, so tests can disable the dialog. -
release
public void release()Release the lock on shutdown. This should be invoked by the application's shutdown hook to clean up the server socket. Note that for swing-extras applications that use the UpdateManager, the cleanup code should be registered as a shutdownHook with the UpdateManager so that it runs when the UpdateManager initiates an application restart.
-