aboutsummaryrefslogtreecommitdiffstats
path: root/netx/net/sourceforge/jnlp/services/XSingleInstanceService.java
diff options
context:
space:
mode:
Diffstat (limited to 'netx/net/sourceforge/jnlp/services/XSingleInstanceService.java')
-rw-r--r--netx/net/sourceforge/jnlp/services/XSingleInstanceService.java236
1 files changed, 236 insertions, 0 deletions
diff --git a/netx/net/sourceforge/jnlp/services/XSingleInstanceService.java b/netx/net/sourceforge/jnlp/services/XSingleInstanceService.java
new file mode 100644
index 0000000..1a40794
--- /dev/null
+++ b/netx/net/sourceforge/jnlp/services/XSingleInstanceService.java
@@ -0,0 +1,236 @@
+// Copyright (C) 2009 Red Hat, Inc.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+package net.sourceforge.jnlp.services;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.jnlp.SingleInstanceListener;
+import javax.management.InstanceAlreadyExistsException;
+
+import net.sourceforge.jnlp.JNLPFile;
+import net.sourceforge.jnlp.runtime.JNLPRuntime;
+
+/**
+ * This class implements SingleInstanceService
+ *
+ * @author <a href="mailto:[email protected]">Omair Majid</a>
+ */
+public class XSingleInstanceService implements ExtendedSingleInstanceService {
+
+ boolean initialized = false;
+ List<SingleInstanceListener> listeners = new LinkedList<SingleInstanceListener>();
+
+ /**
+ * Implements a server that listens for arguments from new instances of this
+ * application
+ *
+ */
+ class SingleInstanceServer implements Runnable {
+
+ SingleInstanceLock lockFile = null;
+
+ public SingleInstanceServer(SingleInstanceLock lockFile) {
+ this.lockFile = lockFile;
+ }
+
+ public void run() {
+ ServerSocket listeningSocket = null;
+ try {
+ listeningSocket = new ServerSocket(0);
+ lockFile.createWithPort(listeningSocket.getLocalPort());
+
+ if (JNLPRuntime.isDebug()) {
+ System.out.println("Starting SingleInstanceServer on port" + listeningSocket);
+ }
+
+ while (true) {
+ try {
+ Socket communicationSocket = listeningSocket.accept();
+ ObjectInputStream ois = new ObjectInputStream(communicationSocket
+ .getInputStream());
+ String[] arguments = (String[]) ois.readObject();
+ notifySingleInstanceListeners(arguments);
+ } catch (Exception exception) {
+ // not much to do here...
+ exception.printStackTrace();
+ }
+
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ if (listeningSocket != null) {
+ try {
+ listeningSocket.close();
+ } catch (IOException e) {
+ // Give up.
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Create a new XSingleInstanceService
+ */
+ protected XSingleInstanceService() {
+ }
+
+ /**
+ * Initialize the new SingleInstanceService
+ *
+ * @throws InstanceAlreadyExistsException if the instance already exists
+ */
+ public void initializeSingleInstance() {
+ if (!initialized) {
+ // this is called after the application has started. so safe to use
+ // JNLPRuntime.getApplication()
+ checkSingleInstanceRunning(JNLPRuntime.getApplication().getJNLPFile());
+ initialized = true;
+ SingleInstanceLock lockFile;
+ JNLPFile jnlpFile = JNLPRuntime.getApplication().getJNLPFile();
+ lockFile = new SingleInstanceLock(jnlpFile);
+ if (!lockFile.isValid()) {
+ startListeningServer(lockFile);
+ }
+ }
+
+ }
+
+ /**
+ * Check if another instance of this application is already running
+ *
+ * @param jnlpFile The {@link JNLPFile} that specifies the application
+ *
+ * @throws InstanceExistsException if an instance of this application
+ * already exists
+ */
+ public void checkSingleInstanceRunning(JNLPFile jnlpFile) {
+ SingleInstanceLock lockFile = new SingleInstanceLock(jnlpFile);
+ if (lockFile.isValid()) {
+ int port = lockFile.getPort();
+ if (JNLPRuntime.isDebug()) {
+ System.out.println("Lock file is valid (port=" + port + "). Exiting.");
+ }
+ try {
+ sendProgramArgumentsToExistingApplication(port, jnlpFile.getApplication()
+ .getArguments());
+ throw new InstanceExistsException(String.valueOf(port));
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ /**
+ * Start the listening server to accept arguments from new instances of
+ * applications
+ *
+ * @param lockFile
+ * the {@link SingleInstanceLock} that the server should use
+ */
+ private void startListeningServer(SingleInstanceLock lockFile) {
+ SingleInstanceServer server = new SingleInstanceServer(lockFile);
+ Thread serverThread = new Thread(server);
+ /*
+ * mark as daemon so the JVM can shutdown if the server is the only
+ * thread running
+ */
+ serverThread.setDaemon(true);
+ serverThread.start();
+ }
+
+ /**
+ * Send the arguments for this application to the main instance
+ *
+ * @param port the port at which the SingleInstanceServer is listening at
+ * @param arguments the new arguments
+ * @throws IOException on any io exception
+ */
+ private void sendProgramArgumentsToExistingApplication(int port, String[] arguments)
+ throws IOException {
+ try {
+ Socket serverCommunicationSocket = new Socket((String) null, port);
+ ObjectOutputStream argumentStream = new ObjectOutputStream(serverCommunicationSocket
+ .getOutputStream());
+ argumentStream.writeObject(arguments);
+ argumentStream.close();
+ serverCommunicationSocket.close();
+
+ } catch (UnknownHostException unknownHost) {
+ if (JNLPRuntime.isDebug()) {
+ System.out.println("Unable to find localhost");
+ }
+ throw new RuntimeException(unknownHost);
+ }
+ }
+
+ /**
+ * Notify any SingleInstanceListener with new arguments
+ *
+ * @param arguments the new arguments to the application
+ */
+ private void notifySingleInstanceListeners(String[] arguments) {
+ for (SingleInstanceListener listener : listeners) {
+ // TODO this proxy is privileged. should i worry about security in
+ // methods being called?
+ listener.newActivation(arguments);
+ }
+ }
+
+ /**
+ * Add the specified SingleInstanceListener
+ *
+ * @throws InstanceExistsException, which is likely to terminate the
+ * application but not guaranteed to
+ */
+ public void addSingleInstanceListener(SingleInstanceListener sil) {
+ initializeSingleInstance();
+
+ if (sil == null) {
+ return;
+ }
+
+ listeners.add(sil);
+ }
+
+ /**
+ * Remove the specified SingleInstanceListener
+ *
+ * @throws InstanceExistsException if an instance of this single instance
+ * application already exists
+ *
+ */
+ public void removeSingleInstanceListener(SingleInstanceListener sil) {
+ initializeSingleInstance();
+
+ if (sil == null) {
+ return;
+ }
+
+ listeners.remove(sil);
+ }
+
+}