requests-simulator

added multi-threaded simulation

12/12/2018 5:43:31 AM

Details

diff --git a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/Main.java b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/Main.java
index 28dc131..1fb16fa 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/Main.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/Main.java
@@ -5,17 +5,7 @@
  */
 package br.ufrgs.inf.prosoft.requestssimulator;
 
-import java.io.IOException;
-import java.io.OutputStream;
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.util.function.Consumer;
-import java.util.logging.Level;
 import java.util.logging.Logger;
-import java.util.stream.Stream;
 
 /**
  *
@@ -29,60 +19,21 @@ public class Main {
         System.setProperty("java.util.logging.SimpleFormatter.format", "[%1$tF %1$tT+%1$tL] [%4$-7s] [RequestsSimulator] %5$s %n");
 
         String path = null;
+        int users = 1;
         if (args.length < 1) {
-            System.err.println("<RequestsPath>");
+            System.err.println("<RequestsPath> [<users>]");
             System.exit(1);
         } else {
             path = args[0];
-        }
-
-        try (Stream<String> lines = Files.lines(Paths.get(path))) {
-            long count = Files.lines(Paths.get(path)).count();
-            logger.log(Level.INFO, "requesting {0} URLS", count);
-            lines.forEach(new Consumer<String>() {
-                private int i = 1;
-
-                @Override
-                public void accept(String line) {
-                    try {
-                        if (line.startsWith("POST")) {
-                            String[] split = line.split(" ");
-                            URL url = new URL(split[1]);
-                            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
-                            connection.setRequestMethod("POST");
-                            connection.setDoOutput(true);
-                            try (OutputStream outputStream = connection.getOutputStream()) {
-                                outputStream.write(split[2].getBytes());
-                            }
-                            int responseCode = connection.getResponseCode();
-                            if (responseCode == 200) {
-                                logger.log(Level.INFO, "{0} {1}", new Object[]{i, line});
-                            } else {
-                                logger.log(Level.SEVERE, "{0} error {1} on {2}", new Object[]{i, responseCode, line});
-                            }
-                            connection.disconnect();
-                        } else {
-                            URL url = new URL(line);
-                            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
-                            connection.setRequestMethod("GET");
-                            int responseCode = connection.getResponseCode();
-                            if (responseCode == 200) {
-                                logger.log(Level.INFO, "{0} GET {1}", new Object[]{i, line});
-                            } else {
-                                logger.log(Level.SEVERE, "{0} error {1} on {2}", new Object[]{i, responseCode, line});
-                            }
-                            connection.disconnect();
-                        }
-                    } catch (MalformedURLException ex) {
-                        logger.log(Level.SEVERE, "Malormed URL");
-                    } catch (IOException ex) {
-                        logger.log(Level.SEVERE, "IOException");
-                    }
-                    i++;
+            if (args.length == 2) {
+                try {
+                    users = Integer.valueOf(args[1]);
+                } catch (NumberFormatException ex) {
+                    System.err.println("<users> must be a number");
+                    System.exit(1);
                 }
-            });
-        } catch (IOException ex) {
-            logger.log(Level.SEVERE, "cannot open file {0}", path);
+            }
         }
+        Simulator.simulate(path, users);
     }
 }
diff --git a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/Simulator.java b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/Simulator.java
new file mode 100644
index 0000000..fb67c0a
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/Simulator.java
@@ -0,0 +1,148 @@
+/*
+ * 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.requestssimulator;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.stream.Stream;
+
+/**
+ *
+ * @author romulo
+ */
+public class Simulator {
+
+    private static final Logger logger = Logger.getLogger(Simulator.class.getName());
+
+    public static final void simulate(String path) {
+        simulate(path, 1);
+    }
+
+    public static final void simulate(String path, int users) {
+        if (users < 1) {
+            logger.log(Level.SEVERE, "informed {0} users. Using 1", users);
+            users = 1;
+        }
+        try {
+            long count = Files.lines(Paths.get(path)).count();
+            logger.log(Level.INFO, "requesting {0} URLS", count);
+            if (users == 1) {
+                Stream<String> lines = Files.lines(Paths.get(path));
+                lines.forEach(new RequestProcesser());
+            } else {
+                List<String> requests = Files.readAllLines(Paths.get(path));
+                int requestsSize = requests.size();
+                int inclusiveStart = 0;
+                int partitionSize = requestsSize / users;
+                if (partitionSize < 1) {
+                    partitionSize = 1;
+                    logger.log(Level.SEVERE, "more users {0} than requests {1}. Using {1} users", new Object[]{users, requests.size()});
+                }
+                Collection<Thread> threads = new ArrayList<>();
+                while (inclusiveStart < requestsSize) {
+                    int exclusiveEnd = inclusiveStart + partitionSize;
+                    Thread thread = new Thread(new PartitionProcesser(requests, inclusiveStart, exclusiveEnd));
+                    thread.start();
+                    threads.add(thread);
+                    inclusiveStart = exclusiveEnd;
+                }
+                threads.forEach(thread -> {
+                    try {
+                        thread.join();
+                    } catch (InterruptedException ex) {
+                        logger.log(Level.SEVERE, "thread stopped");
+                    }
+                });
+            }
+        } catch (IOException ex) {
+            logger.log(Level.SEVERE, "cannot open file {0}", path);
+        }
+    }
+
+    private static class RequestProcesser implements Consumer<String> {
+
+        private int i;
+
+        public RequestProcesser() {
+            this.i = 1;
+        }
+
+        public RequestProcesser(int i) {
+            this.i = i;
+        }
+
+        @Override
+        public void accept(String line) {
+            try {
+                if (line.startsWith("POST")) {
+                    String[] split = line.split(" ");
+                    URL url = new URL(split[1]);
+                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+                    connection.setRequestMethod("POST");
+                    connection.setDoOutput(true);
+                    try (OutputStream outputStream = connection.getOutputStream()) {
+                        outputStream.write(split[2].getBytes());
+                    }
+                    int responseCode = connection.getResponseCode();
+                    if (responseCode == 200) {
+                        logger.log(Level.INFO, "{0} {1}", new Object[]{i, line});
+                    } else {
+                        logger.log(Level.SEVERE, "{0} error {1} on {2}", new Object[]{i, responseCode, line});
+                    }
+                    connection.disconnect();
+                } else {
+                    URL url = new URL(line);
+                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+                    connection.setRequestMethod("GET");
+                    int responseCode = connection.getResponseCode();
+                    if (responseCode == 200) {
+                        logger.log(Level.INFO, "{0} GET {1}", new Object[]{i, line});
+                    } else {
+                        logger.log(Level.SEVERE, "{0} error {1} on {2}", new Object[]{i, responseCode, line});
+                    }
+                    connection.disconnect();
+                }
+            } catch (MalformedURLException ex) {
+                logger.log(Level.SEVERE, "Malormed URL");
+            } catch (IOException ex) {
+                logger.log(Level.SEVERE, "IOException");
+            }
+            i++;
+        }
+    }
+
+    private static class PartitionProcesser implements Runnable {
+
+        private final Stream<String> requests;
+        private final int inclusiveStart;
+
+        public PartitionProcesser(List<String> requests, int incusiveStart, int exclusiveEnd) {
+            this.inclusiveStart = incusiveStart;
+            this.requests = requests.subList(incusiveStart, exclusiveEnd).stream();
+        }
+
+        public PartitionProcesser(Stream<String> requests) {
+            this.requests = requests;
+            this.inclusiveStart = 1;
+        }
+
+        @Override
+        public void run() {
+            this.requests.forEach(new RequestProcesser(this.inclusiveStart + 1));
+        }
+    }
+}