package org.lysty.ui; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.UnknownHostException; import org.apache.log4j.Logger; public class ApplicationInstanceManager { private static final String NO_ARGS_STR = "$$NOARGS$$"; private static ApplicationInstanceListener subListener; /** Randomly chosen, but static, high socket number */ public static final int SINGLE_INSTANCE_NETWORK_SOCKET = 44431; /** Must end with newline */ public static final String SINGLE_INSTANCE_SHARED_KEY = "$$NewInstance$$" + System.getProperty("line.separator"); public static Logger log = Logger .getLogger(ApplicationInstanceManager.class); /** * Registers this instance of the application. * * @return true if first instance, false if not. */ public static boolean registerInstance(String[] args) { // returnValueOnError should be true if lenient (allows app to run on // network error) or false if strict. boolean returnValueOnError = true; // try to open network socket // if success, listen to socket for new instance message, return true // if unable to open, connect to existing and send new instance message, // return false try { final ServerSocket socket = new ServerSocket( SINGLE_INSTANCE_NETWORK_SOCKET, 10, InetAddress.getLocalHost()); log.debug("Listening for application instances on socket " + SINGLE_INSTANCE_NETWORK_SOCKET); Thread instanceListenerThread = new Thread(new Runnable() { @Override public void run() { boolean socketClosed = false; while (!socketClosed) { if (socket.isClosed()) { socketClosed = true; } else { try { Socket client = socket.accept(); BufferedReader in = new BufferedReader( new InputStreamReader(client .getInputStream())); String message = in.readLine(); if (message == null) message = ""; if (SINGLE_INSTANCE_SHARED_KEY.trim().equals( message.trim())) { log.debug("Shared key matched - new application instance found"); String newArgsStr = in.readLine(); if (newArgsStr == null) newArgsStr = ""; String[] newArgs = newArgsStr.split("\\|"); if (NO_ARGS_STR.equals(newArgs[0])) { fireNewInstance(new String[0]); } else { fireNewInstance(newArgs); } } in.close(); client.close(); } catch (IOException e) { socketClosed = true; } } } } }); instanceListenerThread.start(); // listen } catch (UnknownHostException e) { log.error(e.getMessage(), e); return returnValueOnError; } catch (IOException e) { log.debug("Port is already taken. Notifying first instance."); try { Socket clientSocket = new Socket(InetAddress.getLocalHost(), SINGLE_INSTANCE_NETWORK_SOCKET); OutputStream out = clientSocket.getOutputStream(); out.write(SINGLE_INSTANCE_SHARED_KEY.getBytes()); StringBuilder builder = new StringBuilder(); if (args == null || args.length == 0) { builder.append("|").append(NO_ARGS_STR); } else { for (int i = 0; i < args.length; i++) { builder.append("|").append(args[i]); } } builder.append(System.getProperty("line.separator")); String newArgsStr = builder.substring(1).toString(); out.write(newArgsStr.getBytes()); out.close(); clientSocket.close(); log.debug("Successfully notified first instance."); return false; } catch (UnknownHostException e1) { log.error(e.getMessage(), e); return returnValueOnError; } catch (IOException e1) { log.error("Error connecting to local port for single instance notification"); log.error(e1.getMessage(), e1); return returnValueOnError; } } return true; } public static void setApplicationInstanceListener( ApplicationInstanceListener listener) { subListener = listener; } private static void fireNewInstance(String[] args) { if (subListener != null) { subListener.newInstanceCreated(args); } } }