summaryrefslogtreecommitdiffstats
path: root/dozentenmodul/src/main/java/org/openslx/dozmod/gui/control/AdvancedConfigurator.java
diff options
context:
space:
mode:
authorJonathan Bauer2016-03-03 18:01:37 +0100
committerJonathan Bauer2016-03-03 18:01:37 +0100
commitf6a0867f2d8235a9c38c06dc0702c6e948928bcf (patch)
treebcd38a61059097cf559d6f4b8898628285871fce /dozentenmodul/src/main/java/org/openslx/dozmod/gui/control/AdvancedConfigurator.java
parent[client] add 10px border to wizard's footer (diff)
downloadtutor-module-f6a0867f2d8235a9c38c06dc0702c6e948928bcf.tar.gz
tutor-module-f6a0867f2d8235a9c38c06dc0702c6e948928bcf.tar.xz
tutor-module-f6a0867f2d8235a9c38c06dc0702c6e948928bcf.zip
[client/server] add support for advanced configuration for usb/netrules stuff
Diffstat (limited to 'dozentenmodul/src/main/java/org/openslx/dozmod/gui/control/AdvancedConfigurator.java')
-rw-r--r--dozentenmodul/src/main/java/org/openslx/dozmod/gui/control/AdvancedConfigurator.java351
1 files changed, 351 insertions, 0 deletions
diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/control/AdvancedConfigurator.java b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/control/AdvancedConfigurator.java
new file mode 100644
index 00000000..df036aa3
--- /dev/null
+++ b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/control/AdvancedConfigurator.java
@@ -0,0 +1,351 @@
+package org.openslx.dozmod.gui.control;
+
+import java.awt.Color;
+import java.awt.Insets;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.swing.BorderFactory;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.JTextPane;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.MutableAttributeSet;
+import javax.swing.text.SimpleAttributeSet;
+import javax.swing.text.StyleConstants;
+import javax.swing.text.StyledDocument;
+
+import org.apache.log4j.Logger;
+import org.openslx.bwlp.thrift.iface.NetDirection;
+import org.openslx.bwlp.thrift.iface.NetRule;
+import org.openslx.dozmod.gui.Gui;
+import org.openslx.dozmod.gui.helper.GridManager;
+import org.openslx.dozmod.gui.helper.MessageType;
+
+/**
+ * Widget for advanced configuration options for lectures. This handles
+ * following options - Network rules - Runscript - USB
+ */
+public class AdvancedConfigurator extends AdvancedConfiguratorLayout {
+
+ private static final long serialVersionUID = -3497629601818983994L;
+ private final static Logger LOGGER = Logger
+ .getLogger(AdvancedConfigurator.class);
+
+ /**
+ * Character defining how the rules are parsed, e.g. for whitespace \\s
+ * Example: "IN 8.8.8.8 80"
+ */
+ private static final String FIELD_DELIMITER = "\\s";
+
+ public AdvancedConfigurator() {
+ super();
+ }
+
+ public AdvancedConfiguration getState() {
+ List<NetRule> rules = parseNetRules(taNetworkRules.getText());
+ if (rules != null) {
+ return new AdvancedConfiguration(rules, taRunScript.getText());
+ }
+ return null;
+ }
+
+ public void setState(final AdvancedConfiguration config) {
+ // setText() blanks the text area if null is given, so no null checks
+ this.taNetworkRules.setText(decodeNetRulesToText(config.netRulesList));
+ this.taRunScript.setText(config.runScriptText);
+ }
+
+ public boolean isValidState() {
+ // TODO test state validity?
+ List<NetRule> tmp = parseNetRules(taNetworkRules.getText());
+ if (tmp != null)
+ LOGGER.debug("Parsed: " + tmp.toString());
+ else {
+ LOGGER.debug("Parsed null.");
+ }
+ return tmp != null && !tmp.isEmpty();
+ }
+
+ /**
+ * @param netRulesList
+ * list of NetRule to decode
+ * @return String representation of the list of rules
+ */
+ public static String decodeNetRulesToText(final List<NetRule> netRulesList) {
+ if (netRulesList == null || netRulesList.isEmpty())
+ return "";
+
+ String decodedRules = "";
+ Iterator<NetRule> it = netRulesList.iterator();
+ while (it.hasNext()) {
+ String currentLine = "";
+ NetRule currentRule = it.next();
+ // simple test for validity (since this comes from the server it
+ // should be correct anyways)
+ if (currentRule.host.isEmpty() || currentRule.port > 65535) {
+ LOGGER.error("Invalid rule! Ignoring: " + currentRule.host
+ + ":" + currentRule.port);
+ continue;
+ }
+ currentLine += currentRule.host + " ";
+ currentLine += currentRule.port + " ";
+ currentLine += currentRule.direction.name();
+ decodedRules += currentLine + System.lineSeparator();
+ }
+ return decodedRules;
+ }
+
+ /**
+ * @param rawNetRules
+ * the raw text to be parsed
+ * @return list of valid net rules parsed from the given rawNetRules,
+ * invalid ones are not included
+ * @throws Exception
+ * when parsing fails
+ */
+ public List<NetRule> parseNetRules(final String rawNetRules) {
+ if (rawNetRules == null)
+ return null;
+ List<NetRule> rulesList = new ArrayList<NetRule>();
+ if (rawNetRules.isEmpty()) {
+ return rulesList;
+ }
+ // rawNetRules is the text as entered in the textarea
+ // split it line by line
+ final String[] netRules = rawNetRules.split(System.lineSeparator());
+ for (String ruleLine : netRules) {
+ LOGGER.debug("Parsing rule: " + ruleLine);
+ // split the fields and check if we have 3 as expected.
+ String[] fields = ruleLine.split(FIELD_DELIMITER);
+ if (fields.length != 3) {
+ markText(ruleLine, Color.RED);
+ LOGGER.debug("Invalid number of fields! Expected 3, got: "
+ + fields.length);
+ Gui.showMessageBox(
+ "Nicht genug Felder! Nutzen Sie: <host> <port> [in|out]",
+ MessageType.ERROR, LOGGER, null);
+ break;
+ }
+
+ // start to check fields one by one from the last to the first ....
+ // check net direction: accept either 'in' or 'out' (case
+ // insensitive)
+ if (!fields[2].matches("(?i)^(IN|OUT)+$")) {
+ markText(ruleLine, Color.RED);
+ LOGGER.debug("Invalid net direction! Expected (case insensitive) 'IN' or OUT'. Got: "
+ + fields[2]);
+ Gui.showMessageBox(
+ "Ungültige Richtung: nur 'IN' oder 'OUT' erlaubt!",
+ MessageType.ERROR, LOGGER, null);
+ break;
+ }
+
+ // check port: accept if > -2 and < 65535
+ int port = -2;
+ try {
+ port = Integer.parseInt(fields[1]);
+ } catch (NumberFormatException e) {
+ LOGGER.error("Could not parse '" + fields[1] + "' to an int.");
+ }
+ // TODO: port = -1 for all ports?
+ if (port <= -2 && port > 65535) {
+ markText(ruleLine, Color.RED);
+ LOGGER.debug("Invalid port number! Got: " + port);
+ Gui.showMessageBox(
+ "Ungültiges Port! Muss zwischen 0 und 65536 sein.",
+ MessageType.ERROR, LOGGER, null);
+ break;
+ }
+ // check hostname: bit more to do here
+ // for IPs and/or resolvable hostnames we make use of java.net's
+ // InetAddress.getByName() method which checks the validity of
+ // an IP-Address represented by a string or if the given hostname
+ // is resolvable. If any of these happen, we have a valid hostname.
+ // Non-resolvable hostnames are handled differently, see after the
+ // try/catch-block
+ InetAddress ruleHost = null;
+ try {
+ ruleHost = InetAddress.getByName(fields[0]);
+ } catch (UnknownHostException e) {
+ LOGGER.debug("Invalid hostname (java.net): ", e);
+ // might be good to see this exception in the log file
+ }
+ if (ruleHost == null) {
+ // either invalid IP-Address or an invalid resolvable hostname
+ // however it might also be a non-resolvable hostname that would
+ // be
+ // valid in the actual pool-rooms, so lets check its syntax
+ // according to: http://tools.ietf.org/html/rfc1034#section-3.1
+ LOGGER.debug("Invalid host/IP! Got: " + fields[0]);
+ if (checkHostnameSimple(fields[0])) {
+ markText(ruleLine, Color.YELLOW);
+ if (!Gui.showMessageBox(
+ "Konnte '"
+ + fields[0]
+ + "' nicht verifizieren. Wollen Sie es trotzdem verwenden?",
+ MessageType.WARNING_RETRY, LOGGER, null)) {
+ break;
+ } else {
+ // keep it
+ }
+ } else {
+ markText(ruleLine, Color.RED);
+ continue;
+ }
+ } else {
+ markText(ruleLine, Color.GREEN);
+ }
+ // valid, put it in the list
+ rulesList.add(new NetRule(rulesList.size(), NetDirection
+ .valueOf(fields[2].toUpperCase()), fields[0], port));
+ }
+ if (netRules.length == rulesList.size()) {
+ return rulesList;
+ }
+ return null;
+ }
+
+ private boolean checkHostnameSimple(final String hostname) {
+ if (hostname.length() > 254) {
+ LOGGER.debug("Hostname is too long!");
+ Gui.showMessageBox("Hostname ist zu lang!", MessageType.ERROR,
+ LOGGER, null);
+ return false;
+ }
+ for (int i = 0; i < hostname.length(); i++) {
+ Character c = Character.valueOf(hostname.charAt(i));
+ if (!(Character.isDigit(c) || Character.isLetter(c)
+ || c.equals('-') || c.equals('.') || c.equals('/'))) {
+ LOGGER.debug("Invalid character in hostname: '" + c + "'");
+ Gui.showMessageBox("Ungültiges Zeichen '" + c
+ + "' in hostname!", MessageType.ERROR, LOGGER, null);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // TODO still buggy with text colors: the marking works fine
+ // but when trying to input new text, funny things happen
+ private void markText(final String txt, final Color color) {
+ MutableAttributeSet origSet = taNetworkRules.getInputAttributes();
+ SimpleAttributeSet set = new SimpleAttributeSet();
+ StyleConstants.setForeground(set, color);
+ StyleConstants.setBold(set, color == Color.red);
+ StyledDocument doc = taNetworkRules.getStyledDocument();
+ try {
+ boolean found = false;
+ for (int pos = 0; pos < doc.getLength() - txt.length() + 1; ++pos) {
+ String current = doc.getText(pos, txt.length());
+ if (current.endsWith(System.lineSeparator())) {
+ current = current.substring(0, current.length() - 1);
+ }
+ if (current.equals(txt)) {
+ doc.setCharacterAttributes(pos, txt.length(), set, true);
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ }
+ } catch (BadLocationException e) {
+ LOGGER.error(
+ "Failed to set '" + txt + "' to color " + color.toString(),
+ e);
+ }
+ taNetworkRules.setCharacterAttributes(origSet, true);
+ taNetworkRules.setStyledDocument(doc);
+ }
+
+ /**
+ * Wrapper class for the advanced configuration information needed since we
+ * need to return a single object from the runAndReturn routine
+ */
+ public static class AdvancedConfiguration {
+ public List<NetRule> netRulesList;
+ public String runScriptText;
+
+ public AdvancedConfiguration(List<NetRule> netRulesList,
+ String runScriptText) {
+ this.netRulesList = netRulesList;
+ this.runScriptText = runScriptText;
+ }
+ }
+}
+
+/**
+ * Internal layout class for the advanced configurator (to keep it clean even
+ * for widgets)
+ */
+class AdvancedConfiguratorLayout extends JPanel {
+
+ private static final long serialVersionUID = 648729071828404053L;
+
+ private final static String txtNetworkOptionsTitle = "Netzwerk Einstellungen";
+ private final static String txtNetworkOptionsDesc = "Hier können Sie Firewall-Regeln festlegen mit folgendem Format (TODO)";
+ private final static String txtNetworkRulesTitle = "Netzwerk-Regeln";
+ private final static String txtRunScriptTitle = "Run-Skript";
+ private final static String txtRunScriptDesc = "Ein hier abgelegtes Skript wird beim Start einer Windows-VM automatisch ausgeführt.";
+
+ private final JPanel pnlNetworkOptions;
+ private final JPanel pnlRunScript;
+ protected final JTextPane taNetworkRules;
+ protected final JTextArea taRunScript;
+
+ public AdvancedConfiguratorLayout() {
+
+ GridManager grid = new GridManager(this, 1, true,
+ new Insets(5, 5, 5, 5));
+
+ // middle panel for network rules
+ pnlNetworkOptions = new JPanel();
+ GridManager gridNetworkOptions = new GridManager(pnlNetworkOptions, 1,
+ true, new Insets(2, 2, 2, 2));
+ pnlNetworkOptions.setBorder(BorderFactory
+ .createTitledBorder(txtNetworkOptionsTitle));
+ taNetworkRules = new JTextPane();
+
+ JScrollPane scpNetworkRules = new JScrollPane(taNetworkRules,
+ JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
+ JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+ pnlNetworkOptions.setBorder(BorderFactory
+ .createTitledBorder(txtNetworkRulesTitle));
+ gridNetworkOptions
+ .add(new WordWrapLabel(txtNetworkOptionsDesc, false, true))
+ .fill(true, false).expand(true, false);
+ gridNetworkOptions.nextRow();
+ gridNetworkOptions.add(scpNetworkRules).fill(true, true)
+ .expand(true, true);
+ gridNetworkOptions.finish(false);
+
+ // second middle panel for the run script textpane
+ pnlRunScript = new JPanel();
+ GridManager gridRunScript = new GridManager(pnlRunScript, 1, true,
+ new Insets(2, 2, 2, 2));
+ taRunScript = new JTextArea("", 5, 20);
+ taRunScript.setLineWrap(true);
+ taRunScript.setWrapStyleWord(true);
+ JScrollPane scpRunScript = new JScrollPane(taRunScript,
+ JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
+ JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+ pnlRunScript.setBorder(BorderFactory
+ .createTitledBorder(txtRunScriptTitle));
+ gridRunScript.add(new WordWrapLabel(txtRunScriptDesc, false, true))
+ .fill(true, false).expand(true, false);
+ gridRunScript.nextRow();
+ gridRunScript.add(scpRunScript).fill(true, true).expand(true, true);
+ gridRunScript.finish(false);
+
+ // build the final grid
+ grid.add(pnlNetworkOptions).fill(true, true).expand(true, true);
+ grid.nextRow();
+ grid.add(pnlRunScript).fill(true, true).expand(true, true);
+ grid.finish(false);
+
+ }
+}