Server.java

189 lines | 7.448 kB Blame History Raw Download
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package br.ufrgs.inf.prosoft.remoteexecutor;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;

/**
 *
 * @author romulo
 */
public class Server {

    private static final Logger LOGGER = Logger.getLogger(Server.class.getName());

    private static class Tokenizer {

        private int index;
        private final String string;

        public Tokenizer(String string) {
            this.index = 0;
            this.string = string;
        }

        public static List<String> split(String string) {
            Tokenizer tokenizer = new Tokenizer(string);
            List<String> list = new ArrayList<>();
            while (tokenizer.hasMoreTokens()) {
                list.add(tokenizer.getNextToken());
            }
            return list;
        }

        private boolean hasMoreTokens() {
            if (this.string == null) {
                return false;
            }
            if (this.string.isEmpty()) {
                return false;
            }
            return this.index < string.length();
        }

        private String getNextToken() {
            if (!hasMoreTokens()) {
                return null;
            }
            while (this.index < this.string.length() && this.string.charAt(this.index) == ' ') {
                this.index++;
            }
            char quoted = ' ';
            int baseIndex = this.index;
            while (this.index < this.string.length()) {
                char nextChar = this.string.charAt(this.index);
                if (nextChar == ' ' && quoted == ' ') {
                    break;
                }
                this.index++;
                if (nextChar == '\'' || nextChar == '\"') {
                    if (quoted == ' ') {
                        quoted = nextChar;
                    } else if (nextChar == quoted) {
                        break;
                    }
                }
            }
            return this.string.substring(baseIndex, this.index);
        }
    }

    public static void listen(File home, int port) {
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(port);
            LOGGER.log(Level.INFO, "start listening on port " + port);
            boolean exit = false;
            while (!exit) {
                Socket socket = null;
                InputStream inputStream = null;
                OutputStream outputStream = null;
                try {
                    socket = serverSocket.accept();
                    inputStream = socket.getInputStream();
                    InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
                    BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
                    String message = bufferedReader.readLine();
                    if (message == null) {
                        message = "";
                    }
                    LOGGER.log(Level.INFO, "> {0}", message);
                    if (message.startsWith("caching-approaches-comparison ")) {
                        String command = message.replaceFirst("caching-approaches-comparison ", "");
                        if (command.equals("exit")) {
                            exit = true;
                        } else {
                            try {
                                ProcessBuilder processBuilder = new ProcessBuilder();
                                processBuilder.directory(home);
                                List<String> commandList = Tokenizer.split(command)
                                        .stream().map(string -> {
                                            if (string.charAt(0) == '\"' || string.charAt(0) == '\'') {
                                                string = string.substring(1, string.length());
                                            }
                                            if (string.charAt(string.length()- 1) == '\"' || string.charAt(string.length()- 1) == '\'') {
                                                string = string.substring(0, string.length()- 1);
                                            }
                                            return string;
                                        }).collect(Collectors.toList());
                                for (Iterator<String> iterator = commandList.iterator(); iterator.hasNext();) {
                                    String export = iterator.next();
                                    if (!export.contains("=")) {
                                        break;
                                    }
                                    String[] map = export.split("=");
                                    if (map.length > 1) {
                                        processBuilder.environment().put(map[0], map[1]);
                                    } else {
                                        processBuilder.environment().put(map[0], "");
                                    }
                                    iterator.remove();
                                }
                                processBuilder.command(commandList);
                                processBuilder.inheritIO();
                                processBuilder.start();
                            } catch (Exception ex) {
                                LOGGER.log(Level.WARNING, ex.getMessage());
                                message = "command failed";
                            }
                        }
                    }
                    message = "[RemoteExecutor] " + message;
                    LOGGER.log(Level.INFO, "< {0}", message);
                    message += "\n";
                    outputStream = socket.getOutputStream();
                    outputStream.write(message.getBytes());
                } catch (IOException ex) {
                    LOGGER.log(Level.WARNING, "connection closed before echo is sent");
                } catch (Exception ex) {
                    LOGGER.log(Level.WARNING, "exception: {0}", ex);
                } finally {
                    if (inputStream != null) {
                        try {
                            inputStream.close();
                        } catch (IOException ex) {
                        }
                    }
                    if (outputStream != null) {
                        try {
                            outputStream.close();
                        } catch (IOException ex) {
                        }
                    }
                    if (socket != null) {
                        try {
                            socket.close();
                        } catch (IOException ex) {
                        }
                    }
                }
            }
        } catch (IOException ex) {
            LOGGER.log(Level.SEVERE, "port " + port + " is busy");
        } finally {
            if (serverSocket != null) {
                try {
                    serverSocket.close();
                } catch (IOException ex) {
                }
            }
        }
    }
}