/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.sling.launchpad.app;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.OutputStreamWriter;
import java.lang.management.LockInfo;
import java.lang.management.ManagementFactory;
import java.lang.management.MonitorInfo;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.math.BigInteger;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * The <code>ControlListener</code> class is a helper class for the {@link Main}
 * class to support in Sling standalone application process communication. This
 * class implements the client and server sides of a TCP/IP based communication
 * channel to control a running Sling application.
 * <p>
 * The server side listens for commands on a configurable host and port &endash;
 * <code>localhost:63000</code> by default &endash; supporting the following
 * commands:
 * <table>
 * <tr>
 * <th>Command</th>
 * <th>Description</th>
 * </tr>
 * <tr>
 * <td><code>status</code></td>
 * <td>Request status information. Currently only <i>OK</i> is sent back. If no
 * connection can be created to the server the client assumes Sling is not
 * running.</td>
 * </tr>
 * <tr>
 * <td><code>stop</code></td>
 * <td>Requests Sling to shutdown.</td>
 * </tr>
 * </table>
 */
class ControlListener implements Runnable {

    // command sent by the client to cause Sling to shutdown
    static final String COMMAND_STOP = "stop";

    // command sent by the client to check for the status of the server
    static final String COMMAND_STATUS = "status";

    // command sent by the client to request a thread dump
    static final String COMMAND_THREADS = "threads";

    // the response sent by the server if the command executed successfully
    private static final String RESPONSE_OK = "OK";

    // the status response sent by the server when shutting down
    private static final String RESPONSE_STOPPING = "STOPPING";

    // The default interface to listen on
    private static final String DEFAULT_LISTEN_INTERFACE = "127.0.0.1";

    // The default port to listen on and to connect to - we select it randomly
    private static final int DEFAULT_LISTEN_PORT = 0;

    // The reference to the Main class to shutdown on request
    private final Main slingMain;

    private final String listenSpec;

    private String secretKey;
    private InetSocketAddress socketAddress;

    private volatile Thread shutdownThread = null;

    /**
     * Creates an instance of this control support class.
     * <p>
     * The host (name or address) and port number of the socket is defined by
     * the <code>listenSpec</code> parameter. This parameter is defined as
     * <code>[ host ":" ] port</code>. If the parameter is empty or
     * <code>null</code> it defaults to <i>localhost:0</i>. If the host name
     * is missing it defaults to <i>localhost</i>.
     *
     * @param slingMain The Main class reference. This is only required if this
     *            instance is used for the server side to listen for remote stop
     *            commands. Otherwise this argument may be <code>null</code>.
     * @param listenSpec The specification for the host and port for the socket
     *            connection. See above for the format of this parameter.
     */
    ControlListener(final Main slingMain, final String listenSpec) {
        this.slingMain = slingMain;
        this.listenSpec = listenSpec; // socketAddress = this.getSocketAddress(listenSpec, selectNewPort);
    }

    /**
     * Implements the server side of the control connection starting a thread
     * listening on the host and port configured on setup of this instance.
     */
    boolean listen() {
        final File configFile = getConfigFile();
        if (configFile.canRead() && statusServer() == 0) {
            // server already running, fail
            Main.error("Sling already active in " + this.slingMain.getSlingHome(), null);
            return false;
        }
        configFile.delete();

        final Thread listener = new Thread(this);
        listener.setDaemon(true);
        listener.setName("Apache Sling Control Listener (inactive)");
        listener.start();
        return true;
    }

    /**
     * Implements the client side of the control connection sending the command
     * to shutdown Sling.
     */
    int shutdownServer() {
        return sendCommand(COMMAND_STOP);
    }

    /**
     * Implements the client side of the control connection sending the command
     * to check whether Sling is active.
     */
    int statusServer() {
        return sendCommand(COMMAND_STATUS);
    }

    /**
     * Implements the client side of the control connection sending the command
     * to retrieve a thread dump.
     */
    int dumpThreads() {
        return sendCommand(COMMAND_THREADS);
    }

    // ---------- Runnable interface

