requests-simulator

Details

diff --git a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/LogExecutor.java b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/LogExecutor.java
new file mode 100644
index 0000000..24cb842
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/LogExecutor.java
@@ -0,0 +1,89 @@
+/*
+ * 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.GetRequest;
+import br.ufrgs.inf.prosoft.requestssimulator.requests.PostRequest;
+import br.ufrgs.inf.prosoft.requestssimulator.requests.Request;
+import br.ufrgs.inf.prosoft.requestssimulator.requests.RequestPlan;
+import com.google.gson.Gson;
+import com.google.gson.JsonParser;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ *
+ * @author romulo
+ */
+public class LogExecutor {
+
+    public static void execute(Profile profile, String tracePath) {
+        String fileContent = null;
+        try (Stream<String> lines = Files.lines(Paths.get(tracePath))) {
+            fileContent = lines.collect(Collectors.joining());
+        } catch (IOException ex) {
+            Logger.getLogger(ProfileReader.class.getName()).log(Level.SEVERE, null, ex);
+        }
+        JsonParser jsonParser = new JsonParser();
+        Collection<Thread> threads = new ArrayList<>();
+        JsonElement parse = jsonParser.parse(fileContent);
+        JsonArray users = parse
+                .getAsJsonArray();
+        Gson gson = new Gson();
+        users.forEach(user -> {
+            Thread thread = new Thread(() -> {
+                JsonArray sessions = user.getAsJsonArray();
+                Session session = profile.newSession();
+                sessions.forEach(sessionExecution -> {
+                    JsonArray requests = sessionExecution.getAsJsonArray();
+                    requests.forEach(requestJson -> {
+                        JsonObject jsonObject = requestJson.getAsJsonObject();
+                        String method = jsonObject.get("method").getAsString();
+                        String requestPlanReference = method;
+                        requestPlanReference += "@";
+                        requestPlanReference += jsonObject.get("URL").getAsString();
+                        RequestPlan requestPlan = profile.getRequestPlan(requestPlanReference);
+                        if (requestPlan == null) {
+                            throw new RuntimeException("Request Plan not found");
+                        }
+                        Request request;
+                        if (method.equals("GET")) {
+                            request = gson.fromJson(jsonObject, GetRequest.class);
+                        } else {
+                            JsonElement headers = jsonObject.get("headers");
+                            if (headers != null && headers.getAsString().contains("multipart")) {
+                                request = gson.fromJson(jsonObject, MultipartRequest.class);
+                            } else {
+                                request = gson.fromJson(jsonObject, PostRequest.class);
+                            }
+                        }
+                        request = requestPlan.bind(request, session);
+                        request.fire();
+                    });
+                });
+            });
+            threads.add(thread);
+            thread.start();
+        });
+        threads.forEach((thread) -> {
+            try {
+                thread.join();
+            } catch (InterruptedException ex) {
+                Logger.getLogger(Simulator.class.getName()).log(Level.SEVERE, null, ex);
+            }
+        });
+    }
+}
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 781ea77..298f780 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/Main.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/Main.java
@@ -19,18 +19,24 @@ public class Main {
         System.setProperty("java.util.logging.SimpleFormatter.format", "[%1$tF %1$tT+%1$tL] [%4$-7s] [RequestsSimulator] %5$s %n");
 
         String profilePath = null;
+        String tracePath = null;
         long time = 0;
         int users = 1;
         if (args.length < 2) {
             System.err.println("<ProfilePath> <time> [<users>]");
+            System.err.println("<ProfilePath> <TracePath>");
             System.exit(1);
         } else {
             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) {
+                    System.err.println("<time> must be a number");
+                    System.exit(1);
+                } else {
+                    tracePath = args[1];
+                }
             }
             if (args.length == 3) {
                 try {
@@ -42,6 +48,10 @@ public class Main {
             }
         }
         Profile profile = ProfileReader.parseFile(profilePath);
-        Simulator.simulate(profile, time, users);
+        if (tracePath == null) {
+            Simulator.simulate(profile, time, users);
+        } else {
+            LogExecutor.execute(profile, tracePath);
+        }
     }
 }
