Request.java

297 lines | 9.698 kB Blame History Raw Download
/*
 * 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 br.ufrgs.inf.prosoft.requestssimulator.Session;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

import java.io.FileWriter;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;

/**
 * @author romulo
 */
public abstract class Request {

  public static String REQUESTS_LOG = null;
  public static String HOME_PATH = "";
  private final RequestPlan requestPlan;
  private final String URL;
  private final String headers;
  private final Collection<String> storeFields;
  private final Session session;

  protected Request(RequestPlan requestPlan, Session session, String URL) {
    this.requestPlan = requestPlan;
    this.session = session;
    this.URL = URL;
    this.headers = null;
    this.storeFields = null;
  }

  protected Request(RequestPlan requestPlan, Session session, String URL, Collection<String> storeFields) {
    this.requestPlan = requestPlan;
    this.session = session;
    this.URL = URL;
    this.headers = null;
    this.storeFields = storeFields;
  }

  protected Request(RequestPlan requestPlan, Session session, String URL, String headers) {
    this.requestPlan = requestPlan;
    this.session = session;
    this.URL = URL;
    this.headers = headers;
    this.storeFields = null;
  }

  protected Request(RequestPlan requestPlan, Session session, String URL, String headers, Collection<String> storeFields) {
    this.requestPlan = requestPlan;
    this.session = session;
    this.URL = URL;
    this.headers = headers;
    this.storeFields = storeFields;
  }

  public String getMethod() {
    return this.requestPlan.getMethod();
  }

  public String getURL() {
    return this.URL;
  }

  protected String getHeaders() {
    return this.headers;
  }

  public Stream<Map.Entry<String, String>> headers() {
    Map<String, String> headers = new HashMap<>();
    if (this.headers != null && !this.headers.isEmpty()) {
      String[] headerPairs = this.headers.split("; ");
      for (String headerPair : headerPairs) {
        String[] pair = headerPair.split(": ");
        if (pair.length > 1) headers.put(pair[0], pair[1]);
        else Logger.getGlobal().log(Level.SEVERE, "invalid header pair {0}", headerPair);
      }
    }
    return headers.entrySet().stream();
  }

  protected Collection<String> getStoreFields() {
    return storeFields;
  }

  private Stream<String> storeFields() {
    if (this.storeFields == null || this.storeFields.isEmpty()) return Stream.empty();
    return this.storeFields.stream();
  }

  private Stream<String> storeCookies() {
    return this.requestPlan.storeCookies();
  }

  public Request pickNextRequest(Session session) {
    return this.requestPlan.pickNextRequest(session);
  }

  protected void storeCookies(List<String> cookies) {
    if (storeCookies().count() == 0) return;
    Map<String, String> map = new HashMap<>();
    cookies.forEach(cookieGroup -> {
      String[] cookiePairs = cookieGroup.split("; ");
      for (String cookiePair : cookiePairs) {
        String[] pair = cookiePair.split("=");
        if (pair.length > 1) map.put(pair[0], pair[1]);
      }
    });
    storeCookies().forEach(storeCookie -> storeValue(storeCookie, map.get(storeCookie)));
  }

