RequestPlan.java

327 lines | 11.025 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 java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 *
 * @author romulo
 */
public class RequestPlan {

    private final String method;
    private final String URL;
    private final String data;
    private String reference;
    private List<RequestPlan> readLinks;
    private List<RequestPlan> writeLinks;
    private Collection<String> storeFields;
    private Collection<String> storeCookies;
    private Collection<RequestPlan> requirements;
    private String headers;
    private String forms;

    private RequestPlan(String URL) {
        this.method = "GET";
        this.URL = URL;
        this.data = null;
    }

    private RequestPlan(String URL, String data) {
        this.method = "POST";
        this.URL = URL;
        this.data = data;
    }

    private RequestPlan(String method, String URL, String data) {
        this.method = method;
        this.URL = URL;
        this.data = data;
    }

    public static RequestPlan get(String URL) {
        return new RequestPlan(URL);
    }

    public static RequestPlan post(String URL, String data) {
        return new RequestPlan(URL, data);
    }

    public static RequestPlan delete(String URL, String data) {
        return new RequestPlan("DELETE", URL, data);
    }

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

    public RequestPlan setReference(String reference) {
        this.reference = reference;
        return this;
    }

    public String getReference() {
        if (this.reference == null) {
            return method + "@" + this.URL;
        }
        return this.reference;
    }

    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<RequestPlan> links() {
        if (this.readLinks == null && this.writeLinks == null) {
            return Stream.empty();
        }
        if (this.readLinks != null && this.writeLinks != null) {
            return Stream.concat(this.readLinks.stream(), this.writeLinks.stream());
        }
        if (this.readLinks != null) {
            return this.readLinks.stream();
        }
        return this.writeLinks.stream();
    }

    public RequestPlan addLink(RequestPlan requestPlan) {
        if (requestPlan.getMethod().equals("GET")) {
            if (this.readLinks == null) {
                this.readLinks = new ArrayList<>();
            }
            this.readLinks.add(requestPlan);
        } else {
            if (this.writeLinks == null) {
                this.writeLinks = new ArrayList<>();
            }
            this.writeLinks.add(requestPlan);
        }
        return this;
    }

    public RequestPlan addLinks(Collection<RequestPlan> requestPlans) {
        requestPlans.forEach(requestPlan -> addLink(requestPlan));
        return this;
    }

    public RequestPlan addRequirement(RequestPlan requestPlan) {
        if (this.requirements == null) {
            this.requirements = new ArrayList<>();
        }
        this.requirements.add(requestPlan);
        return this;
    }

    protected Stream<RequestPlan> requirements() {
        if (this.requirements == null || this.requirements.isEmpty()) {
            return Stream.empty();
        }
        return this.requirements.stream();
    }

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

    public Request pickNextRequest(Session session) {
        Random random = new Random();
        int probability = random.nextInt(100);
        if ((this.readLinks == null || this.readLinks.isEmpty()) && (this.writeLinks == null || this.writeLinks.isEmpty())) {
            throw new RuntimeException("GET and POST links empty: " + this.URL);
        }
        RequestPlan chosen;
        if (this.readLinks == null || this.readLinks.isEmpty()) {
            probability = 100;
        } else if (this.writeLinks == null || this.writeLinks.isEmpty()) {
            probability = 0;
        }
        if (probability < 80) {
            int chosenIndex = random.nextInt(this.readLinks.size());
            chosen = this.readLinks.get(chosenIndex);
        } else {
            int chosenIndex = random.nextInt(this.writeLinks.size());
            chosen = this.writeLinks.get(chosenIndex);
        }
        return chosen.build(session);
    }