    /**
     * Implements the server thread receiving commands from clients and acting
     * upon them.
     */
    @Override
    public void run() {
        this.configure(false);

        final ServerSocket server;
        try {
            server = new ServerSocket();
            server.bind(this.socketAddress);
            writePortToConfigFile(getConfigFile(),
                new InetSocketAddress(server.getInetAddress(), server.getLocalPort()), this.secretKey);
            Thread.currentThread().setName(
                "Apache Sling Control Listener@" + server.getInetAddress() + ":" + server.getLocalPort());
            Main.info("Apache Sling Control Listener started", null);
        } catch (final IOException ioe) {
            Main.error("Failed to start Apache Sling Control Listener", ioe);
            return;
        }

        long delay = 0;

        try {
            while (true) {

                final Socket s;
                try {
                    s = server.accept();
                } catch (IOException ioe) {
                    // accept terminated, most probably due to Socket.close()
                    // just end the loop and exit
                    break;
                }

                // delay processing after unsuccessful attempts
                if (delay > 0) {
                    Main.info(s.getRemoteSocketAddress() + ": Delay: " + (delay / 1000), null);
                    try {
                        Thread.sleep(delay);
                    } catch (InterruptedException e) {
                    }
                }

                try {
                    String commandLine = null;
                    try {
                        commandLine = readLine(s);
                    } catch (SocketException ignore) {
                        Main.error("Failure in accessing a socket", ignore);
                        continue;
                    }

                    if (commandLine == null) {
                        final String msg = "ERR: missing command";
                        writeLine(s, msg);
                        continue;
                    }

                    final int blank = commandLine.indexOf(' ');
                    if (blank < 0) {
                        final String msg = "ERR: missing key";
                        writeLine(s, msg);
                        continue;
                    }

                    if (!secretKey.equals(commandLine.substring(0, blank))) {
                        final String msg = "ERR: wrong key";
                        writeLine(s, msg);
                        delay = (delay > 0) ? delay * 2 : 1000L;
                        continue;
                    }

                    final String command = commandLine.substring(blank + 1);
                    Main.info(s.getRemoteSocketAddress() + ">" + command, null);

                    if (COMMAND_STOP.equals(command)) {
                        if (this.shutdownThread != null) {
                            writeLine(s, RESPONSE_STOPPING);
                        } else {
                            this.shutdownThread = new Thread("Apache Sling Control Listener: Shutdown") {
                                @Override
                                public void run() {
                                    slingMain.doStop();
                                    try {
                                        server.close();
                                    } catch (final IOException ignore) {
                                    }
                                }
                            };
                            this.shutdownThread.start();
                            writeLine(s, RESPONSE_OK);
                        }

                    } else if (COMMAND_STATUS.equals(command)) {
                        writeLine(s, (this.shutdownThread == null) ? RESPONSE_OK : RESPONSE_STOPPING);

                    } else if (COMMAND_THREADS.equals(command)) {
                        dumpThreads(s);

                    } else {
                        final String msg = "ERR:" + command;
                        writeLine(s, msg);

                    }
                } finally {
                    try {
                        s.close();
                    } catch (IOException ignore) {
                    }
                }
            }
        } catch (final IOException ioe) {
            Main.error("Failure reading from client", ioe);
        } finally {
            try {
                server.close();
            } catch (final IOException ignore) {
            }
        }

        getConfigFile().delete();

        // everything has stopped and when this thread terminates,
        // the VM should stop. If there are still some non-daemon threads
        // active, this will not happen, so we force this here ...
        Main.info("Apache Sling terminated, exiting Java VM", null);
        this.slingMain.terminateVM(0);
    }

    // ---------- socket support