  protected void processResponse(String response) {
    if (response == null || response.isEmpty()) {
      Logger.getGlobal().log(Level.SEVERE, "empty response");
      return;
    }
    if (storeFields().count() == 0) return;
    storeFields().forEach(new Consumer<String>() {

      private final JsonParser jsonParser;
      private final JsonElement jsonElement;

      {
        this.jsonParser = new JsonParser();
        this.jsonElement = this.jsonParser.parse(response);
      }

      @Override
      public void accept(String storeField) {
        String tokenVariable;
        if (storeField.contains("@")) tokenVariable = storeField.split("@")[1];
        else tokenVariable = storeField;
        Tokenizer tokenizer = new Tokenizer(tokenVariable);
        JsonElement jsonElement = this.jsonElement;
        while (tokenizer.hasMoreTokens()) {
          String nextToken = tokenizer.getNextToken();
          if (nextToken.charAt(0) == '[') {
            try {
              Integer index = Integer.valueOf(nextToken.substring(1, nextToken.length() - 1));
              JsonArray jsonArray = jsonElement.getAsJsonArray();
              if (index >= jsonArray.size()) {
                Logger.getGlobal().log(Level.SEVERE, "index error {0}", storeField);
                return;
              }
              jsonElement = jsonArray.get(index);
            } catch (NumberFormatException ex) {
              Logger.getGlobal().log(Level.SEVERE, "NumberFormatException {0}", storeField);
              return;
            }
          } else {
            if (nextToken.charAt(0) == '#') nextToken = nextToken.substring(1);
            JsonObject jsonObject = jsonElement.getAsJsonObject();
            jsonElement = jsonObject.get(nextToken);
          }
          if (jsonElement == null) {
            Logger.getGlobal().log(Level.SEVERE, "field {0} not present", storeField);
            return;
          }
        }
        Pattern pattern = Pattern.compile("\\[(.*?)\\]");
        Matcher matcher = pattern.matcher(storeField);
        while (matcher.find()) {
          String found = matcher.group();
          storeField = storeField.replace(found, "[$]");
        }
        String storedValue = jsonElement.getAsString();
        storeValue(storeField, storedValue);
      }

      class Tokenizer {

        private final String string;
        private int index;

        public Tokenizer(String string) {
          this.index = 0;
          this.string = string;
        }

        private String getNextToken() {
          if (!hasMoreTokens()) return null;
          StringBuilder nextToken = new StringBuilder();
          while (true) {
            char nextChar = this.string.charAt(this.index);
            this.index++;
            nextToken.append(nextChar);
            if (nextChar == ']') break;
            if (this.index == this.string.length()) break;
            char futureChar = this.string.charAt(this.index);
            if (futureChar == '#' || futureChar == '[') break;
          }
          return nextToken.toString();
        }

        protected boolean hasMoreTokens() {
          if (this.string == null) return false;
          if (this.string.isEmpty()) return false;
          return this.index < string.length();
        }
      }
    });
  }

  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("#{")) {
      Pattern pattern = Pattern.compile("#\\{(.*?)}");
      Matcher matcher = pattern.matcher(property);
      while (matcher.find()) {
        String storedField = matcher.group();
        String fieldName = storedField.substring(2, storedField.length() - 1);
        String storedValue = this.session.getStoredValue(fieldName);
        if (storedValue == null) {
          Logger.getGlobal().log(Level.SEVERE, "variable {0} not stored", storedField);
          continue;
        }
        filledProperty = filledProperty.replace(storedField, storedValue);
      }
    }
    return filledProperty;
  }

  public void fire() {
    this.requestPlan.requirements().forEach(requirement -> {
      boolean unfired = Stream.concat(requirement.storeFields(), requirement.storeCookies()).anyMatch(field -> this.session.getStoredValue(field) == null);
      if (unfired) requirement.build(this.session).fire();
    });
    fireRequest();
  }

  protected abstract void fireRequest();

  protected void log(int statusCode) {
    if (REQUESTS_LOG == null) return;
    JsonObject jsonObject = new JsonObject();
    jsonObject.addProperty("time", System.currentTimeMillis());
    jsonObject.addProperty("code", statusCode);
    jsonObject.addProperty("method", getMethod());
    jsonObject.addProperty("url", getURL());
    log(jsonObject.toString());
  }

  private void log(String message) {
    if (REQUESTS_LOG == null) return;
    try (FileWriter fileWriter = new FileWriter(REQUESTS_LOG, true)) {
      fileWriter.write(message + "\n");
    } catch (IOException ignored) {
    }
  }

  public final JsonObject toJsonObject() {
    JsonObject jsonObject = new JsonObject();
    jsonObject.addProperty("reference", this.requestPlan.getReference());
    jsonObject.addProperty("URL", getURL());
    jsonObject.addProperty("headers", getHeaders());
    if (storeFields().count() > 0) {
      JsonArray storeFields = new JsonArray();
      storeFields().forEach(storeFields::add);
      jsonObject.add("storeFields", storeFields);
    }
    if (storeCookies().count() > 0) {
      JsonArray storeCookies = new JsonArray();
      storeCookies().forEach(storeCookies::add);
      jsonObject.add("storeCookies", storeCookies);
    }
    if (this instanceof PostRequest) {
      PostRequest postRequest = (PostRequest) this;
      jsonObject.addProperty("data", postRequest.getData());
    }
    if (this instanceof MultipartRequest) {
      MultipartRequest multipartRequest = (MultipartRequest) this;
      jsonObject.addProperty("forms", multipartRequest.getForms());
    }
    return jsonObject;
  }
}