Java tutorial
/* * DoomManager * Copyright (C) 2014 Chris K * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package ca.wumbo.doommanager.client.controller; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.StringSelection; import java.net.InetSocketAddress; import java.nio.channels.SelectionKey; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Optional; import javax.annotation.PostConstruct; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import ca.wumbo.doommanager.Start; import ca.wumbo.doommanager.client.util.Controllable; import ca.wumbo.doommanager.client.util.SelfInjectableController; import ca.wumbo.doommanager.net.NetworkReceiver; import ca.wumbo.doommanager.net.NetworkSelector; import ca.wumbo.doommanager.server.Server; import ca.wumbo.doommanager.server.ServerManager; import javafx.application.Platform; import javafx.fxml.FXML; import javafx.scene.control.TextArea; import javafx.scene.control.TextField; import javafx.scene.input.KeyCode; import javafx.scene.layout.BorderPane; import javafx.scene.layout.Pane; /** * The controller for the console, which accepts text and allows the user to * issue commands. */ public class ConsoleController extends SelfInjectableController implements Controllable { /** * The max amount of commands to remember. */ public static final int MAX_COMMANDS_REMEMBERED = 128; /** * The pointer to the last command the user was at. */ private int commandBufferIndex = 0; /** * Contains a list of sent commands that can be recalled by pressing the up * arrow. */ private ArrayList<String> commandBuffer = new ArrayList<>(MAX_COMMANDS_REMEMBERED); @Autowired private CoreController coreController; @Autowired private ServerManager serverManager; @Autowired private NetworkSelector clientSelector; @Value("${console.controller.fxmlpath}") private String fxmlPath; @Value("${doommanager.title}") private String applicationTitle; @Value("${doommanager.version}") private String applicationVersion; //========================================================================= @FXML private BorderPane rootBorderPane; @FXML private TextArea textArea; @FXML private TextField textField; //========================================================================= /** * The logger for this class. */ private static final Logger log = LogManager.getLogger(ConsoleController.class); /** * Only to be instantiated by Spring. */ private ConsoleController() { } /** * Loads the FXML data and injects it into this object. Should be called by * Spring right after the constructor and dependencies are linked. To * reduce code duplication, this functionality was moved to a containing * class. * * @throws NullPointerException * If the FXML path is null. * * @throws RuntimeException * If the FXML file is missing or corrupt. */ @PostConstruct public void loadFXML() { super.loadFXML(fxmlPath); } @FXML private void initialize() { textField.setOnKeyPressed(event -> { // Submit any text on enter. if (event.getCode().equals(KeyCode.ENTER)) submitLineToConsole(); // If we press up/down, look for lines we stored. if (event.getCode().equals(KeyCode.UP) || event.getCode().equals(KeyCode.DOWN)) { if (commandBuffer.size() > 0) { commandBufferIndex += (event.getCode().equals(KeyCode.UP) ? -1 : 1); commandBufferIndex = Math.min(Math.max(0, commandBufferIndex), commandBuffer.size()); textField.setText(commandBufferIndex == commandBuffer.size() ? "" : commandBuffer.get(commandBufferIndex)); textField.end(); event.consume(); // Has to be consumed or else it will mess up the end() caret setting. } else { textField.setText(""); } } }); } /** * Takes whatever is in the text field and submits it. */ private void submitLineToConsole() { // Trim the string before using, also nulls shouldn't happen (but just in case). String text = textField.getText().trim().replace('\0', '?'); // Ignore empty lines. if (text.isEmpty()) return; // Remember what we submitted, most recent goes first. commandBuffer.add(text); // Reset due to submission of text. commandBufferIndex = commandBuffer.size(); // Handle commands. switch (text.toLowerCase()) { case "clear": textArea.clear(); break; case "connect": // Note: Debugging only. textArea.appendText("Starting connection to local host..." + System.lineSeparator()); Optional<SelectionKey> key = clientSelector.openTCPConnection( new InetSocketAddress("localhost", Server.DEFAULT_LISTEN_PORT), new NetworkReceiver() { @Override public void signalConnectionTerminated() { System.out.println("Test connection killed."); } @Override public void receiveData(byte[] data) { System.out.println("Got data: " + data.length + " = " + Arrays.toString(data)); } }); if (key.isPresent()) { SelectionKey k = key.get(); Platform.runLater(() -> { try { Thread.sleep(2000); clientSelector.writeData(k, new byte[] { 1, 2 }); System.out.println("Go forth..."); } catch (Exception e) { System.err.println("UGH"); e.printStackTrace(); } }); } textArea.appendText("Connection made = " + key.isPresent() + System.lineSeparator()); break; case "copy": try { Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); StringSelection stringSelection = new StringSelection(textArea.getText()); clipboard.setContents(stringSelection, stringSelection); textArea.appendText("Copied to clipboard." + System.lineSeparator()); } catch (Exception e) { textArea.appendText("Error: Unable to get system clipboard." + System.lineSeparator()); } break; case "exit": coreController.exit(); break; case "getconnections": int numKeys = clientSelector.getNumConnections(); textArea.appendText("There " + (numKeys != 1 ? "are " : "is ") + numKeys + " key" + (numKeys != 1 ? "s." : ".") + System.lineSeparator()); break; case "help": textArea.appendText("Commands:" + System.lineSeparator()); textArea.appendText(" clear - Clears the console" + System.lineSeparator()); textArea.appendText(" copy - Copies all the content to your clipboard" + System.lineSeparator()); textArea.appendText(" exit - Exits the program" + System.lineSeparator()); textArea.appendText(" getconnections - Lists the connections available" + System.lineSeparator()); textArea.appendText(" help - Shows this help" + System.lineSeparator()); textArea.appendText(" history - Prints command history for " + MAX_COMMANDS_REMEMBERED + " entries" + System.lineSeparator()); textArea.appendText(" memory - Get current memory statistics" + System.lineSeparator()); textArea.appendText(" version - Gets the version information" + System.lineSeparator()); break; case "history": if (commandBuffer.size() <= 1) { textArea.appendText("No history to display" + System.lineSeparator()); break; } textArea.appendText("History:" + System.lineSeparator()); for (int i = 0; i < commandBuffer.size() - 1; i++) textArea.appendText(" " + commandBuffer.get(i) + System.lineSeparator()); // Print everything but the last command (which was this). break; case "memory": NumberFormat nf = NumberFormat.getInstance(); nf.setMaximumFractionDigits(2); nf.setMinimumFractionDigits(2); long totalMem = Runtime.getRuntime().totalMemory(); long usedMem = totalMem - Runtime.getRuntime().freeMemory(); long maxMem = Runtime.getRuntime().maxMemory(); double megabyte = 1024.0 * 1024.0; textArea.appendText("Memory statistics:" + System.lineSeparator()); textArea.appendText( " Memory used: " + nf.format(Math.abs(((double) usedMem / (double) maxMem)) * 100.0) + "%" + System.lineSeparator()); textArea.appendText( " " + nf.format(usedMem / megabyte) + " mb (used memory)" + System.lineSeparator()); textArea.appendText( " " + nf.format(maxMem / megabyte) + " mb (max memory)" + System.lineSeparator()); break; // DEBUG case "startserver": if (Start.getParsedRuntimeArgs().isClientServer()) { if (!serverManager.isInitialized()) { try { textArea.appendText("Starting server on port " + Server.DEFAULT_LISTEN_PORT + "." + System.lineSeparator()); serverManager.initialize(); } catch (Exception e) { textArea.appendText("Unable to initialize server." + System.lineSeparator()); textArea.appendText(" " + e.getMessage() + System.lineSeparator()); } } if (serverManager.isInitialized()) { if (!serverManager.isRunning()) { textArea.appendText("Running server on port " + Server.DEFAULT_LISTEN_PORT + "." + System.lineSeparator()); try { new Thread(serverManager, "ClientConsoleServer").start(); textArea.appendText("Successfully set up server." + System.lineSeparator()); } catch (Exception e) { textArea.appendText("Error setting up server:" + System.lineSeparator()); textArea.appendText(" " + e.getMessage() + System.lineSeparator()); } } else { textArea.appendText("Server is already running." + System.lineSeparator()); } } else { textArea.appendText("Server not initialized, cannot run." + System.lineSeparator()); } } break; // DEBUG case "stopserver": if (Start.getParsedRuntimeArgs().isClientServer()) { if (serverManager.isInitialized() && serverManager.isRunning()) { serverManager.requestServerTermination(); textArea.appendText("Requested server termination." + System.lineSeparator()); } else { textArea.appendText( "Cannot stop server, it has not been initialized or started." + System.lineSeparator()); } } break; case "version": textArea.appendText(applicationTitle + " version: " + applicationVersion + System.lineSeparator()); break; default: textArea.appendText("Unknown command: " + text + System.lineSeparator()); textArea.appendText("Type 'help' for commands" + System.lineSeparator()); break; } textField.clear(); } /** * Adds text to the textbox. * * @param text * The text to add. This should not be null (if so, a warning will be * emitted) and will be discarded if it is. */ public void addText(String text) { if (text == null) { log.warn("Passed a null text log message to the console."); return; } textArea.appendText(text + System.lineSeparator()); } @Override public Pane getRootPane() { return rootBorderPane; } }