/*
* 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.ArrayList;
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 {
private final RequestPlan requestPlan;
private final String URL;
private final String headers;
private final Collection<String> storeFields;
private final Session session;
public static String REQUESTS_LOG = null;
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.stream().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);
}
class Tokenizer {
private int index;
private final String string;
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();
}
}
@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, nextToken.length());
}
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);
}
});
}
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("#{")) {
Collection<String> matches = new ArrayList<>();
Pattern pattern = Pattern.compile("#\\{(.*?)\\}");
Matcher matcher = pattern.matcher(property);
while (matcher.find()) {
matches.add(matcher.group());
}
for (String storedField : matches) {
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 ex) {
}
}
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(storeField -> {
storeFields.add(storeField);
});
jsonObject.add("storeFields", storeFields);
}
if (storeCookies().count() > 0) {
JsonArray storeCookies = new JsonArray();
storeCookies().forEach(storeCookie -> {
storeCookies.add(storeCookie);
});
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;
}
}