From 3b99a35740e6f25d66a1d221be78aae86227d0a4 Mon Sep 17 00:00:00 2001 From: violette Date: Sun, 24 Mar 2024 13:14:37 -0400 Subject: [PATCH] Q2 done! --- src/main/java/usherbrooke/ift630/App.java | 69 +++++--- src/main/java/usherbrooke/ift630/Bus.java | 159 ++++++++++++------ .../ift630/BusInformationMessage.java | 39 +++++ .../usherbrooke/ift630/ExitException.java | 9 + .../usherbrooke/ift630/NotFoundException.java | 10 -- .../ift630/OverCapacityException.java | 10 -- .../java/usherbrooke/ift630/Passenger.java | 9 +- src/main/java/usherbrooke/ift630/Stop.java | 114 ++++++++----- .../ift630/UnauthorizedException.java | 9 + 9 files changed, 289 insertions(+), 139 deletions(-) create mode 100644 src/main/java/usherbrooke/ift630/BusInformationMessage.java create mode 100644 src/main/java/usherbrooke/ift630/ExitException.java delete mode 100644 src/main/java/usherbrooke/ift630/NotFoundException.java delete mode 100644 src/main/java/usherbrooke/ift630/OverCapacityException.java create mode 100644 src/main/java/usherbrooke/ift630/UnauthorizedException.java diff --git a/src/main/java/usherbrooke/ift630/App.java b/src/main/java/usherbrooke/ift630/App.java index e92c9ca..cc64ca9 100644 --- a/src/main/java/usherbrooke/ift630/App.java +++ b/src/main/java/usherbrooke/ift630/App.java @@ -5,51 +5,68 @@ import java.util.ArrayList; import java.util.concurrent.TimeUnit; import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; -/** - * Hello world! - * - */ +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + public class App { - static private int numStops = 10; static private int numBusses = 5; - static private int numStopPerBus = 2; - static private int numPassengersPerBus = 2; - static private int numPassengersPerStop = 5; + static private int numStopPerBus = 8; + static private int numStops = numBusses * numStopPerBus; + static private int numPassengersPerBus = 10; + static private int numPassengersPerStop = 3; static private int numPassengers = numPassengersPerStop * numStops; - static private int numThreads = 5; - static private int timeBetweenStops = 0; - static private int timeEmbark = 0; + static private int numThreadsBus = 5; + static private int numThreadsStop = 2; + static private int timeBetweenStops = 5; + static private int timeEmbark = 2; public static void main(String[] args) { - ExecutorService threads = Executors.newFixedThreadPool(numThreads); - ArrayList stops = new ArrayList(); - ArrayList busses = new ArrayList(); - ArrayList passengers = new ArrayList(); + ExecutorService threadsBus = Executors.newFixedThreadPool(numThreadsBus); + ExecutorService threadsStop = Executors.newFixedThreadPool(numThreadsStop); + ArrayList stops = new ArrayList(); + ArrayList busses = new ArrayList(); + ArrayList passengers = new ArrayList(); + BlockingQueue blockingQueue = new LinkedBlockingQueue(); + // make stops for (int k = 0; k < numStops; k++) { Stop s = new Stop(k, numPassengersPerStop); - stops.add(s); + s.setBlockingQueue(blockingQueue); - //threads.submit(s); + stops.add(s); + s.setThreadPool(threadsStop); + threadsStop.submit(s); + //s.run(); } + + // make busses for (int k = 0; k < numBusses; k++) { + if (numStopPerBus > numStops) + {System.out.println("More stops per bus than stops."); return;} + ArrayList s_list = new ArrayList(); Stop s; + // add stop. Make a bus doesnt stop multiple time at the same stop while (s_list.size() < numStopPerBus) { do { s = stops.get((int) (Math.random() * numStops)); } while (s_list.contains(s)); s_list.add(s); } + Bus b = new Bus(s_list, k, timeBetweenStops, timeEmbark, numPassengersPerBus); + b.setBlockingQueue(blockingQueue); busses.add(b); } + // make passenger int idPassenger = 0; for (Bus b : busses) { for (Stop start : b.getStops()) { + + // make sure passenger can leave. if (start == b.getTerminus()) continue; @@ -70,22 +87,30 @@ public class App { } } + // pretty print! for (Bus b : busses) { b.printDetails(); } + System.out.println("-----".repeat(5) + " START " + "-----".repeat(5)); // start bus thread // (here so init logs are clean) for (Bus b : busses) { - threads.submit(b); - //b.run(); + threadsBus.submit(b); } - threads.shutdown(); - + // block bus pool + threadsBus.shutdown(); try { - threads.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS); + threadsBus.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS); + } catch (InterruptedException e) {} + + // block stop pool once bus have finished + + threadsStop.shutdown(); + try { + threadsStop.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS); } catch (InterruptedException e) {} } } diff --git a/src/main/java/usherbrooke/ift630/Bus.java b/src/main/java/usherbrooke/ift630/Bus.java index 99fa636..402c4e4 100644 --- a/src/main/java/usherbrooke/ift630/Bus.java +++ b/src/main/java/usherbrooke/ift630/Bus.java @@ -1,31 +1,39 @@ package usherbrooke.ift630; import java.util.ArrayList; +import java.util.concurrent.BlockingQueue; public class Bus extends Thread { - private ArrayList passengers; - private ArrayList stops; - private String name; - private int id; - private int maxCapacity; - private int currentCapacity; - private int timeBetweenStops; - private int timeEmbark; - private Stop nextStop; + private ArrayList passengers; + private ArrayList stops; + private String name; + private int id; + private int maxCapacity; + private int currentCapacity; + private int timeBetweenStops; + private int timeToNextStop; + private int timeEmbark; + private Stop nextStop; + private BlockingQueue blockingQueue; + // returns time for a single passenger to embark. private int timeEmbark() { return (int) (Math.random() * timeEmbark); } - private int timeBetweenStops() { - return (int) (Math.random() * timeBetweenStops); + // set time between stop. + private int calculateTimeBetweenStops() { + timeToNextStop = (int) ((timeBetweenStops / 3) + (Math.random() * 2 * timeBetweenStops / 3)); + return timeToNextStop; } + // check if a passenger must leave at next stop. private boolean stopAsked() { boolean res = false; for (Passenger p : passengers){ if (p.getDest() == nextStop) { res = true; + Logger.getInstance().print(id, "[BUS] " + name + " stop asked!"); break; } } @@ -33,25 +41,39 @@ public class Bus extends Thread { return res; } - private Stop goToNextStop() { + // travel to next stop. Waits the travel time. + private Stop goToNextStop() throws InterruptedException, IndexOutOfBoundsException { // if no reason to stop, skip current stop - try { - do { - nextStop = stops.remove(0); - } while ((getNextStopPassengers().isEmpty() || currentCapacity >= maxCapacity) && !stopAsked()); + boolean nextStopEmpty, overMaxCapacity; + do { + nextStop = stops.remove(0); - } catch (IndexOutOfBoundsException e) { - nextStop = null; - } + sendNextStopInfo(); + + waitStop(); + + overMaxCapacity = currentCapacity >= maxCapacity; + nextStopEmpty = getNextStopPassengers().isEmpty(); + + if (overMaxCapacity) + Logger.getInstance().print(id, "[BUS] " + name + " im full, sorry!"); + if (nextStopEmpty && !stopAsked()) + Logger.getInstance().print(id, "[BUS] " + name + " next " + nextStop.getStopName() + " is empty!"); + } while (!stopAsked() && (nextStopEmpty || overMaxCapacity)); - try { - Thread.sleep(timeBetweenStops() * 1000); - } catch (InterruptedException e) { - } return nextStop; } - // TODO what + // send Bus info msg to next stop + private void sendNextStopInfo() throws InterruptedException{ + BusInformationMessage info = new BusInformationMessage(this, nextStop, timeToNextStop); + synchronized(blockingQueue) { + blockingQueue.put(info); + } + } + + // get all passenger waiting at next stop + // useful for knowing if we should stop private ArrayList getNextStopPassengers() { ArrayList res = new ArrayList(); @@ -66,57 +88,82 @@ public class Bus extends Thread { return res; } + // lock until passenger got in + private void waitEmbark() throws InterruptedException { + synchronized (this) { + sleep(timeEmbark()); + } + } + + // lock until passenger got out + private void waitStop() throws InterruptedException { + synchronized (this) { + sleep(timeToNextStop); + } + } + @Override public void run() { try { - while (nextStop != null) { - Logger.getInstance().print(id, "[BUS] hop into " + name + " at stop " + nextStop.getName() + "!"); - disembarkPassengers(); - embarkPassengers(); + // run until terminus + while (nextStop != null) { + // new stop ! + Logger.getInstance().print(id, "[BUS] " + name + " reached stop " + nextStop.getStopName() + "!"); - nextStop = goToNextStop(); + disembarkPassengers(); + embarkPassengers(); + calculateTimeBetweenStops(); + + try { + nextStop = goToNextStop(); + } catch (IndexOutOfBoundsException e) { + nextStop = null; + } + } + } catch (InterruptedException e) { + Logger.getInstance().print(id, "[BUS] exception: " + e.toString()); } - } catch (Exception e) { - Logger.getInstance().print(id, "[BUS] exception: " + e.getMessage()); - } - Logger.getInstance().print(id, "[BUS]" + name + " exiting!"); + Logger.getInstance().print(id, "[BUS] " + name + " exiting!"); } Bus(ArrayList s, int id, int timeStop, int timeEmbark, int maxCapacity) { - this.timeBetweenStops = timeStop; - this.timeEmbark = timeEmbark; + this.timeBetweenStops = timeStop * 1000 + 1; + this.timeEmbark = timeEmbark * 1000 + 1; this.name = "Bus n°" + id; this.id = id; this.passengers = new ArrayList(); this.stops = s; - this.nextStop = stops.remove(0); + this.nextStop = stops.get(0); this.currentCapacity = 0; this.maxCapacity = maxCapacity; } - public synchronized void disembarkPassengers() { - Logger.getInstance().print(id, "[BUS] waiting mutex for " + nextStop.getName()); - synchronized (nextStop.getMutex()) { + // disembark passenger at a stop. Synchronizes, locks on that stop, and waits. + public synchronized void disembarkPassengers() throws InterruptedException { + // lock on next stop + synchronized (nextStop) { for (Passenger p : passengers) { + waitEmbark(); + Logger.getInstance().print(id, - "\t[DISEMBARK] " + p.getName() + " at " + nextStop.getName()); + "\t[DISEMBARK] " + p.getName() + " at " + nextStop.getStopName()); if (p.getDest() == nextStop) { p.disembark(); currentCapacity--; } } - Logger.getInstance().print(id, "[BUS] release mutex for " + nextStop.getName()); } } - public synchronized void embarkPassengers() { - Logger.getInstance().print(id, "[BUS] waiting mutex for " + nextStop.getName()); - synchronized (nextStop.getMutex()) { + // embark passenger at a stop. Synchronizes, locks on that stop, and waits. + // check for overflow, and if passenger should embark in the first place + public synchronized void embarkPassengers() throws InterruptedException { + synchronized (nextStop) { try { ArrayList list = nextStop.getPassengerByDest(stops); for (Passenger p : list) { - Thread.sleep(timeEmbark() * 1000); + waitEmbark(); if (currentCapacity >= maxCapacity) continue; passengers.add(p); @@ -124,40 +171,46 @@ public class Bus extends Thread { currentCapacity++; Logger.getInstance().print(id, - "\t[EMBARK] " + p.getName() + " at " + nextStop.getName()); + "\t[EMBARK] " + p.getName() + " at " + nextStop.getStopName()); } - } catch (IndexOutOfBoundsException | InterruptedException e) { + } catch (IndexOutOfBoundsException e) { Logger.getInstance().print(id, "Exception: " + e.getMessage()); } - Logger.getInstance().print(id, "[BUS] release mutex for " + nextStop.getName()); } } + // pretty print! public void printDetails(int indent) { Logger.getInstance().print(id, "\t".repeat(indent) + "---".repeat(3) + " Bus details " + "---".repeat(3)); Logger.getInstance().print(id, "\t".repeat(indent) + name); Logger.getInstance().print(id, "\t".repeat(indent) + "time between stops: " + timeBetweenStops); Logger.getInstance().print(id, "\t".repeat(indent) + "max capacity: " + maxCapacity); - Logger.getInstance().print(id, "\t".repeat(indent) + "current stop: " + nextStop.getName()); + Logger.getInstance().print(id, "\t".repeat(indent) + "current stop: " + nextStop.getStopName()); Logger.getInstance().print(id, "\t".repeat(indent) + "stops: "); - nextStop.printDetails(id, indent + 1); + + if (nextStop != stops.get(0)) + nextStop.printDetails(id, indent + 1); for (Stop s : stops) { s.printDetails(id, indent + 1); } } + // pretty print w/ 0 indent public void printDetails() { printDetails(0); } + // return stop list public ArrayList getStops() { ArrayList res = new ArrayList(stops); - res.add(0, nextStop); + if (nextStop != stops.get(0)) + res.add(0, nextStop); return res; } + // return last stop public Stop getTerminus() { return stops.get(stops.size() - 1); } @@ -165,4 +218,8 @@ public class Bus extends Thread { public String getNameBus() { return name; } + + public void setBlockingQueue(BlockingQueue q) { + blockingQueue = q; + } } diff --git a/src/main/java/usherbrooke/ift630/BusInformationMessage.java b/src/main/java/usherbrooke/ift630/BusInformationMessage.java new file mode 100644 index 0000000..109751b --- /dev/null +++ b/src/main/java/usherbrooke/ift630/BusInformationMessage.java @@ -0,0 +1,39 @@ +package usherbrooke.ift630; + +class BusInformationMessage { + private Bus bus; // origin + private Stop stop; //dest + private int timeToStop; // info + + public BusInformationMessage(Bus b, Stop s, int time) { + this.bus = b; + this.stop = s; + this.timeToStop = time; + } + + // throws unauth if stop shouldt see + public Bus getBus(Stop s) throws UnauthorizedException { + if (s != stop) { + throw new UnauthorizedException("UnauthorizedException"); + } + + return bus; + } + + // throws unauth if stop shouldt see + public Stop getStop(Stop s) throws UnauthorizedException { + if (s != stop) { + throw new UnauthorizedException("UnauthorizedException"); + } + + return stop; + } + + // throws unauth if stop shouldt see + public int getTimeToStop(Stop s) throws UnauthorizedException { + if (s != stop) { + throw new UnauthorizedException("UnauthorizedException"); + } + return timeToStop; + } +} diff --git a/src/main/java/usherbrooke/ift630/ExitException.java b/src/main/java/usherbrooke/ift630/ExitException.java new file mode 100644 index 0000000..7ec3e2d --- /dev/null +++ b/src/main/java/usherbrooke/ift630/ExitException.java @@ -0,0 +1,9 @@ +package usherbrooke.ift630; + +public class ExitException extends Exception { + ExitException() {} + + public ExitException(String message) { + super(message); + } +} diff --git a/src/main/java/usherbrooke/ift630/NotFoundException.java b/src/main/java/usherbrooke/ift630/NotFoundException.java deleted file mode 100644 index 5e53278..0000000 --- a/src/main/java/usherbrooke/ift630/NotFoundException.java +++ /dev/null @@ -1,10 +0,0 @@ -package usherbrooke.ift630; - -public class NotFoundException extends Exception { - NotFoundException() {} - - public NotFoundException(String message) - { - super(message); - } -} diff --git a/src/main/java/usherbrooke/ift630/OverCapacityException.java b/src/main/java/usherbrooke/ift630/OverCapacityException.java deleted file mode 100644 index 5388909..0000000 --- a/src/main/java/usherbrooke/ift630/OverCapacityException.java +++ /dev/null @@ -1,10 +0,0 @@ -package usherbrooke.ift630; - -public class OverCapacityException extends Exception { - OverCapacityException() {} - - public OverCapacityException(String message) - { - super(message); - } -} diff --git a/src/main/java/usherbrooke/ift630/Passenger.java b/src/main/java/usherbrooke/ift630/Passenger.java index eae88ba..df1213c 100644 --- a/src/main/java/usherbrooke/ift630/Passenger.java +++ b/src/main/java/usherbrooke/ift630/Passenger.java @@ -14,8 +14,10 @@ public class Passenger { this.start = start; } + // unused, *yet* public synchronized void embark() {} + // unused, *yet* public synchronized void disembark() {} public Stop getStart() { @@ -30,16 +32,19 @@ public class Passenger { return name; } + // Pretty print, with color! public void printDetails(int color, int indent) { Logger.getInstance().print(color, "\t".repeat(indent) + "---".repeat(3) + " Passenger details " + "---".repeat(3)); - Logger.getInstance().print(color, "\t".repeat(indent) + name + " start: " + start.getName() + " dest: " + dest.getName()); + Logger.getInstance().print(color, "\t".repeat(indent) + name + " start: " + start.getStopName() + " dest: " + dest.getStopName()); } + // Pretty print, with indent! public void printDetails(int indent) { Logger.getInstance().print(id, "\t".repeat(indent) + "---".repeat(3) + " Passenger details " + "---".repeat(3)); - Logger.getInstance().print(id, "\t".repeat(indent) + name + " start: " + start.getName() + " dest: " + dest.getName()); + Logger.getInstance().print(id, "\t".repeat(indent) + name + " start: " + start.getStopName() + " dest: " + dest.getStopName()); } + // Pretty print! public void printDetails() { printDetails(0); } diff --git a/src/main/java/usherbrooke/ift630/Stop.java b/src/main/java/usherbrooke/ift630/Stop.java index 7e1c0f3..b370dc7 100644 --- a/src/main/java/usherbrooke/ift630/Stop.java +++ b/src/main/java/usherbrooke/ift630/Stop.java @@ -1,37 +1,66 @@ package usherbrooke.ift630; import java.util.ArrayList; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ExecutorService; -public class Stop implements Runnable { - private String name; - private int id; - private int maxCapacity; - private ArrayList passengers; - private Lock mutex = new ReentrantLock(); +public class Stop extends Thread { + private String name; + private int id; + private int maxCapacity; + private int indent = 0; + private ArrayList passengers; + private ExecutorService threads; + private BlockingQueue blockingQueue; + + + // print bus info times. + private void displayInfos(int indent) throws InterruptedException, ExitException{ + BusInformationMessage info = null; + + // lock queue, get head + synchronized (blockingQueue) { + info = blockingQueue.poll(); + } + // get infos + try { + try { + int time = info.getTimeToStop(this) / 1000; + // if everything is alright, print + Logger.getInstance().print(id, + "\t".repeat(indent) + "[STOP] " + info.getBus(this).getNameBus() + " arrives in " + time + "s"); + // else, catch + } catch (NullPointerException e) {} + + } catch (UnauthorizedException e) { + // if unauth, requeue message. + synchronized (blockingQueue) { + blockingQueue.add(info); + } + } + + // loop, and ensure that every stop is reactive + synchronized (this) { + threads.submit(this); + sleep(10); + throw new ExitException(); + } + } - // TODO lock mutex when stop is used @Override public void run() { - // xd do nothing for now - //for (Passenger p : passengers) { - // // - //} + try { + for (;;) { + displayInfos(indent); + } + } catch (InterruptedException | ExitException e) {} } - // run once. Then, queue the same thread, and exit. - // Message a bus their current number of passenger ; and the - // number of passenger willing to take this bus. Stop(int id, int maxCapacity) { - this.id = id; - this.name = "Stop " + id; - this.passengers = new ArrayList(); - this.maxCapacity = maxCapacity; - } - - public Passenger getPassenger() { - return passengers.get(0); + this.id = id; + this.name = "Stop " + id; + this.passengers = new ArrayList(); + this.maxCapacity = maxCapacity; } public void addPassenger(Passenger p) { @@ -40,10 +69,12 @@ public class Stop implements Runnable { // return all passenger that stops at a stop in the list public ArrayList getPassengerByDest(ArrayList list) { - // res for a little cleaner code ArrayList res = new ArrayList(); + // for all given stop for (Stop s : list) { + // for all passenger at this stop for (Passenger p : passengers) { + // if they stop at this stop, add to res if (p.getDest() == s) { res.add(p); } @@ -53,7 +84,7 @@ public class Stop implements Runnable { return res; } - public String getName() { + public String getStopName() { return name; } @@ -65,10 +96,6 @@ public class Stop implements Runnable { return maxCapacity; } - public Lock getMutex() { - return mutex; - } - public void printDetails(int color, int indent) { Logger.getInstance().print(color, "\t".repeat(indent) + "---".repeat(3) + " Stop details " + "---".repeat(3)); Logger.getInstance().print(color, "\t".repeat(indent) + name); @@ -91,24 +118,23 @@ public class Stop implements Runnable { printDetails(0); } - public void busArrive() { - synchronized(this) { - mutex.lock(); - } - } - - public void busLeave() { - synchronized(this) { - mutex.unlock(); - } - } - public void removePassenger(Passenger p) { - // Logger.getInstance().print(id, "Passenger " + p.getName() + " left " + name); try { passengers.remove(p); - } catch(Exception e) { + } catch (Exception e) { System.out.println("exception" + e.getMessage()); } } + + public void setIndent(int indent) { + this.indent = indent; + } + + public void setBlockingQueue(BlockingQueue q) { + blockingQueue = q; + } + + public void setThreadPool(ExecutorService threads) { + this.threads = threads; + } } diff --git a/src/main/java/usherbrooke/ift630/UnauthorizedException.java b/src/main/java/usherbrooke/ift630/UnauthorizedException.java new file mode 100644 index 0000000..80b4f72 --- /dev/null +++ b/src/main/java/usherbrooke/ift630/UnauthorizedException.java @@ -0,0 +1,9 @@ +package usherbrooke.ift630; + +public class UnauthorizedException extends Exception { + public UnauthorizedException() {} + + public UnauthorizedException(String message) { + super(message); + } +}