import java.util.*;
import static java.lang.System.out;
/**
* A centralized supplier of grain.
*
* CS 537, Spring 2007, Project 3.
*
* This class replaces the Traders of Project 2.
* A Warehouse accepts request from Brewers and serves them as fast as
* possible. If it has multiple requests, it satisfies them in a variety of
* orders, depending on the algorithm specified in the constructor.
*/
public class Warehouse implements Runnable {
/** Source version number. */
private static final int VERSION = 2;
// Parameters that determine the behavior of this warehouse.
/** The algorithm used by this Warehouse. */
private int algorithm;
/** The number of algorithms implemented. */
private static final int NUM_ALGORITHMS = 4;
// Current state of this warehouse
/** Queue of waiting requests. */
private List waiters = new ArrayList();
/** The current stock on hand. */
private Order onHand = new Order();
/** The total amount received from the Supplier. */
private Order supplied = new Order();
/** Number of requests fulfilled. */
private int fulfilled = 0;
/** The total amount delivered to Customers. */
private Order delivered = new Order();
/** Creates a new Warehouse.
* @param algorithm the algorithm used to choose among requests.
*/
public Warehouse(int algorithm) {
if (algorithm < 1 || algorithm > NUM_ALGORITHMS) {
throw new IllegalArgumentException(
"Algorithm must be in the range 1.." + NUM_ALGORITHMS);
}
this.algorithm = algorithm;
} // Warehouse(int)
/** Accepts more grain from the supplier.
* @param amount the amount being supplied.
*/
public synchronized void deliver(Order amount) {
onHand.change(amount);
supplied.change(amount);
notify();
} // deliver(Order)
/** Accepts back grain from an interrupted request.
* @param amount the amount being returned.
*/
public synchronized void undo(Order amount) {
onHand.change(amount);
} // undo(Order)
/** Accepts a request from a Brewer and blocks the Brewer until the
* request can be satisfied.
*
* @param id the requesting Brewer's id (for debugging output).
* @param amt the request.
* @throws InterruptedException if the Brewer thread is interrupted while
* waiting for the request to be filled.
*/
public void get(int id, Order amt) throws InterruptedException {
Request req = enqueue(id, amt);
try {
req.await();
recordFulfillment(amt);
} catch (InterruptedException e) {
undo(req.getAlloc());
throw e;
}
} // get
// Other methods
/** Creates a Request object and places it onto the waiters list.
* @param id the requesting customer's id (for debugging output).
* @param amt the request.
* @return the created Order
*/
private synchronized Request enqueue(int id, Order amt) {
Request req = new Request(id, amt);
waiters.add(req);
notify();
return req;
} // enqueue(Order)
/** Main loop. */
public synchronized void run() {
for (;;) {
switch (algorithm) {
case 1: algorithm1(); break;
case 2: algorithm2(); break;
case 3: algorithm3(); break;
case 4: algorithm4(); break;
}
try {
wait();
} catch (InterruptedException e) {
P3.debug("Warehouse shutting down");
break;
}
}
out.printf("Warehouse, algorithm %d%n", algorithm);
out.printf(" Purchases fulfilled: %d%n", fulfilled);
out.printf(" Grain received: %s%n", supplied);
out.printf(" Grain delivered: %s%n", delivered);
out.printf(" Remaining stock: %s%n", onHand);
} // run()
/** Reports on the total amount of grain held by this Warehouse.
* Also audit debits and credits.
* @return an indication of the amount of each grain type held by this
* Warehouse.
*/
public synchronized Order getAmountOnHand() {
return onHand.copy();
} // getAmountOnHand()
/** Tries to satisfy and release one or more customers.
* Uses algorithm 1.
* Should be called whenever conditions change. Only called from
* synchronized methods.
*/
private void algorithm1() {
while (!waiters.isEmpty()) {
Request req = waiters.get(0);
if (req.give(onHand, 0) == 0) {
return;
}
if (req.satisfied()) {
waiters.remove(0);
req.complete();
}
}
} // algorithm1()
/** Tries to satisfy and release one or more customers.
* Uses algorithm 2.
* Should be called whenever conditions change. Only called from
* synchronized methods.
*/
private void algorithm2() {
int amt;
do {
amt = 0;
for (Iterator i = waiters.iterator(); i.hasNext(); ) {
Request req = i.next();
amt += req.give(onHand, 1);
if (req.satisfied()) {
i.remove();
req.complete();
}
}
} while (amt > 0);
} // algorithm2()
/** Tries to satisfy and release one or more customers.
* Uses algorithm 3.
* Should be called whenever conditions change. Only called from
* synchronized methods.
*/
private void algorithm3() {
while (!waiters.isEmpty()) {
Request req;
int min = Integer.MAX_VALUE;
int mini = -1;
for (int i = 0; i < waiters.size(); i++) {
req = waiters.get(i);
if (req.size() < min) {
min = req.size();
mini = i;
}
}
req = waiters.get(mini);
if (req.give(onHand, 0) == 0) {
return;
}
if (req.satisfied()) {
waiters.remove(mini);
req.complete();
}
}
} // algorithm3()
/** Tries to satisfy and release one or more customers.
* Uses algorithm 4.
* Should be called whenever conditions change. Only called from
* synchronized methods.
*/
private void algorithm4() {
while (!waiters.isEmpty()) {
Request req;
int min = Integer.MAX_VALUE;
int mini = -1;
for (int i = 0; i < waiters.size(); i++) {
req = waiters.get(i);
if (req.remaining() < min) {
min = req.remaining();
mini = i;
}
}
req = waiters.get(mini);
if (req.give(onHand, 0) == 0) {
return;
}
if (req.satisfied()) {
waiters.remove(mini);
req.complete();
}
}
} // algorithm4()
/** Record the fact that an order was fulfilled.
* @param amt the order.
*/
private synchronized void recordFulfillment(Order amt) {
fulfilled++;
delivered.change(amt);
} // recordFulfillment
} // Warehouse