requests-simulator

implemented profile reader (json) session simulator and requests

2/22/2019 4:03:42 AM

Details

pom.xml 20(+20 -0)

diff --git a/pom.xml b/pom.xml
index 515e53c..f6b6ae0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,6 +10,26 @@
         <maven.compiler.source>1.8</maven.compiler.source>
         <maven.compiler.target>1.8</maven.compiler.target>
     </properties>
+    <dependencies>
+        <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+            <version>4.5.7</version>
+        </dependency>
+        <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpmime -->
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpmime</artifactId>
+            <version>4.5.7</version>
+        </dependency>
+        <!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
+        <dependency>
+            <groupId>com.google.code.gson</groupId>
+            <artifactId>gson</artifactId>
+            <version>2.8.5</version>
+        </dependency>
+    </dependencies>
     <build>
         <plugins>
             <plugin>
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 1fb16fa..781ea77 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/Main.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/Main.java
@@ -18,22 +18,30 @@ public class Main {
     public static void main(String[] args) {
         System.setProperty("java.util.logging.SimpleFormatter.format", "[%1$tF %1$tT+%1$tL] [%4$-7s] [RequestsSimulator] %5$s %n");
 
-        String path = null;
+        String profilePath = null;
+        long time = 0;
         int users = 1;
-        if (args.length < 1) {
-            System.err.println("<RequestsPath> [<users>]");
+        if (args.length < 2) {
+            System.err.println("<ProfilePath> <time> [<users>]");
             System.exit(1);
         } else {
-            path = args[0];
-            if (args.length == 2) {
+            profilePath = args[0];
+            try {
+                time = Long.valueOf(args[1]);
+            } catch (NumberFormatException ex) {
+                System.err.println("<time> must be a number");
+                System.exit(1);
+            }
+            if (args.length == 3) {
                 try {
-                    users = Integer.valueOf(args[1]);
+                    users = Integer.valueOf(args[2]);
                 } catch (NumberFormatException ex) {
                     System.err.println("<users> must be a number");
                     System.exit(1);
                 }
             }
         }
-        Simulator.simulate(path, users);
+        Profile profile = ProfileReader.parseFile(profilePath);
+        Simulator.simulate(profile, time, users);
     }
 }
diff --git a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/Profile.java b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/Profile.java
new file mode 100644
index 0000000..3a0b866
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/Profile.java
@@ -0,0 +1,30 @@
+/*
+ * 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 br.ufrgs.inf.prosoft.requestssimulator.requests.RequestPlan;
+import java.util.Collection;
+
+/**
+ *
+ * @author romulo
+ */
+public class Profile {
+
+    private final Collection<RequestPlan> roots;
+
+    public Profile(Collection<RequestPlan> roots) {
+        this.roots = roots;
+    }
+
+    public void run(long time) {
+        long end = System.currentTimeMillis() + time;
+        while (System.currentTimeMillis() < end) {
+            Session session = new Session(this.roots);
+            session.run();
+        }
+    }
+}
diff --git a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/ProfileReader.java b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/ProfileReader.java
new file mode 100644
index 0000000..5f006b0
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/ProfileReader.java
@@ -0,0 +1,59 @@
+/*
+ * 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 br.ufrgs.inf.prosoft.requestssimulator.requests.RequestPlan;
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ *
+ * @author romulo
+ */
+public class ProfileReader {
+
+    public static Profile parseFile(String profilePath) {
+        String fileContent = null;
+        try (Stream<String> lines = Files.lines(Paths.get(profilePath))) {
+            fileContent = lines.collect(Collectors.joining());
+        } catch (IOException ex) {
+            Logger.getLogger(ProfileReader.class.getName()).log(Level.SEVERE, null, ex);
+        }
+        Map<String, RequestPlan> urlHasRequestPlan = new HashMap<>();
+        Gson gson = new Gson();
+        JsonParser jsonParser = new JsonParser();
+        JsonObject jsonObject = jsonParser.parse(fileContent).getAsJsonObject();
+        jsonObject.entrySet().forEach((entry) -> {
+            RequestPlan requestPlan = gson.fromJson(entry.getValue(), RequestPlan.class);
+            urlHasRequestPlan.put(entry.getKey(), requestPlan);
+        });
+        Map<String, RequestPlan> rootsReferences = new HashMap<>(urlHasRequestPlan);
+        urlHasRequestPlan.values().forEach(requestPlan -> {
+            requestPlan.linksReferences().forEach(linkReference -> {
+                RequestPlan reference = urlHasRequestPlan.get(linkReference);
+                if (reference == null) {
+                    throw new RuntimeException("link not declared");
+                }
+                requestPlan.addLink(reference);
+                rootsReferences.remove(linkReference);
+            });
+        });
+        Collection<RequestPlan> roots = rootsReferences.values();
+        Profile profile = new Profile(roots);
+        return profile;
+    }
+}
diff --git a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/GetRequest.java b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/GetRequest.java
new file mode 100644
index 0000000..ed586ca
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/GetRequest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.requests;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ *
+ * @author romulo
+ */
+public class GetRequest extends Request {
+
+    protected GetRequest(RequestPlan requestPlan, String URL) {
+        super(requestPlan, URL);
+    }
+
+    protected GetRequest(RequestPlan requestPlan, String URL, String headers) {
+        super(requestPlan, URL, headers);
+    }
+
+    @Override
+    public void fire() {
+        try {
+            URL url = new URL(getURL());
+            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+            connection.setRequestMethod("GET");
+            getHeaders().forEach((entry) -> {
+                connection.setRequestProperty(entry.getKey(), entry.getValue());
+            });
+            int responseCode = connection.getResponseCode();
+            if (responseCode < 400) {
+                Logger.getGlobal().log(Level.INFO, "{0} {1}", new Object[]{getMethod(), getURL()});
+            } else {
+                Logger.getGlobal().log(Level.SEVERE, "error {0} on {1} {2}", new Object[]{responseCode, getMethod(), getURL()});
+            }
+            connection.disconnect();
+        } catch (MalformedURLException ex) {
+            Logger.getGlobal().log(Level.SEVERE, "Malormed URL");
+        } catch (IOException ex) {
+            Logger.getGlobal().log(Level.SEVERE, "IOException");
+        }
+    }
+
+}
diff --git a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/MultipartRequest.java b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/MultipartRequest.java
new file mode 100644
index 0000000..628f221
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/MultipartRequest.java
@@ -0,0 +1,86 @@
+/*
+ * 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.requests;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.apache.http.HttpEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.mime.MultipartEntityBuilder;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+
+/**
+ *
+ * @author romulo
+ */
+public class MultipartRequest extends Request {
+
+    private final String forms;
+
+    protected MultipartRequest(RequestPlan requestPlan, String URL, String forms) {
+        super(requestPlan, URL);
+        this.forms = forms;
+    }
+
+    protected MultipartRequest(RequestPlan requestPlan, String URL, String headers, String forms) {
+        super(requestPlan, URL, headers);
+        this.forms = forms;
+    }
+
+    public Stream<Map.Entry<String, String>> getForms() {
+        Map<String, String> forms = new HashMap<>();
+        if (this.forms != null) {
+            String[] formsPairs = this.forms.split("; ");
+            for (String formPair : formsPairs) {
+                String[] pair = formPair.split(": ");
+                forms.put(pair[0], pair[1]);
+            }
+        }
+        return forms.entrySet().stream();
+    }
+
+    @Override
+    public void fire() {
+        try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) {
+            HttpPost httpPost = new HttpPost(getURL());
+            MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
+            getForms().forEach(entry -> {
+                if (entry.getKey().equals("file")) {
+                    File value = new File(entry.getValue());
+                    multipartEntityBuilder.addBinaryBody(entry.getKey(), value);
+                } else {
+                    multipartEntityBuilder.addTextBody(entry.getKey(), entry.getValue());
+                }
+            });
+            HttpEntity httpEntity = multipartEntityBuilder.build();
+            httpPost.setEntity(httpEntity);
+            try (CloseableHttpResponse closeableHttpResponse = httpClient.execute(httpPost)) {
+                int responseCode = closeableHttpResponse.getStatusLine().getStatusCode();
+                if (responseCode < 400) {
+                    Logger.getGlobal().log(Level.INFO, "{0} {1}", new Object[]{getMethod(), getURL()});
+                    try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(closeableHttpResponse.getEntity().getContent()))) {
+                        String response = bufferedReader.lines().collect(Collectors.joining());
+                    }
+                } else {
+                    Logger.getGlobal().log(Level.SEVERE, "error {0} on {1} {2}", new Object[]{responseCode, getMethod(), getURL()});
+                }
+            }
+        } catch (IOException e) {
+            Logger.getGlobal().log(Level.SEVERE, "IOException");
+        }
+    }
+
+}
diff --git a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/PostRequest.java b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/PostRequest.java
new file mode 100644
index 0000000..68bb47c
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/PostRequest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.requests;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ *
+ * @author romulo
+ */
+public class PostRequest extends Request {
+
+    private final String data;
+
+    protected PostRequest(RequestPlan requestPlan, String URL, String data) {
+        super(requestPlan, URL);
+        this.data = data;
+    }
+
+    protected PostRequest(RequestPlan requestPlan, String URL, String headers, String data) {
+        super(requestPlan, URL, headers);
+        this.data = data;
+    }
+
+    @Override
+    public void fire() {
+        try {
+            URL url = new URL(getURL());
+            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+            connection.setRequestMethod("POST");
+            connection.setDoOutput(true);
+            try (OutputStream outputStream = connection.getOutputStream()) {
+                outputStream.write(this.data.getBytes());
+            }
+            getHeaders().forEach((entry) -> {
+                connection.setRequestProperty(entry.getKey(), entry.getValue());
+            });
+            int responseCode = connection.getResponseCode();
+            if (responseCode < 400) {
+                Logger.getGlobal().log(Level.INFO, "{0} {1}", new Object[]{getMethod(), getURL()});
+            } else {
+                Logger.getGlobal().log(Level.SEVERE, "error {0} on {1} {2}", new Object[]{responseCode, getMethod(), getURL()});
+            }
+            connection.disconnect();
+        } catch (MalformedURLException ex) {
+            Logger.getGlobal().log(Level.SEVERE, "Malormed URL");
+        } catch (IOException ex) {
+            Logger.getGlobal().log(Level.SEVERE, "IOException");
+        }
+    }
+}
diff --git a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/Request.java b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/Request.java
new file mode 100644
index 0000000..ff8df44
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/Request.java
@@ -0,0 +1,60 @@
+/*
+ * 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.requests;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Stream;
+
+/**
+ *
+ * @author romulo
+ */
+public abstract class Request {
+
+    private final RequestPlan requestPlan;
+    private final String URL;
+    private final String headers;
+    private Map<String, String> storedValues;
+
+    protected Request(RequestPlan requestPlan, String URL) {
+        this.requestPlan = requestPlan;
+        this.URL = URL;
+        this.headers = null;
+    }
+
+    protected Request(RequestPlan requestPlan, String URL, String headers) {
+        this.requestPlan = requestPlan;
+        this.URL = URL;
+        this.headers = headers;
+    }
+
+    public String getMethod() {
+        return this.requestPlan.getMethod();
+    }
+
+    public String getURL() {
+        return this.URL;
+    }
+
+    public Stream<Map.Entry<String, String>> getHeaders() {
+        Map<String, String> headers = new HashMap<>();
+        if (this.headers != null) {
+            String[] headerPairs = this.headers.split("; ");
+            for (String headerPair : headerPairs) {
+                String[] pair = headerPair.split(": ");
+                headers.put(pair[0], pair[1]);
+            }
+        }
+        return headers.entrySet().stream();
+    }
+
+    public Request pickNextRequest() {
+        return this.requestPlan.pickNextRequest();
+    }
+
+    public abstract void fire();
+}
diff --git a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/RequestPlan.java b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/RequestPlan.java
new file mode 100644
index 0000000..ab249dd
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/RequestPlan.java
@@ -0,0 +1,194 @@
+/*
+ * 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.requests;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+import java.util.Random;
+import java.util.stream.Stream;
+
+/**
+ *
+ * @author romulo
+ */
+public class RequestPlan {
+
+    private final String method;
+    private final String URL;
+    private final String data;
+    private Collection<String> linksReferences;
+    private List<RequestPlan> getLinks;
+    private List<RequestPlan> postLinks;
+    private Collection<String> storeFields;
+    private String contentType;
+    private String headers;
+    private String forms;
+
+    private RequestPlan(String URL) {
+        this.method = "GET";
+        this.URL = URL;
+        this.data = null;
+        resetFields();
+    }
+
+    private RequestPlan(String URL, String data) {
+        this.method = "POST";
+        this.URL = URL;
+        this.data = data;
+        resetFields();
+    }
+
+    private void resetFields() {
+        this.contentType = "application/json";
+        this.headers = "";
+        this.forms = "";
+    }
+
+    public static RequestPlan get(String URL) {
+        return new RequestPlan(URL);
+    }
+
+    public static RequestPlan post(String URL, String data) {
+        return new RequestPlan(URL, data);
+    }
+
+    public String getMethod() {
+        return method;
+    }
+
+    public RequestPlan addHeader(String header) {
+        if (this.headers == null || this.headers.isEmpty()) {
+            this.headers = header;
+        } else {
+            this.headers += "; " + header;
+        }
+        return this;
+    }
+
+    public RequestPlan setHeaders(String headers) {
+        this.headers = headers;
+        return this;
+    }
+
+    public RequestPlan addForm(String form) {
+        if (this.method.equals("GET")) {
+            throw new RuntimeException("Adding form to GET request");
+        }
+        if (this.forms == null) {
+            this.forms = form;
+        } else {
+            this.forms += "; " + form;
+        }
+        return this;
+    }
+
+    public RequestPlan setForms(String forms) {
+        if (this.method.equals("GET")) {
+            throw new RuntimeException("Adding form to GET request");
+        }
+        this.forms = forms;
+        return this;
+    }
+
+    public Stream<String> linksReferences() {
+        if (this.linksReferences == null) {
+            return Stream.empty();
+        }
+        return this.linksReferences.stream();
+    }
+
+    public RequestPlan addLink(RequestPlan requestPlan) {
+        if (requestPlan.getMethod().equals("GET")) {
+            if (this.getLinks == null) {
+                this.getLinks = new ArrayList<>();
+            }
+            this.getLinks.add(requestPlan);
+        } else {
+            if (this.postLinks == null) {
+                this.postLinks = new ArrayList<>();
+            }
+            this.postLinks.add(requestPlan);
+        }
+        return this;
+    }
+
+    public RequestPlan addLinks(Collection<RequestPlan> requestPlans) {
+        requestPlans.forEach(requestPlan -> addLink(requestPlan));
+        return this;
+    }
+
+    public RequestPlan setContentType(String contentType) {
+        this.contentType = contentType;
+        return this;
+    }
+
+    public Request pickNextRequest() {
+        Random random = new Random();
+        int probability = random.nextInt(100);
+        if ((this.getLinks == null || this.getLinks.isEmpty()) && (this.postLinks == null || this.postLinks.isEmpty())) {
+            throw new RuntimeException("GET and POST links empty");
+        }
+        RequestPlan chosen;
+        if (this.getLinks == null || this.getLinks.isEmpty()) {
+            probability = 100;
+        } else if (this.postLinks == null || this.postLinks.isEmpty()) {
+            probability = 0;
+        }
+        if (probability < 80) {
+            int chosenIndex = random.nextInt(this.getLinks.size());
+            chosen = this.getLinks.get(chosenIndex);
+        } else {
+            int chosenIndex = random.nextInt(this.postLinks.size());
+            chosen = this.postLinks.get(chosenIndex);
+        }
+        return chosen.build();
+    }
+
+    public Request build() {
+        Random random = new Random();
+        int randomInt = random.nextInt();
+        if (this.URL == null || this.URL.isEmpty()) {
+            throw new RuntimeException("URL is empty");
+        }
+        String URL = this.URL.replace("$", String.valueOf(randomInt));
+        String headers = this.headers;
+        if (this.contentType == null) {
+            this.contentType = "application/json";
+        }
+        if (this.contentType.startsWith("multipart")) {
+            String forms = this.forms;
+            return new MultipartRequest(this, URL, headers, forms);
+        }
+        if (this.method.equals("GET")) {
+            return new GetRequest(this, URL, headers);
+        }
+        String data = this.data;
+        return new PostRequest(this, URL, data, headers);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(this.method, this.URL);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof RequestPlan)) {
+            return false;
+        }
+        RequestPlan other = (RequestPlan) obj;
+        return this.method.equals(other.method) && this.URL.equals(other.URL);
+    }
+
+}
diff --git a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/Session.java b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/Session.java
new file mode 100644
index 0000000..e150663
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/Session.java
@@ -0,0 +1,47 @@
+/*
+ * 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 br.ufrgs.inf.prosoft.requestssimulator.requests.Request;
+import br.ufrgs.inf.prosoft.requestssimulator.requests.RequestPlan;
+import java.util.Collection;
+import java.util.Random;
+
+/**
+ *
+ * @author romulo
+ */
+public class Session {
+
+    private final Collection<RequestPlan> roots;
+
+    public Session(Collection<RequestPlan> roots) {
+        this.roots = roots;
+    }
+
+    public void run() {
+        Random random = new Random();
+        Request request = null;
+        int probability = 0;
+        while (probability < 50) {
+            request = pickNextRequest(request);
+            request.fire();
+            probability = random.nextInt(100);
+        }
+    }
+
+    public Request pickNextRequest(Request currentRequest) {
+        if (currentRequest == null) {
+            if (this.roots == null || this.roots.isEmpty()) {
+                throw new RuntimeException("root within cycle");
+            }
+            currentRequest = RequestPlan.get("root")
+                    .addLinks(this.roots)
+                    .build();
+        }
+        return currentRequest.pickNextRequest();
+    }
+}
diff --git a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/Simulator.java b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/Simulator.java
index f54e11e..3d0a94e 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/Simulator.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/Simulator.java
@@ -5,20 +5,10 @@
  */
 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;
 
 /**
  *
@@ -28,133 +18,25 @@ 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(Profile profile, long time) {
+        simulate(profile, time, 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;
+    public static final void simulate(Profile profile, long time, int users) {
+        Collection<Thread> threads = new ArrayList<>();
+        for (int i = 0; i < users; i++) {
+            Thread thread = new Thread(() -> {
+                profile.run(time);
+            });
+            threads.add(thread);
+            thread.start();
         }
-        long startTime = System.currentTimeMillis();
-        int requestsSize = 1;
-        try {
-            logger.log(Level.INFO, "requesting {0} URLS", requestsSize);
-            if (users == 1) {
-                requestsSize = (int) Files.lines(Paths.get(path)).count();
-                Stream<String> lines = Files.lines(Paths.get(path));
-                startTime = System.currentTimeMillis();
-                lines.forEach(new RequestProcesser());
-            } else {
-                List<String> requests = Files.readAllLines(Paths.get(path));
-                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<>();
-                startTime = System.currentTimeMillis();
-                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);
-        }
-        long endTime = System.currentTimeMillis();
-        long executionTime = startTime - endTime;
-        int milliseconds = (int) (executionTime % 1000);
-        int seconds = (int) (executionTime / 1000) % 60;
-        int minutes = (int) (executionTime / (1000 * 60));
-        double throughput = requestsSize / (double) seconds;
-        System.out.println("Execution Time: " + minutes + ":" + seconds + "." + milliseconds + " minutes");
-        System.out.println("Throughput: " + throughput + " requests per second");
-    }
-
-    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) {
+        threads.forEach((thread) -> {
             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");
+                thread.join();
+            } catch (InterruptedException ex) {
+                Logger.getLogger(Simulator.class.getName()).log(Level.SEVERE, null, ex);
             }
-            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));
-        }
+        });
     }
 }