Simulator.java

161 lines | 6.151 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;

import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Stream;

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

    private static final Logger logger = Logger.getLogger(Simulator.class.getName());

    public static final void simulate(String path) {
        simulate(path, 1);
    }

    public static final void simulate(String path, int users) {
        if (users < 1) {
            logger.log(Level.SEVERE, "informed {0} users. Using 1", users);
            users = 1;
        }
        long startTime = System.currentTimeMillis();
        int requestsSize = 1;
        try {
            logger.log(Level.INFO, "requesting {0} URLS", requestsSize);
            if (users == 1) {
                requestsSize = (int) Files.lines(Paths.get(path)).count();
                Stream<String> lines = Files.lines(Paths.get(path));
                startTime = System.currentTimeMillis();
                lines.forEach(new RequestProcesser());
            } else {
                List<String> requests = Files.readAllLines(Paths.get(path));
                requestsSize = requests.size();
                int inclusiveStart = 0;
                int partitionSize = requestsSize / users;
                if (partitionSize < 1) {
                    partitionSize = 1;
                    logger.log(Level.SEVERE, "more users {0} than requests {1}. Using {1} users", new Object[]{users, requests.size()});
                }
                Collection<Thread> threads = new ArrayList<>();
                startTime = System.currentTimeMillis();
                while (inclusiveStart < requestsSize) {
                    int exclusiveEnd = inclusiveStart + partitionSize;
                    Thread thread = new Thread(new PartitionProcesser(requests, inclusiveStart, exclusiveEnd));
                    thread.start();
                    threads.add(thread);
                    inclusiveStart = exclusiveEnd;
                }
                threads.forEach(thread -> {
                    try {
                        thread.join();
                    } catch (InterruptedException ex) {
                        logger.log(Level.SEVERE, "thread stopped");
                    }
                });
            }
        } catch (IOException ex) {
            logger.log(Level.SEVERE, "cannot open file {0}", path);
        }
        long endTime = System.currentTimeMillis();
        long executionTime = startTime - endTime;
        int milliseconds = (int) (executionTime % 1000);
        int seconds = (int) (executionTime / 1000) % 60;
        int minutes = (int) ((executionTime / (1000 * 60)) % 60);
        double throughput = requestsSize / (double) seconds;
        System.out.println("Execution Time: " + minutes + ":" + seconds + "." + milliseconds + " minutes");
        System.out.println("Throughput: " + throughput + " requests per second");
    }

    private static class RequestProcesser implements Consumer<String> {

        private int i;

        public RequestProcesser() {
            this.i = 1;
        }

        public RequestProcesser(int i) {
            this.i = i;
        }

        @Override
        public void accept(String line) {
            try {
                if (line.startsWith("POST")) {
                    String[] split = line.split(" ");
                    URL url = new URL(split[1]);
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    connection.setRequestMethod("POST");
                    connection.setDoOutput(true);
                    try (OutputStream outputStream = connection.getOutputStream()) {
                        outputStream.write(split[2].getBytes());
                    }
                    int responseCode = connection.getResponseCode();
                    if (responseCode == 200) {
                        logger.log(Level.INFO, "{0} {1}", new Object[]{i, line});
                    } else {
                        logger.log(Level.SEVERE, "{0} error {1} on {2}", new Object[]{i, responseCode, line});
                    }
                    connection.disconnect();
                } else {
                    URL url = new URL(line);
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    connection.setRequestMethod("GET");
                    int responseCode = connection.getResponseCode();
                    if (responseCode == 200) {
                        logger.log(Level.INFO, "{0} GET {1}", new Object[]{i, line});
                    } else {
                        logger.log(Level.SEVERE, "{0} error {1} on {2}", new Object[]{i, responseCode, line});
                    }
                    connection.disconnect();
                }
            } catch (MalformedURLException ex) {
                logger.log(Level.SEVERE, "Malormed URL");
            } catch (IOException ex) {
                logger.log(Level.SEVERE, "IOException");
            }
            i++;
        }
    }

    private static class PartitionProcesser implements Runnable {

        private final Stream<String> requests;
        private final int inclusiveStart;

        public PartitionProcesser(List<String> requests, int incusiveStart, int exclusiveEnd) {
            this.inclusiveStart = incusiveStart;
            this.requests = requests.subList(incusiveStart, exclusiveEnd).stream();
        }

        public PartitionProcesser(Stream<String> requests) {
            this.requests = requests;
            this.inclusiveStart = 1;
        }

        @Override
        public void run() {
            this.requests.forEach(new RequestProcesser(this.inclusiveStart + 1));
        }
    }
}