diff --git a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/Profile.java b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/Profile.java
index 3a0b866..77dfb01 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/Profile.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/Profile.java
@@ -7,6 +7,8 @@ package br.ufrgs.inf.prosoft.requestssimulator;
 
 import br.ufrgs.inf.prosoft.requestssimulator.requests.RequestPlan;
 import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  *
@@ -15,9 +17,25 @@ import java.util.Collection;
 public class Profile {
 
     private final Collection<RequestPlan> roots;
+    private final Map<String, RequestPlan> urlHasRequestPlan;
 
-    public Profile(Collection<RequestPlan> roots) {
-        this.roots = roots;
+    public Profile(Map<String, RequestPlan> urlHasRequestPlan) {
+        this.urlHasRequestPlan = urlHasRequestPlan;
+        Map<String, RequestPlan> rootsReferences = new HashMap<>(this.urlHasRequestPlan);
+        this.urlHasRequestPlan.values().forEach(requestPlan -> {
+            requestPlan.linksReferences().forEach(linkReference -> {
+                rootsReferences.remove(linkReference);
+            });
+        });
+        this.roots = rootsReferences.values();
+    }
+
+    public Session newSession() {
+        return new Session(this.roots);
+    }
+
+    public RequestPlan getRequestPlan(String requestPlanReference) {
+        return this.urlHasRequestPlan.get(requestPlanReference);
     }
 
     public void run(long time) {
diff --git a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/ProfileReader.java b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/ProfileReader.java
index 5f006b0..676c68c 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/ProfileReader.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/ProfileReader.java
@@ -12,7 +12,6 @@ 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;
@@ -52,8 +51,7 @@ public class ProfileReader {
                 rootsReferences.remove(linkReference);
             });
         });
-        Collection<RequestPlan> roots = rootsReferences.values();
-        Profile profile = new Profile(roots);
+        Profile profile = new Profile(urlHasRequestPlan);
         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
index ed586ca..28471e6 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/GetRequest.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/GetRequest.java
@@ -5,12 +5,16 @@
  */
 package br.ufrgs.inf.prosoft.requestssimulator.requests;
 
+import br.ufrgs.inf.prosoft.requestssimulator.Session;
+import java.io.BufferedReader;
 import java.io.IOException;
+import java.io.InputStreamReader;
 import java.net.HttpURLConnection;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.logging.Level;
 import java.util.logging.Logger;
