Request.java

341 lines | 12.008 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.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;
    }
}