/* * 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.maven.projectsupport; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.ConnectException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketAddress; import java.net.UnknownHostException; import org.apache.maven.plugin.logging.Log; /** * This class is adapted from org.apache.sling.launchpad.app.ControlListener. */ 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"; // the response sent by the server if the command executed successfully private static final String RESPONSE_OK = "OK"; // The default port to listen on and to connect to private static final int DEFAULT_LISTEN_PORT = 63000; /** The mojo */ private AbstractLaunchpadStartingMojo mojo; /** The log object */ private final Log log; /** The socket address used for control communication */ private final SocketAddress socketAddress; ControlListener(AbstractLaunchpadStartingMojo mojo, Log log, String host, int port) { this.mojo = mojo; this.log = log; this.socketAddress = getSocketAddress(host, port); } /** * Implements the server side of the control connection starting a thread * listening on the host and port configured on setup of this instance. */ void listen() { if (socketAddress != null) { Thread listener = new Thread(this); listener.setDaemon(true); listener.setName("Sling Control Listener@" + socketAddress); listener.start(); } else { log.info("No socket address to listen to"); } } /** * Implements the client side of the control connection sending the command * to shutdown Sling. */ void shutdownServer() { sendCommand(COMMAND_STOP); } /** * Implements the client side of the control connection sending the command * to check whether Sling is active. */ void statusServer() { sendCommand(COMMAND_STATUS); } // ---------- Runnable interface /** * Implements the server thread receiving commands from clients and acting * upon them. */ public void run() { ServerSocket server = null; try { server = new ServerSocket(); server.bind(socketAddress); log.info("Sling Control Server started on " + socketAddress.toString()); } catch (IOException ioe) { log.error("Failed to start Sling Control Server", ioe); return; } try { while (true) { Socket s = server.accept(); try { String command = readLine(s); log.info(s.getRemoteSocketAddress() + ">" + command); if (COMMAND_STOP.equals(command)) { if (mojo != null) { mojo.stopSling(); } writeLine(s, RESPONSE_OK); log.info("Sling shut down, stopping Sling."); mojo.stopSling(); } else if (COMMAND_STATUS.equals(command)) { writeLine(s, RESPONSE_OK); } else { writeLine(s, "ERR:" + command); } } finally { try { s.close(); } catch (IOException ignore) { } } } } catch (IOException ioe) { log.error("Failure reading from client", ioe); } finally { try { server.close(); } catch (IOException ignore) { } } } // ---------- socket support private SocketAddress getSocketAddress(String host, int port) { try { if (port == -1) { port = DEFAULT_LISTEN_PORT; } if (host != null) { return new InetSocketAddress(host, port); } else { return new InetSocketAddress(InetAddress.getLocalHost(), port); } } catch (UnknownHostException uhe) { log.error("Unknown host in '" + host + "': " + uhe.getMessage(), null); } return null; } private void sendCommand(String command) { if (socketAddress != null) { Socket socket = null; try { socket = new Socket(); socket.connect(socketAddress); writeLine(socket, command); String result = readLine(socket); log.info("Sent '" + command + "' to " + socketAddress + ": " + result, null); } catch (ConnectException ce) { log.info("No Sling running at " + socketAddress, null); } catch (IOException ioe) { log.error("Failed sending '" + command + "' to " + socketAddress, ioe); } finally { if (socket != null) { try { socket.close(); } catch (IOException ignore) { } } } } else { log.info("No socket address to send '" + command + "' to", null); } } private String readLine(Socket socket) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8")); return br.readLine(); } private void writeLine(Socket socket, String line) throws IOException { BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8")); bw.write(line); bw.write("\r\n"); bw.flush(); } }