+import java.util.stream.Collectors;
 
 /**
  *
@@ -18,12 +22,12 @@ import java.util.logging.Logger;
  */
 public class GetRequest extends Request {
 
-    protected GetRequest(RequestPlan requestPlan, String URL) {
-        super(requestPlan, URL);
+    protected GetRequest(RequestPlan requestPlan, Session session, String URL) {
+        super(requestPlan, session, URL);
     }
 
-    protected GetRequest(RequestPlan requestPlan, String URL, String headers) {
-        super(requestPlan, URL, headers);
+    protected GetRequest(RequestPlan requestPlan, Session session, String URL, String headers) {
+        super(requestPlan, session, URL, headers);
     }
 
     @Override
@@ -32,12 +36,17 @@ public class GetRequest extends Request {
             URL url = new URL(getURL());
             HttpURLConnection connection = (HttpURLConnection) url.openConnection();
             connection.setRequestMethod("GET");
-            getHeaders().forEach((entry) -> {
-                connection.setRequestProperty(entry.getKey(), entry.getValue());
+            forEachHeader((key, value) -> {
+                value = fillPropertyVariable(value);
+                connection.setRequestProperty(key, value);
             });
             int responseCode = connection.getResponseCode();
             if (responseCode < 400) {
                 Logger.getGlobal().log(Level.INFO, "{0} {1}", new Object[]{getMethod(), getURL()});
+                try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
+                    String response = bufferedReader.lines().collect(Collectors.joining());
+                    processResponse(response);
+                }
             } else {
                 Logger.getGlobal().log(Level.SEVERE, "error {0} on {1} {2}", new Object[]{responseCode, getMethod(), getURL()});
             }
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
index 628f221..18bb1bc 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/MultipartRequest.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/MultipartRequest.java
@@ -5,16 +5,17 @@
  */
 package br.ufrgs.inf.prosoft.requestssimulator.requests;
 
+import br.ufrgs.inf.prosoft.requestssimulator.Session;
 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.function.BiConsumer;
 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;
@@ -30,17 +31,21 @@ public class MultipartRequest extends Request {
 
     private final String forms;
 
-    protected MultipartRequest(RequestPlan requestPlan, String URL, String forms) {
-        super(requestPlan, URL);
+    protected MultipartRequest(RequestPlan requestPlan, Session session, String URL, String forms) {
+        super(requestPlan, session, URL);
         this.forms = forms;
     }
 
-    protected MultipartRequest(RequestPlan requestPlan, String URL, String headers, String forms) {
-        super(requestPlan, URL, headers);
+    protected MultipartRequest(RequestPlan requestPlan, Session session, String URL, String headers, String forms) {
+        super(requestPlan, session, URL, headers);
         this.forms = forms;
     }
 
-    public Stream<Map.Entry<String, String>> getForms() {
+    protected String getForms() {
+        return this.forms;
+    }
+
+    public void forEachForm(BiConsumer<? super String, ? super String> forEach) {
         Map<String, String> forms = new HashMap<>();
         if (this.forms != null) {
             String[] formsPairs = this.forms.split("; ");
@@ -49,7 +54,7 @@ public class MultipartRequest extends Request {
                 forms.put(pair[0], pair[1]);
             }
         }
-        return forms.entrySet().stream();
+        forms.forEach(forEach);
     }
 
     @Override
@@ -57,22 +62,27 @@ public class MultipartRequest extends Request {
         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);
+            forEachForm((key, value) -> {
+                if (key.equals("file")) {
+                    File file = new File(value);
+                    multipartEntityBuilder.addBinaryBody(key, file);
                 } else {
-                    multipartEntityBuilder.addTextBody(entry.getKey(), entry.getValue());
+                    multipartEntityBuilder.addTextBody(key, value);
                 }
             });
             HttpEntity httpEntity = multipartEntityBuilder.build();
             httpPost.setEntity(httpEntity);
+            forEachHeader((key, value) -> {
+                value = fillPropertyVariable(value);
+                httpPost.setHeader(key, value);
+            });
             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());
+                        processResponse(response);
                     }
                 } else {
                     Logger.getGlobal().log(Level.SEVERE, "error {0} on {1} {2}", new Object[]{responseCode, getMethod(), getURL()});
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
index 68bb47c..d3c1f4a 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/PostRequest.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/PostRequest.java
@@ -5,13 +5,17 @@
  */
 package br.ufrgs.inf.prosoft.requestssimulator.requests;
 
+import br.ufrgs.inf.prosoft.requestssimulator.Session;
+import java.io.BufferedReader;
 import java.io.IOException;
+import java.io.InputStreamReader;
 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;
+import java.util.stream.Collectors;
 
 /**
  *
@@ -21,16 +25,20 @@ public class PostRequest extends Request {
 
     private final String data;
 
-    protected PostRequest(RequestPlan requestPlan, String URL, String data) {
-        super(requestPlan, URL);
+    protected PostRequest(RequestPlan requestPlan, Session session, String URL, String data) {
+        super(requestPlan, session, URL);
         this.data = data;
     }
 
-    protected PostRequest(RequestPlan requestPlan, String URL, String headers, String data) {
-        super(requestPlan, URL, headers);
+    protected PostRequest(RequestPlan requestPlan, Session session, String URL, String headers, String data) {
+        super(requestPlan, session, URL, headers);
         this.data = data;
     }
 
+    protected String getData() {
+        return this.data;
+    }
+
     @Override
     public void fire() {
         try {
@@ -41,12 +49,17 @@ public class PostRequest extends Request {
             try (OutputStream outputStream = connection.getOutputStream()) {
                 outputStream.write(this.data.getBytes());
             }
-            getHeaders().forEach((entry) -> {
-                connection.setRequestProperty(entry.getKey(), entry.getValue());
+            forEachHeader((key, value) -> {
+                value = fillPropertyVariable(value);
+                connection.setRequestProperty(key, value);
             });
             int responseCode = connection.getResponseCode();
             if (responseCode < 400) {
                 Logger.getGlobal().log(Level.INFO, "{0} {1}", new Object[]{getMethod(), getURL()});
+                try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
+                    String response = bufferedReader.lines().collect(Collectors.joining());
+                    processResponse(response);
+                }
             } else {
                 Logger.getGlobal().log(Level.SEVERE, "error {0} on {1} {2}", new Object[]{responseCode, getMethod(), getURL()});
             }
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
index ff8df44..f38a641 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/Request.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/Request.java
@@ -5,9 +5,13 @@
  */
 package br.ufrgs.inf.prosoft.requestssimulator.requests;
 
+import br.ufrgs.inf.prosoft.requestssimulator.Session;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.stream.Stream;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
 
 /**
  *
@@ -18,16 +22,18 @@ public abstract class Request {
     private final RequestPlan requestPlan;
     private final String URL;
     private final String headers;
-    private Map<String, String> storedValues;
+    private final Session session;
 
-    protected Request(RequestPlan requestPlan, String URL) {
+    protected Request(RequestPlan requestPlan, Session session, String URL) {
         this.requestPlan = requestPlan;
+        this.session = session;
         this.URL = URL;
         this.headers = null;
     }
 
-    protected Request(RequestPlan requestPlan, String URL, String headers) {
+    protected Request(RequestPlan requestPlan, Session session, String URL, String headers) {
         this.requestPlan = requestPlan;
+        this.session = session;
         this.URL = URL;
         this.headers = headers;
     }
@@ -40,7 +46,11 @@ public abstract class Request {
         return this.URL;
     }
 
-    public Stream<Map.Entry<String, String>> getHeaders() {
+    protected String getHeaders() {
+        return this.headers;
+    }
+
+    public void forEachHeader(BiConsumer<? super String, ? super String> forEach) {
         Map<String, String> headers = new HashMap<>();
         if (this.headers != null) {
             String[] headerPairs = this.headers.split("; ");
@@ -49,11 +59,46 @@ public abstract class Request {
                 headers.put(pair[0], pair[1]);
             }
         }
-        return headers.entrySet().stream();
+        headers.forEach(forEach);
+    }
+
+    public Request pickNextRequest(Session session) {
+        return this.requestPlan.pickNextRequest(session);
+    }
+    
+    protected void processResponse(String response) {
+        this.requestPlan.forEachStoreField(new Consumer<String>() {
+
+            private final JsonParser jsonParser;
+            private final JsonObject jsonObject;
+
+            {
+                this.jsonParser = new JsonParser();
+                this.jsonObject = jsonParser.parse(response).getAsJsonObject();
+            }
+
+            @Override
+            public void accept(String storeField) {
+                String storedValue = jsonObject.get(storeField).getAsString();
+                storeValue(storeField, storedValue);
+            }
+        });
     }
 
-    public Request pickNextRequest() {
-        return this.requestPlan.pickNextRequest();
+    protected Request storeValue(String field, String value) {
+        this.session.storeValue(field, value);
+        return this;
+    }
+
+
+    protected String fillPropertyVariable(String property) {
+        String filledProperty = property;
+        if (filledProperty.contains("#")) {
+            String storedField = filledProperty.substring(filledProperty.indexOf("#") + 1);
+            String storedValue = this.session.getStoredValue(storedField);
+            filledProperty = filledProperty.replace("#" + storedField, storedValue);
+        }
+        return filledProperty;
     }
 
     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
index ab249dd..fe89440 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/RequestPlan.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/RequestPlan.java
@@ -5,11 +5,13 @@
  */
 package br.ufrgs.inf.prosoft.requestssimulator.requests;
 
+import br.ufrgs.inf.prosoft.requestssimulator.Session;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Objects;
 import java.util.Random;
+import java.util.function.Consumer;
 import java.util.stream.Stream;
 
 /**
@@ -25,7 +27,6 @@ public class RequestPlan {
     private List<RequestPlan> getLinks;
     private List<RequestPlan> postLinks;
     private Collection<String> storeFields;
-    private String contentType;
     private String headers;
     private String forms;
 
@@ -33,20 +34,12 @@ public class RequestPlan {
         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) {
@@ -58,7 +51,11 @@ public class RequestPlan {
     }
 
     public String getMethod() {
-        return method;
+        return this.method;
+    }
+
+    public String getReference() {
+        return this.method + "@" + this.URL;
     }
 
     public RequestPlan addHeader(String header) {
@@ -122,12 +119,11 @@ public class RequestPlan {
         return this;
     }
 
-    public RequestPlan setContentType(String contentType) {
-        this.contentType = contentType;
-        return this;
+    protected void forEachStoreField(Consumer<? super String> forEach) {
+        this.storeFields.forEach(forEach);
     }
 
-    public Request pickNextRequest() {
+    public Request pickNextRequest(Session session) {
         Random random = new Random();
         int probability = random.nextInt(100);
         if ((this.getLinks == null || this.getLinks.isEmpty()) && (this.postLinks == null || this.postLinks.isEmpty())) {
@@ -146,29 +142,41 @@ public class RequestPlan {
             int chosenIndex = random.nextInt(this.postLinks.size());
             chosen = this.postLinks.get(chosenIndex);
         }
-        return chosen.build();
+        return chosen.build(session);
     }
 
-    public Request build() {
+    public Request build(Session session) {
         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);
+        String headers = null;
+        if (this.headers != null) {
+            headers = this.headers.replace("$", String.valueOf(randomInt));
+            if (this.headers.contains("multipart")) {
+                String forms = this.forms;
+                return new MultipartRequest(this, session, URL, headers, forms);
+            }
         }
         if (this.method.equals("GET")) {
-            return new GetRequest(this, URL, headers);
+            return new GetRequest(this, session, URL, headers);
+        }
+        String data = this.data.replace("$", String.valueOf(randomInt));;
+        return new PostRequest(this, session, URL, data, headers);
+    }
+
+    public Request bind(Request request, Session session) {
+        if (request instanceof GetRequest) {
+            return new GetRequest(this, session, request.getURL());
+        }
+        if (request instanceof PostRequest) {
+            PostRequest postRequest = (PostRequest) request;
+            return new PostRequest(this, session, postRequest.getURL(), postRequest.getHeaders(), postRequest.getData());
         }
-        String data = this.data;
-        return new PostRequest(this, URL, data, headers);
+        MultipartRequest multipartRequest = (MultipartRequest) request;
+        return new MultipartRequest(this, session, multipartRequest.getURL(), multipartRequest.getHeaders(), multipartRequest.getForms());
     }
 
     @Override
@@ -190,5 +198,4 @@ public class RequestPlan {
         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
index e150663..5facf23 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/Session.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/Session.java
@@ -8,6 +8,8 @@ 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.HashMap;
+import java.util.Map;
 import java.util.Random;
 
 /**
@@ -17,9 +19,20 @@ import java.util.Random;
 public class Session {
 
     private final Collection<RequestPlan> roots;
+    private final Map<String, String> storedValues;
 
     public Session(Collection<RequestPlan> roots) {
         this.roots = roots;
+        this.storedValues = new HashMap<>();
+    }
+
+    public Session storeValue(String field, String value) {
+        this.storedValues.put(field, value);
+        return this;
+    }
+
+    public String getStoredValue(String storedField) {
+        return this.storedValues.get(storedField);
     }
 
     public void run() {
@@ -40,8 +53,8 @@ public class Session {
             }
             currentRequest = RequestPlan.get("root")
                     .addLinks(this.roots)
-                    .build();
+                    .build(this);
         }
-        return currentRequest.pickNextRequest();
+        return currentRequest.pickNextRequest(this);
     }
 }
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 3d0a94e..1a24c8b 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/Simulator.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/Simulator.java
@@ -31,7 +31,7 @@ public class Simulator {
             threads.add(thread);
             thread.start();
         }
-        threads.forEach((thread) -> {
+        threads.forEach(thread -> {
             try {
                 thread.join();
             } catch (InterruptedException ex) {