    public Request build(Session session) {
        if (this.URL == null || this.URL.isEmpty()) {
            throw new RuntimeException("URL is empty");
        }
        String URL = replaceOptionals(this.URL);
        HashMap<String, Integer> map = new HashMap<>();
        URL = replaceRandoms(URL, map);
        Pattern pattern = Pattern.compile("#\\{(.*?)\\[(.*?)\\](.*?)\\}");
        Matcher originalMatcher = pattern.matcher(this.URL);
        Matcher randomMatcher = pattern.matcher(URL);
        while (originalMatcher.find() & randomMatcher.find()) {
            String originalFound = originalMatcher.group();
            String randomFound = randomMatcher.group();
            URL = URL.replace(randomFound, originalFound);
        }
        Collection<String> storeFields = storeFields()
                .map(storeField -> replaceRandoms(storeField, map))
                .collect(Collectors.toList());
        String headers = null;
        if (this.headers != null) {
            headers = replaceOptionals(this.headers);
            headers = replaceRandoms(headers, map);
            if (this.headers.contains("multipart")) {
                String forms = replaceOptionals(this.forms);
                return new MultipartRequest(this, session, URL, headers, forms, storeFields);
            }
        }
        if (this.method.equals("DELETE")) {
            return new DeleteRequest(this, session, URL, headers, storeFields);
        }
        if (this.method.equals("GET")) {
            return new GetRequest(this, session, URL, headers, storeFields);
        }
        String data = replaceOptionals(this.data);
        data = replaceRandoms(data, map);
        return new PostRequest(this, session, URL, data, headers, storeFields);
    }

    private String replaceRandoms(String data) {
        return replaceRandoms(data, new HashMap<>());
    }

    private String replaceRandoms(String data, Map<String, Integer> map) {
        Random random = new Random();
        Pattern pattern = Pattern.compile("\\$\\{(.*?)\\}");
        Matcher randomMatcher = pattern.matcher(data);
        while (randomMatcher.find()) {
            String randomFound = randomMatcher.group();
            String randomTrimmed = randomFound.substring(2, randomFound.length() - 1);
            int randomInt;
            if (map.containsKey(randomFound)) {
                randomInt = map.get(randomFound);
            } else {
                String[] split = randomTrimmed.split("-");
                int from = Integer.valueOf(split[0]);
                int to = Integer.valueOf(split[1]);
                randomInt = random.nextInt(to - from + 1) + from;
                map.put(randomFound, randomInt);
            }
            data = data.replace(randomFound, String.valueOf(randomInt));
        }
        int randomInt;
        if (map.containsKey("$")) {
            randomInt = map.get("$");
        } else {
            randomInt = random.nextInt() & Integer.MAX_VALUE;
            map.put("$", randomInt);
        }
        data = data.replace("$", String.valueOf(randomInt));
        return data;
    }

    private String replaceOptionals(String data) {
        Pattern pattern = Pattern.compile("<(.*?)>");
        Matcher matcher = pattern.matcher(data);
        Random random = new Random();
        while (matcher.find()) {
            String options = matcher.group();
            String optionsTrimmed = options.substring(1, options.length() - 1);
            String[] split = optionsTrimmed.split("\\|");
            int nextInt = random.nextInt(split.length);
            String choice = split[nextInt];
            data = data.replace(options, choice);
        }
        return data;
    }

    public Request bind(Request request, Session session) {
        if (request instanceof DeleteRequest) {
            DeleteRequest deleteRequest = (DeleteRequest) request;
            return new DeleteRequest(this, session, deleteRequest.getURL(), deleteRequest.getHeaders(), deleteRequest.getStoreFields());
        }
        if (request instanceof GetRequest) {
            GetRequest getRequest = (GetRequest) request;
            return new GetRequest(this, session, getRequest.getURL(), getRequest.getHeaders(), getRequest.getStoreFields());
        }
        if (request instanceof PostRequest) {
            PostRequest postRequest = (PostRequest) request;
            return new PostRequest(this, session, postRequest.getURL(), postRequest.getData(), postRequest.getHeaders(), postRequest.getStoreFields());
        }
        MultipartRequest multipartRequest = (MultipartRequest) request;
        return new MultipartRequest(this, session, multipartRequest.getURL(), multipartRequest.getHeaders(), multipartRequest.getForms(), multipartRequest.getStoreFields());
    }

    @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);
    }
}