diff --git a/template_java/.gitignore b/template_java/.gitignore new file mode 100644 index 0000000..c35584b --- /dev/null +++ b/template_java/.gitignore @@ -0,0 +1,32 @@ +# Created by https://www.toptal.com/developers/gitignore/api/java +# Edit at https://www.toptal.com/developers/gitignore?templates=java + +target/ +bin/da_proc.jar + +### Java ### +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +# End of https://www.toptal.com/developers/gitignore/api/java diff --git a/template_java/bin/README b/template_java/bin/README new file mode 100644 index 0000000..ced5c3b --- /dev/null +++ b/template_java/bin/README @@ -0,0 +1 @@ +This is a reserved directory name! Store the binary generated by `build.sh` in this directory diff --git a/template_java/bin/deploy/README b/template_java/bin/deploy/README new file mode 100644 index 0000000..1a2f94d --- /dev/null +++ b/template_java/bin/deploy/README @@ -0,0 +1 @@ +This is a reserved directory name, do not delete or use in your application! diff --git a/template_java/bin/logs/README b/template_java/bin/logs/README new file mode 100644 index 0000000..1a2f94d --- /dev/null +++ b/template_java/bin/logs/README @@ -0,0 +1 @@ +This is a reserved directory name, do not delete or use in your application! diff --git a/template_java/build.sh b/template_java/build.sh new file mode 100755 index 0000000..28a73eb --- /dev/null +++ b/template_java/build.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +set -e + +# Change the current working directory to the location of the present file +cd "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" + +mvn clean compile assembly:single +mv target/da_project-1.0-SNAPSHOT-jar-with-dependencies.jar bin/da_proc.jar diff --git a/template_java/cleanup.sh b/template_java/cleanup.sh new file mode 100755 index 0000000..51b3a48 --- /dev/null +++ b/template_java/cleanup.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +# Change the current working directory to the location of the present file +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" + +rm -f "$DIR"/bin/da_proc.jar +rm -rf "$DIR"/target diff --git a/template_java/pom.xml b/template_java/pom.xml new file mode 100644 index 0000000..ca664cd --- /dev/null +++ b/template_java/pom.xml @@ -0,0 +1,64 @@ + + + + 4.0.0 + + cs451 + da_project + 1.0-SNAPSHOT + + DA_Project + + http://www.example.com + + + UTF-8 + 1.11 + 1.11 + + + + + + + + maven-clean-plugin + 3.1.0 + + 11 + + + + + maven-compiler-plugin + 3.8.1 + + 11 + + + + maven-jar-plugin + 3.2.0 + + 11 + + + + maven-assembly-plugin + + + + cs451.Main + + + + jar-with-dependencies + + + + + + + + diff --git a/template_java/run.sh b/template_java/run.sh new file mode 100755 index 0000000..4f300c7 --- /dev/null +++ b/template_java/run.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +# Change the current working directory to the location of the present file +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" + +ret=0 +exec 3>&1; $(java -jar "$DIR"/bin/da_proc.jar "$@" >&3); ret=$?; exec 3>&- + +exit $ret diff --git a/template_java/src/main/java/cs451/BarrierParser.java b/template_java/src/main/java/cs451/BarrierParser.java new file mode 100644 index 0000000..9f6245c --- /dev/null +++ b/template_java/src/main/java/cs451/BarrierParser.java @@ -0,0 +1,76 @@ +package cs451; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; + +public class BarrierParser { + + private static final String BARRIER_KEY = "--barrier"; + + private static final int BARRIER_ARGS_NUM = 2; + private static final String COLON_REGEX = ":"; + private static final String IP_START_REGEX = "/"; + + private static String ip; + private static int port; + + public boolean populate(String key, String value) { + if (!key.equals(BARRIER_KEY)) { + return false; + } + + String[] barrier = value.split(COLON_REGEX); + if (barrier.length != BARRIER_ARGS_NUM) { + return false; + } + + try { + String ipTest = InetAddress.getByName(barrier[0]).toString(); + if (ipTest.startsWith(IP_START_REGEX)) { + ip = ipTest.substring(1); + } else { + ip = InetAddress.getByName(ipTest.split(IP_START_REGEX)[0]).getHostAddress(); + } + + port = Integer.parseInt(barrier[1]); + if (port <= 0) { + System.err.println("Barrier port must be a positive number!"); + return false; + } + } catch (UnknownHostException e) { + e.printStackTrace(); + } + + return true; + } + + public String getIp() { + return ip; + } + + public int getPort() { + return port; + } + + public static class Barrier { + + public static void waitOnBarrier() { + try (Socket socket = new Socket(ip, port)) { + InputStream input = socket.getInputStream(); + InputStreamReader reader = new InputStreamReader(input); + System.out.println("Accessing barrier..."); + + int character; + while ((character = reader.read()) != -1) {} + } catch (IOException ex) { + System.out.println("I/O error: " + ex.getMessage()); + } + } + + } + +} diff --git a/template_java/src/main/java/cs451/ConfigParser.java b/template_java/src/main/java/cs451/ConfigParser.java new file mode 100644 index 0000000..0f97051 --- /dev/null +++ b/template_java/src/main/java/cs451/ConfigParser.java @@ -0,0 +1,19 @@ +package cs451; + +import java.io.File; + +public class ConfigParser { + + private String path; + + public boolean populate(String value) { + File file = new File(value); + path = file.getPath(); + return true; + } + + public String getPath() { + return path; + } + +} diff --git a/template_java/src/main/java/cs451/Constants.java b/template_java/src/main/java/cs451/Constants.java new file mode 100644 index 0000000..bbba87d --- /dev/null +++ b/template_java/src/main/java/cs451/Constants.java @@ -0,0 +1,26 @@ +package cs451; + +public class Constants { + + public static final int ARG_LIMIT_NO_CONFIG = 8; + public static final int ARG_LIMIT_CONFIG = 9; + + // indexes for id + public static final int ID_KEY = 0; + public static final int ID_VALUE = 1; + + // indexes for hosts + public static final int HOSTS_KEY = 2; + public static final int HOSTS_VALUE = 3; + + // indexes for barrier + public static final int BARRIER_KEY = 4; + public static final int BARRIER_VALUE = 5; + + // indexes for output + public static final int OUTPUT_KEY = 6; + public static final int OUTPUT_VALUE = 7; + + // indexes for config + public static final int CONFIG_VALUE = 8; +} diff --git a/template_java/src/main/java/cs451/Host.java b/template_java/src/main/java/cs451/Host.java new file mode 100644 index 0000000..3c2e360 --- /dev/null +++ b/template_java/src/main/java/cs451/Host.java @@ -0,0 +1,56 @@ +package cs451; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +public class Host { + + private static final String IP_START_REGEX = "/"; + + private int id; + private String ip; + private int port = -1; + + public boolean populate(String idString, String ipString, String portString) { + try { + id = Integer.parseInt(idString); + + String ipTest = InetAddress.getByName(ipString).toString(); + if (ipTest.startsWith(IP_START_REGEX)) { + ip = ipTest.substring(1); + } else { + ip = InetAddress.getByName(ipTest.split(IP_START_REGEX)[0]).getHostAddress(); + } + + port = Integer.parseInt(portString); + if (port <= 0) { + System.err.println("Port in the hosts file must be a positive number!"); + return false; + } + } catch (NumberFormatException e) { + if (port == -1) { + System.err.println("Id in the hosts file must be a number!"); + } else { + System.err.println("Port in the hosts file must be a number!"); + } + return false; + } catch (UnknownHostException e) { + e.printStackTrace(); + } + + return true; + } + + public int getId() { + return id; + } + + public String getIp() { + return ip; + } + + public int getPort() { + return port; + } + +} diff --git a/template_java/src/main/java/cs451/HostsParser.java b/template_java/src/main/java/cs451/HostsParser.java new file mode 100644 index 0000000..d0ebfc2 --- /dev/null +++ b/template_java/src/main/java/cs451/HostsParser.java @@ -0,0 +1,88 @@ +package cs451; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +public class HostsParser { + + private static final String HOSTS_KEY = "--hosts"; + private static final String SPACES_REGEX = "\\s+"; + + private String filename; + private List hosts = new ArrayList<>(); + + public boolean populate(String key, String filename) { + if (!key.equals(HOSTS_KEY)) { + return false; + } + + this.filename = filename; + try(BufferedReader br = new BufferedReader(new FileReader(filename))) { + int lineNum = 1; + for(String line; (line = br.readLine()) != null; lineNum++) { + if (line.isBlank()) { + continue; + } + + String[] splits = line.split(SPACES_REGEX); + if (splits.length != 3) { + System.err.println("Problem with the line " + lineNum + " in the hosts file!"); + return false; + } + + Host newHost = new Host(); + if (!newHost.populate(splits[0], splits[1], splits[2])) { + return false; + } + + hosts.add(newHost); + } + } catch (IOException e) { + System.err.println("Problem with the hosts file!"); + return false; + } + + if (!checkIdRange()) { + System.err.println("Hosts ids are not within the range!"); + return false; + } + + // sort by id + Collections.sort(hosts, new HostsComparator()); + return true; + } + + private boolean checkIdRange() { + int num = hosts.size(); + for (Host host : hosts) { + if (host.getId() < 1 || host.getId() > num) { + System.err.println("Id of a host is not in the right range!"); + return false; + } + } + + return true; + } + + public boolean inRange(int id) { + return id < hosts.size(); + } + + public List getHosts() { + return hosts; + } + + class HostsComparator implements Comparator { + + public int compare(Host a, Host b) { + return a.getId() - b.getId(); + } + + } + +} diff --git a/template_java/src/main/java/cs451/IdParser.java b/template_java/src/main/java/cs451/IdParser.java new file mode 100644 index 0000000..c40260a --- /dev/null +++ b/template_java/src/main/java/cs451/IdParser.java @@ -0,0 +1,31 @@ +package cs451; + +public class IdParser { + + private static final String ID_KEY = "--id"; + + private int id; + + public boolean populate(String key, String value) { + if (!key.equals(ID_KEY)) { + return false; + } + + try { + id = Integer.parseInt(value); + if (id <= 0) { + System.err.println("Id must be a positive number!"); + } + } catch (NumberFormatException e) { + System.err.println("Id must be a number!"); + return false; + } + + return true; + } + + public int getId() { + return id; + } + +} diff --git a/template_java/src/main/java/cs451/Main.java b/template_java/src/main/java/cs451/Main.java new file mode 100644 index 0000000..394c8fa --- /dev/null +++ b/template_java/src/main/java/cs451/Main.java @@ -0,0 +1,53 @@ +package cs451; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.Socket; + +public class Main { + + private static void handleSignal() { + //immediately stop network packet processing + System.out.println("Immediately stopping network packet processing."); + + //write/flush output file if necessary + System.out.println("Writing output."); + } + + private static void initSignalHandlers() { + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + handleSignal(); + } + }); + } + + public static void main(String[] args) { + Parser parser = new Parser(args); + parser.parse(); + + initSignalHandlers(); + + // example + long pid = ProcessHandle.current().pid(); + System.out.println("My PID is " + pid + "."); + System.out.println("Use 'kill -SIGINT " + pid + " ' or 'kill -SIGTERM " + pid + " ' to stop processing packets."); + + System.out.println("My id is " + parser.myId() + "."); + System.out.println("List of hosts is:"); + for (Host host: parser.hosts()) { + System.out.println(host.getId() + ", " + host.getIp() + ", " + host.getPort()); + } + + System.out.println("Barrier: " + parser.barrierIp() + ":" + parser.barrierPort()); + System.out.println("Output: " + parser.output()); + // if config is defined; always check before parser.config() + if (parser.hasConfig()) { + System.out.println("Config: " + parser.config()); + } + + BarrierParser.Barrier.waitOnBarrier(); + } +} diff --git a/template_java/src/main/java/cs451/OutputParser.java b/template_java/src/main/java/cs451/OutputParser.java new file mode 100644 index 0000000..b1a6adc --- /dev/null +++ b/template_java/src/main/java/cs451/OutputParser.java @@ -0,0 +1,25 @@ +package cs451; + +import java.io.File; + +public class OutputParser { + + private static final String OUTPUT_KEY = "--output"; + + private String path; + + public boolean populate(String key, String value) { + if (!key.equals(OUTPUT_KEY)) { + return false; + } + + File file = new File(value); + path = file.getPath(); + return true; + } + + public String getPath() { + return path; + } + +} diff --git a/template_java/src/main/java/cs451/Parser.java b/template_java/src/main/java/cs451/Parser.java new file mode 100644 index 0000000..cff51cf --- /dev/null +++ b/template_java/src/main/java/cs451/Parser.java @@ -0,0 +1,93 @@ +package cs451; + +import java.util.List; + +public class Parser { + + private String[] args; + private long pid; + private IdParser idParser; + private HostsParser hostsParser; + private BarrierParser barrierParser; + private OutputParser outputParser; + private ConfigParser configParser; + + public Parser(String[] args) { + this.args = args; + } + + public void parse() { + pid = ProcessHandle.current().pid(); + + idParser = new IdParser(); + hostsParser = new HostsParser(); + barrierParser = new BarrierParser(); + outputParser = new OutputParser(); + configParser = null; + + int argsNum = args.length; + if (argsNum != Constants.ARG_LIMIT_NO_CONFIG && argsNum != Constants.ARG_LIMIT_CONFIG) { + help(); + } + + if (!idParser.populate(args[Constants.ID_KEY], args[Constants.ID_VALUE])) { + help(); + } + + if (!hostsParser.populate(args[Constants.HOSTS_KEY], args[Constants.HOSTS_VALUE])) { + help(); + } + + if (!hostsParser.inRange(idParser.getId())) { + help(); + } + + if (!barrierParser.populate(args[Constants.BARRIER_KEY], args[Constants.BARRIER_VALUE])) { + help(); + } + + if (!outputParser.populate(args[Constants.OUTPUT_KEY], args[Constants.OUTPUT_VALUE])) { + help(); + } + + if (argsNum == Constants.ARG_LIMIT_CONFIG) { + configParser = new ConfigParser(); + if (!configParser.populate(args[Constants.CONFIG_VALUE])) { + } + } + } + + private void help() { + System.err.println("Usage: --id ID --hosts HOSTS --barier NAME:PORT --output OUTPUT [config]"); + System.exit(1); + } + + public int myId() { + return idParser.getId(); + } + + public List hosts() { + return hostsParser.getHosts(); + } + + public String barrierIp() { + return barrierParser.getIp(); + } + + public int barrierPort() { + return barrierParser.getPort(); + } + + public String output() { + return outputParser.getPath(); + } + + public boolean hasConfig() { + return configParser != null; + } + + public String config() { + return configParser.getPath(); + } + +}