src/jdk.packager.services/share/classes/jdk/packager/services/singleton/SingleInstanceImpl.java
branchJDK-8200758-branch
changeset 57017 1b08af362a30
parent 57016 f63f13da91c0
child 57018 9d782e357916
--- a/src/jdk.packager.services/share/classes/jdk/packager/services/singleton/SingleInstanceImpl.java	Fri Nov 02 11:34:56 2018 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,455 +0,0 @@
-/*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code 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 General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.packager.services.singleton;
-
-import java.awt.Desktop;
-import java.awt.desktop.OpenFilesHandler;
-import java.awt.desktop.OpenFilesEvent;
-import java.net.ServerSocket;
-import java.net.InetAddress;
-import java.net.Socket;
-import java.io.File;
-import java.io.PrintStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.List;
-import java.security.PrivilegedAction;
-import java.security.AccessController;
-import java.security.SecureRandom;
-
-
-class SingleInstanceImpl {
-
-    static final String SI_FILEDIR = getTmpDir() + File.separator
-           + "si" + File.separator;
-    static final String SI_MAGICWORD = "jpackager.singleinstance.init";
-    static final String SI_ACK = "jpackager.singleinstance.ack";
-    static final String SI_STOP = "jpackager.singleinstance.stop";
-    static final String SI_EOF = "jpackager.singleinstance.EOF";
-
-    private final ArrayList<SingleInstanceListener> siListeners =
-            new ArrayList<>();
-    private SingleInstanceServer siServer;
-
-    private static final SecureRandom random = new SecureRandom();
-    private static volatile boolean serverStarted = false;
-    private static int randomNumber;
-
-    private final Object lock = new Object();
-
-    static String getSingleInstanceFilePrefix(final String stringId) {
-        String filePrefix = stringId.replace('/','_');
-        filePrefix = filePrefix.replace(':','_');
-        return filePrefix;
-    }
-
-    static String getTmpDir() {
-        String os = System.getProperty("os.name").toLowerCase();
-        if (os.contains("win")) {
-            return System.getProperty("user.home")
-                    + "\\AppData\\LocalLow\\Sun\\Java\\Packager\\tmp";
-        } else if (os.contains("mac") || os.contains("os x")) {
-            return System.getProperty("user.home")
-                    + "/Library/Application Support/Oracle/Java/Packager/tmp";
-        } else if (os.contains("nix") || os.contains("nux")
-                || os.contains("aix")) {
-            return System.getProperty("user.home") + "/.java/packager/tmp";
-        }
-
-        return System.getProperty("java.io.tmpdir");
-    }
-
-    void addSingleInstanceListener(SingleInstanceListener sil, String id) {
-
-        if (sil == null || id == null) {
-            return;
-        }
-
-        // start a new server thread for this unique id
-        // first time
-        synchronized (lock) {
-            if (!serverStarted) {
-                SingleInstanceService.trace("unique id: " + id);
-                try {
-                    siServer = new SingleInstanceServer(id);
-                    siServer.start();
-                } catch (Exception e) {
-                    SingleInstanceService.trace(
-                            "addSingleInstanceListener failed");
-                    SingleInstanceService.trace(e);
-                    return; // didn't start
-                }
-                serverStarted = true;
-            }
-        }
-
-        synchronized (siListeners) {
-            // add the sil to the arrayList
-            if (!siListeners.contains(sil)) {
-                siListeners.add(sil);
-            }
-        }
-    }
-
-    class SingleInstanceServer {
-
-        private final SingleInstanceServerRunnable runnable;
-        private final Thread thread;
-
-        SingleInstanceServer(SingleInstanceServerRunnable runnable)
-                throws IOException {
-            thread = new Thread(null, runnable, "JavaPackagerSIThread",
-                                0, false);
-            thread.setDaemon(true);
-            this.runnable = runnable;
-        }
-
-        SingleInstanceServer(String stringId) throws IOException {
-            this(new SingleInstanceServerRunnable(stringId));
-        }
-
-        int getPort() {
-            return runnable.getPort();
-        }
-
-        void start() {
-            thread.start();
-        }
-    }
-
-    private class SingleInstanceServerRunnable implements Runnable {
-
-        ServerSocket ss;
-        int port;
-        String stringId;
-        String[] arguments;
-
-        int getPort() {
-            return port;
-        }
-
-        SingleInstanceServerRunnable(String id) throws IOException {
-            stringId = id;
-
-            // open a free ServerSocket
-            ss = null;
-
-            // we should bind the server to the local InetAddress 127.0.0.1
-            // port number is automatically allocated for current SI
-            ss = new ServerSocket(0, 0, InetAddress.getByName("127.0.0.1"));
-
-            // get the port number
-            port = ss.getLocalPort();
-            SingleInstanceService.trace("server port at: " + port);
-
-            // create the single instance file with canonical home and port num
-            createSingleInstanceFile(stringId, port);
-        }
-
-        private String getSingleInstanceFilename(final String id,
-                final int port) {
-            String name = SI_FILEDIR + getSingleInstanceFilePrefix(id)
-                    + "_" + port;
-            SingleInstanceService.trace("getSingleInstanceFilename: " + name);
-            return name;
-        }
-
-        private void removeSingleInstanceFile(final String id, final int port) {
-            new File(getSingleInstanceFilename(id, port)).delete();
-            SingleInstanceService.trace("removed SingleInstanceFile: "
-                                        + getSingleInstanceFilename(id, port));
-        }
-
-        private void createSingleInstanceFile(final String id, final int port) {
-            String filename = getSingleInstanceFilename(id, port);
-            final File siFile = new File(filename);
-            final File siDir = new File(SI_FILEDIR);
-            AccessController.doPrivileged(new PrivilegedAction<Void>() {
-                @Override
-                public Void run() {
-                    siDir.mkdirs();
-                    String[] fList = siDir.list();
-                    if (fList != null) {
-                        String prefix = getSingleInstanceFilePrefix(id);
-                        for (String file : fList) {
-                            // if file with the same prefix exist, remove it
-                            if (file.startsWith(prefix)) {
-                                SingleInstanceService.trace(
-                                        "file should be removed: "
-                                         + SI_FILEDIR + file);
-                                new File(SI_FILEDIR + file).delete();
-                            }
-                        }
-                    }
-
-                    PrintStream out = null;
-                    try {
-                        siFile.createNewFile();
-                        siFile.deleteOnExit();
-                        // write random number to single instance file
-                        out = new PrintStream(new FileOutputStream(siFile));
-                        randomNumber = random.nextInt();
-                        out.print(randomNumber);
-                    } catch (IOException ioe) {
-                        SingleInstanceService.trace(ioe);
-                    } finally {
-                        if (out != null) {
-                            out.close();
-                        }
-                    }
-                    return null;
-                }
-            });
-        }
-
-        @Override
-        public void run() {
-            // start sil to handle all the incoming request
-            // from the server port of the current url
-            AccessController.doPrivileged(new PrivilegedAction<Void>() {
-                @Override
-                public Void run() {
-                    List<String> recvArgs = new ArrayList<>();
-                    while (true) {
-                        recvArgs.clear();
-                        InputStream is = null;
-                        BufferedReader in = null;
-                        InputStreamReader isr = null;
-                        Socket s = null;
-                        String line = null;
-                        boolean sendAck = false;
-                        int port = -1;
-                        String charset = null;
-                        try {
-                            SingleInstanceService.trace("waiting connection");
-                            s = ss.accept();
-                            is = s.getInputStream();
-                            // read first byte for encoding type
-                            int encoding = is.read();
-                            if (encoding ==
-                                SingleInstanceService.ENCODING_PLATFORM) {
-                                charset = Charset.defaultCharset().name();
-                            } else if (encoding ==
-                                    SingleInstanceService.ENCODING_UNICODE) {
-                                charset =
-                                    SingleInstanceService.ENCODING_UNICODE_NAME;
-                            } else {
-                                SingleInstanceService.trace(
-                                    "SingleInstanceImpl - unknown encoding");
-                                return null;
-                            }
-                            isr = new InputStreamReader(is, charset);
-                            in = new BufferedReader(isr);
-                            // first read the random number
-                            line = in.readLine();
-                            if (line.equals(String.valueOf(randomNumber)) ==
-                                    false) {
-                                // random number does not match
-                                // should not happen
-                                // shutdown server socket
-                                removeSingleInstanceFile(stringId, port);
-                                ss.close();
-                                serverStarted = false;
-                                SingleInstanceService.trace("Unexpected Error, "
-                                        + "SingleInstanceService disabled");
-                                return null;
-                            } else {
-                                line = in.readLine();
-                                // no need to continue reading if MAGICWORD
-                                // did not come first
-                                SingleInstanceService.trace("recv: " + line);
-                                if (line.equals(SI_MAGICWORD)) {
-                                    SingleInstanceService.trace(
-                                            "got magic word.");
-                                    while (true) {
-                                        // Get input string
-                                        try {
-                                            line = in.readLine();
-                                            if (line != null
-                                                    && line.equals(SI_EOF)) {
-                                                // end of file reached
-                                                break;
-                                            } else {
-                                                recvArgs.add(line);
-                                            }
-                                        } catch (IOException ioe) {
-                                            SingleInstanceService.trace(ioe);
-                                        }
-                                    }
-                                    arguments = recvArgs.toArray(
-                                            new String[recvArgs.size()]);
-                                    sendAck = true;
-                                } else if (line.equals(SI_STOP)) {
-                                    // remove the SingleInstance file
-                                    removeSingleInstanceFile(stringId, port);
-                                    break;
-                                }
-                            }
-                        } catch (IOException ioe) {
-                            SingleInstanceService.trace(ioe);
-                        } finally {
-                            try {
-                                if (sendAck) {
-                                    // let the action listener handle the rest
-                                    for (String arg : arguments) {
-                                        SingleInstanceService.trace(
-                                                "Starting new instance with "
-                                                + "arguments: arg:" + arg);
-                                    }
-
-                                    performNewActivation(arguments);
-
-                                    // now the event is handled, we can send
-                                    // out the ACK
-                                    SingleInstanceService.trace(
-                                            "sending out ACK");
-                                    if (s != null) {
-                                        try (OutputStream os =
-                                                s.getOutputStream();
-                                            PrintStream ps = new PrintStream(os,
-                                                    true, charset)) {
-                                            // send OK (ACK)
-                                            ps.println(SI_ACK);
-                                            ps.flush();
-                                        }
-                                    }
-                                }
-
-                                if (in != null) {
-                                    in.close();
-                                }
-
-                                if (isr != null) {
-                                    isr.close();
-                                }
-
-                                if (is != null) {
-                                    is.close();
-                                }
-
-                                if (s != null) {
-                                    s.close();
-                                }
-                            } catch (IOException ioe) {
-                                SingleInstanceService.trace(ioe);
-                            }
-                        }
-                    }
-                    return null;
-                }
-            });
-        }
-    }
-
-    private void performNewActivation(final String[] args) {
-        // enumerate the sil list and call
-        // each sil with arguments
-        @SuppressWarnings("unchecked")
-        ArrayList<SingleInstanceListener> silal =
-                (ArrayList<SingleInstanceListener>)siListeners.clone();
-        silal.forEach(sil -> sil.newActivation(args));
-    }
-
-    void setOpenFileHandler() {
-        String os = System.getProperty("os.name").toLowerCase();
-        if (!os.contains("mac") && !os.contains("os x")) {
-            return;
-        }
-
-        Desktop.getDesktop().setOpenFileHandler(new OpenFilesHandler() {
-            @Override
-            public void openFiles(OpenFilesEvent e) {
-                List<String> arguments = new ArrayList<>();
-                e.getFiles().forEach(file -> arguments.add(file.toString()));
-                performNewActivation(arguments.toArray(
-                                    new String[arguments.size()]));
-            }
-        });
-    }
-
-    void removeSingleInstanceListener(SingleInstanceListener sil) {
-        if (sil == null) {
-            return;
-        }
-
-        synchronized (siListeners) {
-
-            if (!siListeners.remove(sil)) {
-                return;
-            }
-
-            if (siListeners.isEmpty()) {
-                 AccessController.doPrivileged(new PrivilegedAction<Void>() {
-                    @Override
-                    public Void run() {
-                        // stop server
-                        Socket socket = null;
-                        PrintStream out = null;
-                        OutputStream os = null;
-                        try {
-                            socket = new Socket("127.0.0.1",
-                                    siServer.getPort());
-                            os = socket.getOutputStream();
-                            byte[] encoding = new byte[1];
-                            encoding[0] =
-                                    SingleInstanceService.ENCODING_PLATFORM;
-                            os.write(encoding);
-                            String charset = Charset.defaultCharset().name();
-                            out = new PrintStream(os, true, charset);
-                            out.println(randomNumber);
-                            out.println(SingleInstanceImpl.SI_STOP);
-                            out.flush();
-                            serverStarted = false;
-                        } catch (IOException ioe) {
-                            SingleInstanceService.trace(ioe);
-                        } finally {
-                            try {
-                                if (out != null) {
-                                    out.close();
-                                }
-                                if (os != null) {
-                                    os.close();
-                                }
-                                if (socket != null) {
-                                    socket.close();
-                                }
-                            } catch (IOException ioe) {
-                                SingleInstanceService.trace(ioe);
-                            }
-                        }
-                        return null;
-                    }
-               });
-            }
-        }
-    }
-}