    private void dumpThreads(final Socket socket) throws IOException {

        final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
        final ThreadInfo[] threadInfos = threadBean.dumpAllThreads(true, true);

        for (ThreadInfo thread : threadInfos) {
            printThread(socket, thread);

            // add locked synchronizers
            final LockInfo[] locks = thread.getLockedSynchronizers();
            writeLine(socket, "-");
            writeLine(socket, "-   Locked ownable synchronizers:");
            if (locks.length > 0) {
                for (LockInfo li : locks) {
                    writeLine(socket, String.format("-        - locked %s",
                        formatLockInfo(
                            li.getClassName(),
                            li.getIdentityHashCode()
                        )
                    ));
                }
            } else {
                writeLine(socket, "-        - None");
            }

            // empty separator line
            writeLine(socket, "-");
        }

        final long[] deadLocked;
        if (threadBean.isSynchronizerUsageSupported()) {
            deadLocked = threadBean.findDeadlockedThreads();
        } else {
            deadLocked = threadBean.findMonitorDeadlockedThreads();
        }
        if (deadLocked != null) {
            final ThreadInfo[] dl = threadBean.getThreadInfo(deadLocked, true, true);
            final Set<ThreadInfo> dlSet = new HashSet<ThreadInfo>(Arrays.asList(dl));
            int deadlockCount = 0;
            for (ThreadInfo current : dl) {
                if (dlSet.remove(current)) {

                    // find and record a single deadlock
                    ArrayList<ThreadInfo> loop = new ArrayList<ThreadInfo>();
                    do {
                        loop.add(current);
                        for (ThreadInfo cand : dl) {
                            if (cand.getThreadId() == current.getLockOwnerId()) {
                                current = (dlSet.remove(cand)) ? cand : null;
                                break;
                            }
                        }
                    } while (current != null);

                    deadlockCount++;

                    // print the deadlock
                    writeLine(socket, "-Found one Java-level deadlock:");
                    writeLine(socket, "-=============================");
                    for (ThreadInfo thread : loop) {
                        writeLine(socket, String.format("-\"%s\" #%d",
                            thread.getThreadName(),
                            thread.getThreadId()
                        ));
                        writeLine(socket, String.format("-  waiting on %s",
                            formatLockInfo(
                                thread.getLockInfo().getClassName(),
                                thread.getLockInfo().getIdentityHashCode()
                            )
                        ));
                        writeLine(socket, String.format("-  which is held by \"%s\" #%d",
                            thread.getLockOwnerName(),
                            thread.getLockOwnerId()
                        ));
                    }
                    writeLine(socket, "-");

                    writeLine(socket, "-Java stack information for the threads listed above:");
                    writeLine(socket, "-===================================================");

                    for (ThreadInfo thread : loop) {
                        printThread(socket, thread);
                    }
                    writeLine(socket, "-");
                }
            }

//            "Thread-8":
//                waiting to lock monitor 7f89fb80da08 (object 7f37a0968, a java.lang.Object),
//                which is held by "Thread-7"
//              "Thread-7":
//                waiting to lock monitor 7f89fb80b0b0 (object 7f37a0958, a java.lang.Object),
//                which is held by "Thread-8"

            writeLine(socket, String.format("-Found %d deadlocks.",
                deadlockCount
            ));
        }

        writeLine(socket, RESPONSE_OK);
    }

    private String formatLockInfo(final String className, final int objectId) {
        return String.format("<%08x> (a %s)", objectId, className);
    }

    private void printThread(final Socket socket, final ThreadInfo thread) throws IOException {
        writeLine(socket, String.format("-\"%s\" #%d",
            thread.getThreadName(),
            thread.getThreadId()
        ));

        writeLine(socket, String.format("-    java.lang.Thread.State: %s",
            thread.getThreadState()
        ));

        final MonitorInfo[] monitors = thread.getLockedMonitors();
        final StackTraceElement[] trace = thread.getStackTrace();
        for (int i=0; i < trace.length; i++) {
            StackTraceElement ste = trace[i];
            if (ste.isNativeMethod()) {
                writeLine(socket, String.format("-        at %s.%s(Native Method)",
                    ste.getClassName(),
                    ste.getMethodName()
                ));
            } else {
                writeLine(socket, String.format("-        at %s.%s(%s:%d)",
                    ste.getClassName(),
                    ste.getMethodName(),
                    ste.getFileName(),
                    ste.getLineNumber()
                ));
            }

            if (i == 0 && thread.getLockInfo() != null) {
                writeLine(socket, String.format("-        - waiting on %s%s",
                    formatLockInfo(
                        thread.getLockInfo().getClassName(),
                        thread.getLockInfo().getIdentityHashCode()
                    ),
                    (thread.getLockOwnerId() >= 0)
                        ? String.format(" owned by \"%s\" #%d",
                            thread.getLockOwnerName(),
                            thread.getLockOwnerId()
                        ):""
                ));
            }

            for (MonitorInfo mi : monitors) {
                if (i == mi.getLockedStackDepth()) {
                    writeLine(socket, String.format("-        - locked %s",
                        formatLockInfo(
                            mi.getClassName(),
                            mi.getIdentityHashCode()
                        )
                    ));
                }
            }
        }
    }

