From 2969568cce35ec4a1c2ef9aa7fb1ffd5f37a164d Mon Sep 17 00:00:00 2001 From: polyushka Date: Wed, 30 Nov 2022 19:42:35 +0300 Subject: [PATCH] init: Implement everything --- lab-02/pom.xml | 29 +++ .../docks_and_hobos/Main.java | 17 ++ .../docks_and_hobos/Model.java | 88 +++++++ .../docks_and_hobos/actors/Cargo.java | 27 +++ .../docks_and_hobos/actors/Dock.java | 79 +++++++ .../docks_and_hobos/actors/Hobo.java | 52 ++++ .../docks_and_hobos/actors/Ship.java | 17 ++ .../docks_and_hobos/actors/ShipGenerator.java | 62 +++++ .../docks_and_hobos/actors/Tunnel.java | 23 ++ .../controllers/Controller.java | 35 +++ .../controllers/HoboController.java | 222 ++++++++++++++++++ .../controllers/LoggersController.java | 120 ++++++++++ .../docks_and_hobos/logs/log file #1.txt | 55 +++++ .../docks_and_hobos/resources/config.json | 46 ++++ .../docks_and_hobos/utils/LogFormatter.java | 19 ++ 15 files changed, 891 insertions(+) create mode 100644 lab-02/pom.xml create mode 100644 lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/Main.java create mode 100644 lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/Model.java create mode 100644 lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/actors/Cargo.java create mode 100644 lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/actors/Dock.java create mode 100644 lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/actors/Hobo.java create mode 100644 lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/actors/Ship.java create mode 100644 lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/actors/ShipGenerator.java create mode 100644 lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/actors/Tunnel.java create mode 100644 lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/controllers/Controller.java create mode 100644 lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/controllers/HoboController.java create mode 100644 lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/controllers/LoggersController.java create mode 100644 lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/logs/log file #1.txt create mode 100644 lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/resources/config.json create mode 100644 lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/utils/LogFormatter.java diff --git a/lab-02/pom.xml b/lab-02/pom.xml new file mode 100644 index 0000000..b909448 --- /dev/null +++ b/lab-02/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + + by.polina_kostyukovich.docks_and_hobos + lab-02 + 1.0-SNAPSHOT + + + com.googlecode.json-simple + json-simple + 1.1 + + + commons-io + commons-io + 2.6 + + + + + 19 + 19 + UTF-8 + + + \ No newline at end of file diff --git a/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/Main.java b/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/Main.java new file mode 100644 index 0000000..8f344c8 --- /dev/null +++ b/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/Main.java @@ -0,0 +1,17 @@ +package by.polina_kostyukovich.docks_and_hobos; + +import by.polina_kostyukovich.docks_and_hobos.controllers.Controller; +import org.json.simple.parser.ParseException; + +import java.io.IOException; + +public class Main { + public static void main(String[] args) throws IOException, ParseException { + if (args.length != 1) { + throw new IllegalArgumentException("Illegal number of arguments"); + } + + Controller controller = new Controller(args[0]); + controller.startRunning(); + } +} diff --git a/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/Model.java b/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/Model.java new file mode 100644 index 0000000..a18f854 --- /dev/null +++ b/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/Model.java @@ -0,0 +1,88 @@ +package by.polina_kostyukovich.docks_and_hobos; + +import by.polina_kostyukovich.docks_and_hobos.actors.*; +import by.polina_kostyukovich.docks_and_hobos.controllers.HoboController; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + +import java.io.FileReader; +import java.io.IOException; +import java.util.*; + +public class Model { + public void readData(String filename) throws IOException, ParseException { + JSONParser parser = new JSONParser(); + JSONObject info = (JSONObject) parser.parse(new FileReader(filename)); + + final int maxShipsInTunnel = (int) (long) info.get("Max ships in tunnel"); + tunnel = new Tunnel(maxShipsInTunnel); + + final int generatingTime = (int) (long) info.get("Generating time"); + final int minShipCapacity = (int) (long) info.get("Min ship capacity"); + final int maxShipCapacity = (int) (long) info.get("Max ship capacity"); + Object[] cargoTypesJson = ((JSONArray) info.get("Cargo types")).toArray(); + ArrayList cargoTypes = new ArrayList<>(cargoTypesJson.length); + for (Object type : cargoTypesJson) { + cargoTypes.add((String) type); + } + shipGenerator = new ShipGenerator(generatingTime, cargoTypes, minShipCapacity, maxShipCapacity, tunnel); + + final int numberOfDocks = (int) (long) info.get("Number of docks"); + final int unloadingSpeed = (int) (long) info.get("Unloading speed"); + final int dockCapacity = (int) (long) info.get("Dock capacity"); + docks = new ArrayList<>(numberOfDocks); + for (int i = 0; i < numberOfDocks; ++i) { + docks.add(new Dock(unloadingSpeed, dockCapacity, i)); + } + + final int numberOfHobos = (int) (long) info.get("Number of hobos"); + Object[] ingredientsCountJson = ((JSONArray) info.get("Ingredients count")).toArray(); + Map ingredientsCount = new HashMap<>(ingredientsCountJson.length); + for (Object ingredientCount : ingredientsCountJson) { + JSONObject ingredientCountJson = (JSONObject) ingredientCount; + ingredientsCount.put((String) ingredientCountJson.get("Cargo type"), + (int) (long) ingredientCountJson.get("Cargo amount")); + } + final int stealingTime = (int) (long) info.get("Stealing time"); + final int eatingTime = (int) (long) info.get("Eating time"); + ArrayList hobos = new ArrayList<>(numberOfHobos); + for (int i = 0; i < numberOfHobos; ++i) { + hobos.add(new Hobo(stealingTime, i)); + } + hoboController = new HoboController(hobos, ingredientsCount, docks, eatingTime, cargoTypes); + } + + public ShipGenerator getShipGenerator() { + return shipGenerator; + } + + public Tunnel getTunnel() { + return tunnel; + } + + public ArrayList getDocks() { + return docks; + } + + public HoboController getHoboController() { + return hoboController; + } + + public Dock getFreeDock() { + return docks.stream() + .filter(Dock::isFree) + .findAny().orElse(null); + } + + public boolean hasFreeDock() { + return docks.stream() + .anyMatch(Dock::isFree); + } + + private ShipGenerator shipGenerator; + private Tunnel tunnel; + private ArrayList docks; + private HoboController hoboController; +} diff --git a/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/actors/Cargo.java b/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/actors/Cargo.java new file mode 100644 index 0000000..0115389 --- /dev/null +++ b/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/actors/Cargo.java @@ -0,0 +1,27 @@ +package by.polina_kostyukovich.docks_and_hobos.actors; + +public class Cargo { + private final String type; + private int amount; + + public Cargo(String type, int amount) { + if (type == null) { + throw new IllegalArgumentException("Parameter type is null"); + } + + this.type = type; + this.amount = amount; + } + + public void setAmount(int amount) { + this.amount = amount; + } + + public int getAmount() { + return amount; + } + + public String getType() { + return type; + } +} diff --git a/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/actors/Dock.java b/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/actors/Dock.java new file mode 100644 index 0000000..444087e --- /dev/null +++ b/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/actors/Dock.java @@ -0,0 +1,79 @@ +package by.polina_kostyukovich.docks_and_hobos.actors; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class Dock implements Runnable { + public Dock(int unloadingTime, int capacity, int id) { + this.unloadingSpeed = unloadingTime; + this.capacity = capacity; + this.id = id; + } + + @Override + public void run() { + Cargo addedCargo = new Cargo(cargoToAdd.getType(), 0); + while (cargoToAdd.getAmount() > 0 && getTotalCargoAmount() < capacity) { + try { + Thread.sleep(1000L); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + int addedAmount = Math.min( + Math.min(capacity - getTotalCargoAmount(), cargoToAdd.getAmount()), unloadingSpeed); + cargos.computeIfPresent(cargoToAdd.getType(), (type, count) -> count + addedAmount); + cargos.putIfAbsent(cargoToAdd.getType(), addedAmount); + cargoToAdd.setAmount(cargoToAdd.getAmount() - addedAmount); + addedCargo.setAmount(addedCargo.getAmount() + addedAmount); + } + isFree = true; + String strToLog = "Dock #" + id + " ended unloading " + addedCargo.getAmount() + " ones of " + + addedCargo.getType(); + LOGGER.log(Level.INFO, strToLog); + } + + public Map getCargos() { + return cargos; + } + + public int getUnloadingSpeed() { + return unloadingSpeed; + } + + public boolean isFree() { + return isFree && getTotalCargoAmount() < capacity; + } + + public void setCargoToAdd(Cargo cargoToAdd) { + if (cargoToAdd == null) { + throw new IllegalArgumentException("Parameter cargoToAdd is null"); + } + + this.cargoToAdd = cargoToAdd; + } + + public void setFree(boolean isFree) { + this.isFree = isFree; + } + + public int getTotalCargoAmount() { + return cargos.values().stream() + .mapToInt(n -> n) + .sum(); + } + + public static Logger getLogger() { + return LOGGER; + } + + private final int id; + private final int unloadingSpeed; + private final int capacity; + private final ConcurrentMap cargos = new ConcurrentHashMap<>(); + private boolean isFree = true; + private Cargo cargoToAdd; + private static final Logger LOGGER = Logger.getLogger(Dock.class.getName()); +} diff --git a/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/actors/Hobo.java b/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/actors/Hobo.java new file mode 100644 index 0000000..b00cf54 --- /dev/null +++ b/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/actors/Hobo.java @@ -0,0 +1,52 @@ +package by.polina_kostyukovich.docks_and_hobos.actors; + +import by.polina_kostyukovich.docks_and_hobos.controllers.HoboController; + +import java.util.logging.Level; +import java.util.logging.Logger; + +public class Hobo implements Runnable { + public Hobo(int stealingTime, int id) { + this.stealingTime = stealingTime; + this.id = id; + } + + @Override + public void run() { + try { + Thread.sleep(stealingTime * 1000L); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + cargoToBeStolen.getDock().getCargos().compute(cargoToBeStolen.getCargoType(), (type, count) -> count - 1); + cargoToBeStolen.decrementStealingHobosNumber(); + LOGGER.log(Level.FINE, "Hobo #" + id + " stole one " + cargoToBeStolen.getCargoType()); + isFree = true; + } + + public boolean isFree() { + return isFree; + } + + public void setCargoToBeStolen(HoboController.CargoToBeStolen cargoToBeStolen) { + if (cargoToBeStolen == null) { + throw new IllegalArgumentException("cargoToBeStolen is null"); + } + + this.cargoToBeStolen = cargoToBeStolen; + } + + public void setFree(boolean isFree) { + this.isFree = isFree; + } + + public static Logger getLogger() { + return LOGGER; + } + + private final int id; + private final int stealingTime; + private boolean isFree = true; + private HoboController.CargoToBeStolen cargoToBeStolen; + private static final Logger LOGGER = Logger.getLogger(Hobo.class.getName()); +} diff --git a/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/actors/Ship.java b/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/actors/Ship.java new file mode 100644 index 0000000..5211021 --- /dev/null +++ b/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/actors/Ship.java @@ -0,0 +1,17 @@ +package by.polina_kostyukovich.docks_and_hobos.actors; + +public class Ship { + private final Cargo cargo; + + public Ship(Cargo cargo) { + if (cargo == null) { + throw new IllegalArgumentException("Parameter cargo is null"); + } + + this.cargo = cargo; + } + + public Cargo getCargo() { + return cargo; + } +} diff --git a/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/actors/ShipGenerator.java b/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/actors/ShipGenerator.java new file mode 100644 index 0000000..6e77940 --- /dev/null +++ b/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/actors/ShipGenerator.java @@ -0,0 +1,62 @@ +package by.polina_kostyukovich.docks_and_hobos.actors; + +import java.util.ArrayList; +import java.util.Random; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class ShipGenerator implements Runnable { + public ShipGenerator(int generatingTime, ArrayList cargoTypes, int minShipCapacity, int maxShipCapacity, + Tunnel tunnel) { + if (cargoTypes == null || tunnel == null) { + throw new IllegalArgumentException("Some parameter in ShipGenerator constructor is null"); + } + + this.generatingTime = generatingTime; + this.cargoTypes = cargoTypes; + this.minShipCapacity = minShipCapacity; + this.maxShipCapacity = maxShipCapacity; + this.tunnel = tunnel; + } + + @Override + public void run() { + while (true) { + try { + Thread.sleep(1000L * generatingTime); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + Ship newShip = generateShip(); + String strToLog; + if (tunnel.addShip(newShip)) { + strToLog = "Added ship: type - " + newShip.getCargo().getType() + ", amount - " + + newShip.getCargo().getAmount(); + } else { + strToLog = "Killed ship :("; + } + LOGGER.log(Level.INFO, strToLog); + } + } + + private Ship generateShip() { + int capacity = (int) (Math.random() * (maxShipCapacity - minShipCapacity + 1) + minShipCapacity); + String type = cargoTypes.get((new Random()).nextInt(cargoTypes.size())); + return new Ship(new Cargo(type, capacity)); + } + + public int getGeneratingTime() { + return generatingTime; + } + + public static Logger getLogger() { + return LOGGER; + } + + private final int generatingTime; + private final ArrayList cargoTypes; + private final int minShipCapacity; + private final int maxShipCapacity; + private final Tunnel tunnel; + private static final Logger LOGGER = Logger.getLogger(ShipGenerator.class.getName()); +} diff --git a/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/actors/Tunnel.java b/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/actors/Tunnel.java new file mode 100644 index 0000000..400970e --- /dev/null +++ b/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/actors/Tunnel.java @@ -0,0 +1,23 @@ +package by.polina_kostyukovich.docks_and_hobos.actors; + +import java.util.concurrent.LinkedBlockingQueue; + +public class Tunnel { + private final LinkedBlockingQueue ships; + + public Tunnel(int maxShipsNumber) { + ships = new LinkedBlockingQueue<>(maxShipsNumber); + } + + public Ship takeShip() { + return ships.remove(); + } + + public boolean addShip(Ship ship) { + return ships.offer(ship); + } + + public boolean hasShips() { + return !ships.isEmpty(); + } +} diff --git a/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/controllers/Controller.java b/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/controllers/Controller.java new file mode 100644 index 0000000..327b9c2 --- /dev/null +++ b/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/controllers/Controller.java @@ -0,0 +1,35 @@ +package by.polina_kostyukovich.docks_and_hobos.controllers; + +import by.polina_kostyukovich.docks_and_hobos.Model; +import by.polina_kostyukovich.docks_and_hobos.actors.*; +import org.json.simple.parser.ParseException; + +import java.io.IOException; + +public class Controller { + public Controller(String filenameForReadingData) throws IOException, ParseException { + this.model = new Model(); + model.readData(filenameForReadingData); + } + + public void startRunning() { + LoggersController loggersController = new LoggersController(); + loggersController.configureLoggers(); + + new Thread(loggersController).start(); + new Thread(model.getShipGenerator()).start(); + new Thread(model.getHoboController()).start(); + + while (true) { + while (model.hasFreeDock() && model.getTunnel().hasShips()) { + Ship nextShip = model.getTunnel().takeShip(); + Dock freeDock = model.getFreeDock(); + freeDock.setFree(false); + freeDock.setCargoToAdd(nextShip.getCargo()); + new Thread(freeDock).start(); + } + } + } + + private final Model model; +} diff --git a/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/controllers/HoboController.java b/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/controllers/HoboController.java new file mode 100644 index 0000000..3f8a93b --- /dev/null +++ b/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/controllers/HoboController.java @@ -0,0 +1,222 @@ +package by.polina_kostyukovich.docks_and_hobos.controllers; + +import by.polina_kostyukovich.docks_and_hobos.actors.Dock; +import by.polina_kostyukovich.docks_and_hobos.actors.Hobo; + +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class HoboController implements Runnable { + public HoboController(ArrayList hobos, Map ingredientsCount, List docks, + int eatingTime, List allCargoTypes) { + if (hobos == null || ingredientsCount == null || docks == null || allCargoTypes == null) { + throw new IllegalArgumentException("Some parameter in HoboController constructor is null"); + } + this.hobos = hobos; + hobos.remove(hobos.size() - 1); + hobos.remove(hobos.size() - 1); + this.ingredientsCount = ingredientsCount; + this.eatingTime = eatingTime; + + cargos = new ArrayList<>(); + for (String cargoType : allCargoTypes) { + for (Dock dock : docks) { + cargos.add(new CargoToBeStolen(dock, cargoType)); + } + } + } + + @Override + public void run() { + while (true) { + goStealingAndEating(); + } + } + + private void goStealingAndEating() { + while (areAllDocksEmpty()) {} + + Map curIngrCount = new HashMap<>(ingredientsCount.size()); + curIngrCount.putAll(ingredientsCount); + checkStock(curIngrCount); + + while (containsNotOnlyZeros(curIngrCount)) { + while (hasFreeHobo()) { + tryHoboToStealCargo(curIngrCount); + } + } + + while (!areAllHobosFree()) {} + try { + LOGGER.log(Level.INFO, "Hobos started eating"); + Thread.sleep(eatingTime * 1000L); + LOGGER.log(Level.INFO, "Hobos finished eating"); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + private void tryHoboToStealCargo(Map curIngrCount) { + while (areAllDocksEmpty()) { + if (!containsNotOnlyZeros(curIngrCount)) return; + } + + List neededCargoTypes = curIngrCount.entrySet().stream() + .filter(entry -> entry.getValue() > 0) + .map(Map.Entry::getKey) + .toList(); + + boolean wasStealingDetected = false; + for (String cargoType : neededCargoTypes) { + Optional availableCargo = findAvailableCertainCargo(cargoType); + if (availableCargo.isEmpty()) continue; + + stealCargo(availableCargo.get()); + curIngrCount.compute(cargoType, (type, count) -> count - 1); + + wasStealingDetected = true; + break; + } + + if (!wasStealingDetected) { + Optional stolenCargoType = tryToStealRandomCargo(); + if (stolenCargoType.isEmpty()) return; + replaceRandomCargoInRecipe(curIngrCount, stolenCargoType.get()); + } + } + + private Optional findAvailableCertainCargo(String cargoType) { + return cargos.stream() + .filter(cargo -> cargo.getCargoType().equals(cargoType)) + .filter(cargo -> cargo.getDock().getCargos().containsKey(cargo.getCargoType()) + && cargo.getDock().getCargos().get(cargo.getCargoType()) != null) + .filter(cargo -> cargo.getStealingHobosNumber() + < cargo.getDock().getCargos().get(cargoType)) + .findAny(); + } + + private Optional tryToStealRandomCargo() { + Optional stolenCargo = cargos.stream() + .filter(cargo -> cargo.getDock().getCargos().containsKey(cargo.getCargoType()) + && cargo.getDock().getCargos().get(cargo.getCargoType()) != null + && cargo.getDock().getCargos().get(cargo.getCargoType()) > cargo.getStealingHobosNumber()) + .findAny(); + if (stolenCargo.isEmpty()) { + return Optional.empty(); + } + stealCargo(stolenCargo.get()); + return Optional.of(stolenCargo.get().getCargoType()); + } + + private void stealCargo(CargoToBeStolen cargo) { + Hobo freeHobo = getFreeHobo(); + freeHobo.setCargoToBeStolen(cargo); + cargo.incrementStealingHobosNumber(); + freeHobo.setFree(false); + new Thread(freeHobo).start(); + } + + private void replaceRandomCargoInRecipe(Map curIngrCount, String stolenCargoType) { + Optional randomCargoType = curIngrCount.entrySet().stream() + .filter(entry -> entry.getValue() > 0) + .map(Map.Entry::getKey) + .findAny(); + if (randomCargoType.isPresent()) { + curIngrCount.compute(randomCargoType.get(), (type, count) -> count - 1); + } else { + stock.computeIfPresent(stolenCargoType, (type, count) -> count + 1); + stock.putIfAbsent(stolenCargoType, 1); + } + } + + private boolean areAllDocksEmpty() { + return cargos.stream() + .filter(cargo -> cargo.getDock().getCargos().containsKey(cargo.getCargoType()) + && cargo.getDock().getCargos().get(cargo.getCargoType()) != null) + .noneMatch(cargo -> + cargo.getDock().getCargos().get(cargo.getCargoType()) > cargo.getStealingHobosNumber()); + } + + private void checkStock(Map curIngrCount) { + stock.entrySet().stream() + .filter(entry -> entry.getValue() != null && entry.getValue() > 0) + .filter(entry -> curIngrCount.containsKey(entry.getKey()) && curIngrCount.get(entry.getKey()) != null) + .forEach(entry -> { + int amountToTakeFromStock = Math.min(entry.getValue(), curIngrCount.get(entry.getKey())); + stock.compute(entry.getKey(), (type, count) -> count - amountToTakeFromStock); + curIngrCount.compute(entry.getKey(), (type, count) -> count - amountToTakeFromStock); + String strToLog = amountToTakeFromStock + " ones of " + entry.getKey() + " were taken from stock"; + LOGGER.log(Level.FINE, strToLog); + }); + } + + private boolean containsNotOnlyZeros(Map map) { + return map.values().stream() + .mapToInt(n -> n) + .anyMatch(n -> n != 0); + } + + private boolean hasFreeHobo() { + return hobos.stream() + .anyMatch(Hobo::isFree); + } + + private Hobo getFreeHobo() { + return hobos.stream() + .filter(Hobo::isFree) + .findAny().orElse(null); + } + + private boolean areAllHobosFree() { + return hobos.stream() + .allMatch(Hobo::isFree); + } + + public static Logger getLogger() { + return LOGGER; + } + + private final ArrayList hobos; + private final Map ingredientsCount; + private final int eatingTime; + private final Map stock = new HashMap<>(); + private final ArrayList cargos; + private static final Logger LOGGER = Logger.getLogger(HoboController.class.getName()); + + public static class CargoToBeStolen { + private final Dock dock; + private final String cargoType; + private final AtomicInteger stealingHobosNumber = new AtomicInteger(0); + + public CargoToBeStolen(Dock dock, String cargoType) { + if (dock == null || cargoType == null) { + throw new IllegalArgumentException("Some parameter in CargoToBeStolen constructor is null"); + } + + this.dock = dock; + this.cargoType = cargoType; + } + + public Dock getDock() { + return dock; + } + + public String getCargoType() { + return cargoType; + } + + public void incrementStealingHobosNumber() { + stealingHobosNumber.incrementAndGet(); + } + + public void decrementStealingHobosNumber() { + stealingHobosNumber.decrementAndGet(); + } + + public int getStealingHobosNumber() { + return stealingHobosNumber.get(); + } + } +} diff --git a/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/controllers/LoggersController.java b/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/controllers/LoggersController.java new file mode 100644 index 0000000..ccefae0 --- /dev/null +++ b/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/controllers/LoggersController.java @@ -0,0 +1,120 @@ +package by.polina_kostyukovich.docks_and_hobos.controllers; + +import by.polina_kostyukovich.docks_and_hobos.actors.Dock; +import by.polina_kostyukovich.docks_and_hobos.actors.Hobo; +import by.polina_kostyukovich.docks_and_hobos.actors.ShipGenerator; +import by.polina_kostyukovich.docks_and_hobos.utils.LogFormatter; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.*; + +import org.apache.commons.io.FileUtils; + +public class LoggersController implements Runnable { + public LoggersController() { + if (ShipGenerator.getLogger() == null || Dock.getLogger() == null || Hobo.getLogger() == null + || HoboController.getLogger() == null) { + throw new NullPointerException("Some logger is null"); + } + loggers.add(ShipGenerator.getLogger()); + loggers.add(Dock.getLogger()); + loggers.add(Hobo.getLogger()); + loggers.add(HoboController.getLogger()); + + try { + FileUtils.cleanDirectory(new File(PATH_TO_DIRECTORY)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public void configureLoggers() { + for (Logger logger : loggers) { + logger.setUseParentHandlers(false); + } + + ConsoleHandler consoleHandler = new ConsoleHandler(); + consoleHandler.setFormatter(formatter); + consoleHandler.setLevel(Level.INFO); + addHandler(consoleHandler); + + String filename = getNewFilenameAndCreateFile(); + try { + handler = new FileHandler(filename); + } catch (IOException e) { + throw new RuntimeException(e); + } + handler.setFormatter(formatter); + + for (Logger logger : loggers) { + logger.setLevel(Level.FINE); + } + addHandler(handler); + } + + @Override + public void run() { + while (true) { + try { + Thread.sleep(FILE_CHANGING_INTERVAL * 1000L); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + String filename = getNewFilenameAndCreateFile(); + changeHandlers(filename); + } + } + + private synchronized void changeHandlers(String filename) { + if (handler != null) { + handler.flush(); + } + + for (Logger logger : loggers) { + logger.removeHandler(handler); + } + if (handler != null) { + handler.close(); + } + + try { + handler = new FileHandler(filename); + } catch (IOException e) { + throw new RuntimeException(e); + } + handler.setFormatter(formatter); + + addHandler(handler); + } + + private void addHandler(Handler handler) { + for (Logger logger : loggers) { + logger.addHandler(handler); + } + } + + private String getNewFilenameAndCreateFile() { + File file; + String filename; + try { + do { + filename = PATH_TO_DIRECTORY + "/log file #" + numberOfNextFile + ".txt"; + file = new File(filename); + ++numberOfNextFile; + } while (!file.createNewFile()); + } catch (IOException e) { + throw new RuntimeException(e); + } + return filename; + } + + private final List loggers = new ArrayList<>(); + private final static int FILE_CHANGING_INTERVAL = 40; + private final LogFormatter formatter = new LogFormatter(); + private Handler handler; + private int numberOfNextFile = 1; + private final String PATH_TO_DIRECTORY = "src/main/java/by/polina_kostyukovich/docks_and_hobos/logs"; +} diff --git a/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/logs/log file #1.txt b/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/logs/log file #1.txt new file mode 100644 index 0000000..2f95880 --- /dev/null +++ b/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/logs/log file #1.txt @@ -0,0 +1,55 @@ +2022-11-30 19:36:53: Added ship: type - tomato, amount - 19 +2022-11-30 19:36:57: Hobo #1 stole one tomato +2022-11-30 19:36:57: Hobo #2 stole one tomato +2022-11-30 19:36:57: Hobo #0 stole one tomato +2022-11-30 19:36:57: Added ship: type - cheese, amount - 13 +2022-11-30 19:36:58: Hobo #3 stole one tomato +2022-11-30 19:36:58: Hobo #4 stole one tomato +2022-11-30 19:37:00: Dock #0 ended unloading 19 ones of tomato +2022-11-30 19:37:00: Hobo #1 stole one tomato +2022-11-30 19:37:00: Hobo #2 stole one tomato +2022-11-30 19:37:00: Hobo #0 stole one tomato +2022-11-30 19:37:01: Hobo #3 stole one tomato +2022-11-30 19:37:01: Hobo #4 stole one tomato +2022-11-30 19:37:01: Added ship: type - cheese, amount - 15 +2022-11-30 19:37:02: Dock #1 ended unloading 13 ones of cheese +2022-11-30 19:37:03: Hobo #1 stole one cheese +2022-11-30 19:37:03: Hobo #0 stole one cheese +2022-11-30 19:37:03: Hobo #2 stole one cheese +2022-11-30 19:37:04: Hobo #3 stole one cheese +2022-11-30 19:37:04: Hobo #4 stole one cheese +2022-11-30 19:37:05: Added ship: type - cucumber, amount - 14 +2022-11-30 19:37:06: Hobo #1 stole one cheese +2022-11-30 19:37:06: Hobo #0 stole one cheese +2022-11-30 19:37:06: Hobos started eating +2022-11-30 19:37:06: Dock #0 ended unloading 15 ones of cheese +2022-11-30 19:37:09: Added ship: type - cucumber, amount - 13 +2022-11-30 19:37:10: Dock #1 ended unloading 14 ones of cucumber +2022-11-30 19:37:11: Hobos finished eating +2022-11-30 19:37:13: Added ship: type - cheese, amount - 10 +2022-11-30 19:37:14: Hobo #0 stole one tomato +2022-11-30 19:37:14: Hobo #2 stole one tomato +2022-11-30 19:37:14: Hobo #3 stole one cucumber +2022-11-30 19:37:14: Hobo #1 stole one tomato +2022-11-30 19:37:14: Hobo #4 stole one cucumber +2022-11-30 19:37:14: Dock #0 ended unloading 13 ones of cucumber +2022-11-30 19:37:17: Hobo #0 stole one cucumber +2022-11-30 19:37:17: Hobo #2 stole one cucumber +2022-11-30 19:37:17: Hobo #1 stole one cheese +2022-11-30 19:37:17: Hobo #3 stole one cheese +2022-11-30 19:37:17: Hobo #4 stole one cheese +2022-11-30 19:37:17: Added ship: type - tomato, amount - 17 +2022-11-30 19:37:17: Dock #1 ended unloading 10 ones of cheese +2022-11-30 19:37:20: Hobo #0 stole one cheese +2022-11-30 19:37:20: Hobo #2 stole one cheese +2022-11-30 19:37:20: Hobo #1 stole one cheese +2022-11-30 19:37:20: Hobo #3 stole one cheese +2022-11-30 19:37:20: Hobo #4 stole one cheese +2022-11-30 19:37:21: Added ship: type - cucumber, amount - 16 +2022-11-30 19:37:23: Hobo #0 stole one cheese +2022-11-30 19:37:23: Hobo #2 stole one cheese +2022-11-30 19:37:23: Hobos started eating +2022-11-30 19:37:23: Dock #0 ended unloading 17 ones of tomato +2022-11-30 19:37:25: Added ship: type - cucumber, amount - 12 +2022-11-30 19:37:27: Dock #1 ended unloading 16 ones of cucumber +2022-11-30 19:37:28: Hobos finished eating diff --git a/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/resources/config.json b/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/resources/config.json new file mode 100644 index 0000000..13a1551 --- /dev/null +++ b/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/resources/config.json @@ -0,0 +1,46 @@ +{ + "Generating time": 4, + "Min ship capacity": 10, + "Max ship capacity": 20, + "Cargo types": [ + "bread", + "ham", + "cheese", + "butter", + "cucumber", + "tomato" + ], + "Max ships in tunnel": 3, + "Number of docks": 4, + "Unloading speed": 3, + "Dock capacity": 50, + "Number of hobos": 7, + "Ingredients count": [ + { + "Cargo type": "bread", + "Cargo amount": 2 + }, + { + "Cargo type": "ham", + "Cargo amount": 4 + }, + { + "Cargo type": "cheese", + "Cargo amount": 3 + }, + { + "Cargo type": "butter", + "Cargo amount": 1 + }, + { + "Cargo type": "cucumber", + "Cargo amount": 4 + }, + { + "Cargo type": "tomato", + "Cargo amount": 3 + } + ], + "Stealing time": 3, + "Eating time": 5 +} \ No newline at end of file diff --git a/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/utils/LogFormatter.java b/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/utils/LogFormatter.java new file mode 100644 index 0000000..3717184 --- /dev/null +++ b/lab-02/src/main/java/by/polina_kostyukovich/docks_and_hobos/utils/LogFormatter.java @@ -0,0 +1,19 @@ +package by.polina_kostyukovich.docks_and_hobos.utils; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.logging.LogRecord; +import java.util.logging.SimpleFormatter; + +public class LogFormatter extends SimpleFormatter { + public static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; + + @Override + public String format(LogRecord record) { + Date date = new Date(record.getMillis()); + DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT); + String strDate = dateFormat.format(date); + return strDate + ": " + record.getMessage() + "\n"; + } +}