    /**
     * Sends the given command to the server indicated by the configured
     * socket address and logs the reply.
     *
     * @param command The command to send
     *
     * @return A code indicating success of sending the command.
     */
    private int sendCommand(final String command) {
        if (configure(true)) {
            if (this.secretKey == null) {
                Main.info("Missing secret key to protect sending '" + command + "' to " + this.socketAddress, null);
                return 4; // LSB code for unknown status
            }

            Socket socket = null;
            try {
                socket = new Socket();
                socket.connect(this.socketAddress);
                writeLine0(socket, this.secretKey + " " + command);
                final String result = readLine(socket);
                Main.info("Sent '" + command + "' to " + this.socketAddress + ": " + result, null);
                return 0; // LSB code for everything's fine
            } catch (final ConnectException ce) {
                Main.info("No Apache Sling running at " + this.socketAddress, null);
                return 3; // LSB code for programm not running
            } catch (final IOException ioe) {
                Main.error("Failed sending '" + command + "' to " + this.socketAddress, ioe);
                return 1; // LSB code for programm dead
            } finally {
                if (socket != null) {
                    try {
                        socket.close();
                    } catch (IOException ignore) {
                    }
                }
            }
        }
        Main.info("No socket address to send '" + command + "' to", null);
        return 4; // LSB code for unknown status
    }

    private String readLine(final Socket socket) throws IOException {
        final BufferedReader br = new BufferedReader(new InputStreamReader(
            socket.getInputStream(), "UTF-8"));

        StringBuilder b = new StringBuilder();
        boolean more = true;
        while (more) {
            String s = br.readLine();
            if (s != null && s.startsWith("-")) {
                s = s.substring(1);
            } else {
                more = false;
            }
            if (b.length() > 0) {
                b.append("\r\n");
            }
            b.append(s);
        }

        return b.toString();
    }

    private void writeLine(final Socket socket, final String line) throws IOException {
        Main.info(socket.getRemoteSocketAddress() + "<" + line, null);
        this.writeLine0(socket, line);
    }

    private void writeLine0(final Socket socket, final String line) throws IOException {
        final BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"));
        bw.write(line);
        bw.write("\r\n");
        bw.flush();
    }

    /**
     * Read the port from the config file
     * @return The port or null
     */
    private boolean configure(final boolean fromConfigFile) {
        boolean result = false;
        if (fromConfigFile) {
            final File configFile = this.getConfigFile();
            if (configFile.canRead()) {
                try ( final LineNumberReader lnr = new LineNumberReader(new FileReader(configFile))) {
                    this.socketAddress = getSocketAddress(lnr.readLine());
                    this.secretKey = lnr.readLine();
                    result = true;
                } catch (final IOException ignore) {
                    // ignore
                }
            }
        } else {
            this.socketAddress = getSocketAddress(this.listenSpec);
            this.secretKey = generateKey();
            result = true;
        }

        return result;
    }

    private static String generateKey() {
         return new BigInteger(165, new SecureRandom()).toString(32);
    }

    /**
     * Return the control port file
     */
    private File getConfigFile() {
        final File configDir = new File(this.slingMain.getSlingHome(), "conf");
        return new File(configDir, "controlport");
    }

    private static InetSocketAddress getSocketAddress(String listenSpec) {
        try {

            final String address;
            final int port;
            if (listenSpec == null) {
                address = DEFAULT_LISTEN_INTERFACE;
                port = DEFAULT_LISTEN_PORT;
            } else {
                final int colon = listenSpec.indexOf(':');
                if (colon < 0) {
                    address = DEFAULT_LISTEN_INTERFACE;
                    port = Integer.parseInt(listenSpec);
                } else {
                    address = listenSpec.substring(0, colon);
                    port = Integer.parseInt(listenSpec.substring(colon + 1));
                }
            }

            final InetSocketAddress addr = new InetSocketAddress(address, port);
            if (!addr.isUnresolved()) {
                return addr;
            }

            Main.error("Unknown host in '" + listenSpec, null);
        } catch (final NumberFormatException nfe) {
            Main.error("Cannot parse port number from '" + listenSpec + "'",
                null);
        }

        return null;
    }

    private static void writePortToConfigFile(final File configFile, final InetSocketAddress socketAddress,
            final String secretKey) {
        configFile.getParentFile().mkdirs();
        FileWriter fw = null;
        try {
            fw = new FileWriter(configFile);
            fw.write(socketAddress.getAddress().getHostAddress());
            fw.write(':');
            fw.write(String.valueOf(socketAddress.getPort()));
            fw.write('\n');
            fw.write(secretKey);
            fw.write('\n');
        } catch (final IOException ignore) {
            // ignore
        } finally {
            if (fw != null) {
                try {
                    fw.close();
                } catch (final IOException ignore) {
                }
            }
        }
    }
}
