1 package at.ac.tuwien.sbc.valesriegler.xvsm;
3 import java.io.Serializable;
5 import java.util.Arrays;
6 import java.util.Collections;
7 import java.util.Iterator;
10 import at.ac.tuwien.sbc.valesriegler.common.OrderId;
11 import org.mozartspaces.capi3.AnyCoordinator;
12 import org.mozartspaces.capi3.FifoCoordinator;
13 import org.mozartspaces.capi3.LindaCoordinator;
14 import org.mozartspaces.core.ContainerReference;
15 import org.mozartspaces.core.MzsConstants;
16 import org.mozartspaces.core.MzsConstants.RequestTimeout;
17 import org.mozartspaces.core.MzsCoreException;
18 import org.mozartspaces.core.TransactionException;
19 import org.mozartspaces.core.TransactionReference;
20 import org.mozartspaces.notifications.Notification;
21 import org.mozartspaces.notifications.NotificationListener;
22 import org.mozartspaces.notifications.Operation;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
26 import at.ac.tuwien.sbc.valesriegler.common.Util;
27 import at.ac.tuwien.sbc.valesriegler.types.GroupData;
28 import at.ac.tuwien.sbc.valesriegler.types.GroupState;
29 import at.ac.tuwien.sbc.valesriegler.types.Order;
30 import at.ac.tuwien.sbc.valesriegler.types.OrderStatus;
31 import at.ac.tuwien.sbc.valesriegler.types.Pizza;
32 import at.ac.tuwien.sbc.valesriegler.types.Table;
34 public class WaiterXVSM extends AbstractXVSMConnector {
35 private static final Logger log = LoggerFactory.getLogger(WaiterXVSM.class);
36 private final int waiterId;
38 public WaiterXVSM(int waiterId) {
41 this.waiterId = waiterId;
43 freeTablesContainer = useContainer(Util.FREE_TABLES);
44 assignTableContainer = useContainer(Util.ASSIGN_TABLE);
45 takeOrderContainer = useContainer(Util.TAKE_ORDER);
46 orderTakenContainer = useContainer(Util.ORDER_TAKEN);
47 preparePizzasContainer = useContainer(Util.PREPARE_PIZZAS);
48 orderCompleteContainer = useContainer(Util.ORDER_COMPLETE);
49 deliverPizzasContainer = useContainer(Util.DELIVER_PIZZAS);
50 paymentRequestContainer = useContainer(Util.PAYMENT_REQUEST);
51 paymentDoneContainer = useContainer(Util.PAYMENT_DONE);
52 tableAssignedContainer = useContainer(Util.TABLE_ASSIGNED);
53 infoContainer = useContainer(Util.INFO);
56 public void listenForFreeTable() {
57 SpaceListener listener = new SpaceListenerImpl(capi, freeTablesContainer, false) {
60 void onEntriesWritten(List<? extends Serializable> entries) throws Exception {
62 List<Table> tables = castEntries(entries);
64 for (Table table : tables) {
66 TransactionReference tx = capi.createTransaction(
67 Util.SPACE_TRANSACTION_TIMEOUT,
68 URI.create(Util.SERVER_ADDR));
70 // Acquire a lock for the free table in the
72 int id = table.getId();
74 Table tableTemplate = new Table(id);
76 Table lockedFreeTable = takeMatchingEntity(tableTemplate,
77 freeTablesContainer, tx, RequestTimeout.DEFAULT,
78 String.format("There was no free table found with id %d", id));
81 GroupData groupTemplate = new GroupData();
82 GroupData lockedGroup = takeMatchingEntity(groupTemplate,
83 assignTableContainer, tx, RequestTimeout.DEFAULT,
84 "There is no group waiting for a table at the moment");
86 assignGroupToTable(lockedGroup, lockedFreeTable, tx);
87 } catch (Exception e) {
88 // log.info(e.getMessage());
94 createNotification(listener, freeTablesContainer);
99 public void listenForNewGuests() {
100 SpaceListener listener = new SpaceListenerImpl(capi, assignTableContainer) {
103 void onEntriesWritten(List<? extends Serializable> entries)
105 log.info("New guest groups have arrived");
107 List<GroupData> groups = castEntries(entries);
109 for (GroupData group : groups) {
111 TransactionReference tx = capi.createTransaction(
112 Util.SPACE_TRANSACTION_TIMEOUT,
113 URI.create(Util.SERVER_ADDR));
115 // Acquire a lock for the group in the
116 // AssignTableContainer
117 String groupNotFound = String.format("Group with id %d was already assigned a table by another waiter!", group.getId());
120 GroupData lockedGroup = takeMatchingEntity(
121 new GroupData(group.getId()),
122 assignTableContainer, tx,
123 RequestTimeout.DEFAULT, groupNotFound);
124 // Acquire a lock for one free table in the
126 String noFreeTable = String.format("No free table for group with id %d could be found", group.getId());
127 Table lockedFreeTable = takeMatchingEntity(new Table(null), freeTablesContainer, tx, RequestTimeout.DEFAULT,
130 assignGroupToTable(lockedGroup, lockedFreeTable, tx);
131 } catch (Exception e) {
132 // log.info(e.getMessage());
138 createNotification(listener, assignTableContainer);
141 public void listenForPaymentRequest() {
142 SpaceListener paymentListener = new SpaceListenerImpl(capi, paymentRequestContainer) {
145 void onEntriesWritten(List<? extends Serializable> entries)
148 List<GroupData> groups = castEntries(entries);
150 for (GroupData groupData : groups) {
151 TransactionReference tx = capi.createTransaction(
152 Util.SPACE_TRANSACTION_TIMEOUT,
153 URI.create(Util.SERVER_ADDR));
154 GroupData entity = new GroupData(groupData.getId());
156 // Acquire the lock so that another waiter can't do the same
158 String paymentRequestTakenByOtherWaiter = String.format(
159 "The payment request for group %d was already taken by an other waiter!",
162 takeMatchingEntity(entity, paymentRequestContainer, tx, RequestTimeout.DEFAULT, paymentRequestTakenByOtherWaiter);
164 groupData.setPayingWaiter(waiterId);
166 sendItemsToContainer(Arrays.asList(groupData), paymentDoneContainer, RequestTimeout.ZERO, tx);
168 capi.commitTransaction(tx);
169 } catch (Exception e) {
170 // log.info(e.getMessage());
176 createNotification(paymentListener, paymentRequestContainer);
179 public void listenForOrderRequests() {
180 SpaceListener ordersListener = new SpaceListenerImpl(capi, takeOrderContainer) {
183 void onEntriesWritten(List<? extends Serializable> entries)
186 List<GroupData> groups = castEntries(entries);
188 for (GroupData groupData : groups) {
190 TransactionReference tx = capi.createTransaction(
191 Util.SPACE_TRANSACTION_TIMEOUT,
192 URI.create(Util.SERVER_ADDR));
193 GroupData entity = new GroupData(groupData.getId());
194 entity.setState(GroupState.SITTING);
197 // Acquire the lock so that another waiter can't do the same thing!
198 String orderTakenByOtherWaiter = String.format(
199 "The order for group %d was already taken by an other waiter!",
201 takeMatchingEntity(entity, takeOrderContainer, tx, RequestTimeout.DEFAULT, orderTakenByOtherWaiter);
203 groupData.setOrderWaiter(waiterId);
204 groupData.setState(GroupState.ORDERED);
205 Order order = groupData.getOrder();
206 order.setStatus(OrderStatus.ORDERED);
208 /* get the id of the last order of the pizzeria and set the order accordingly and
210 final OrderId orderId = takeMatchingEntity(new OrderId(null), infoContainer, tx, RequestTimeout.INFINITE, "The Order id object could not be taken from the space!");
211 final int id = orderId.getId();
213 sendItemsToContainer(Arrays.asList(new OrderId(id+1)), infoContainer, RequestTimeout.DEFAULT, tx);
215 // send the order as a whole to the space
216 sendItemsToContainer(Arrays.asList(groupData),
217 orderTakenContainer, RequestTimeout.ZERO, tx);
218 sendItemsToContainer(order.getOrderedPizzas(),
219 preparePizzasContainer, RequestTimeout.ZERO, tx);
220 capi.commitTransaction(tx);
222 log.info("Waiter has taken order from group {}",
224 } catch (Exception e) {
225 // log.info(e.getMessage());
231 createNotification(ordersListener, takeOrderContainer);
234 public void listenForPreparedPizzas() {
236 * A waiter gets informed when a new pizza is complete. He takes the
237 * orderId of the pizza and looks up the corresponding order from which
238 * he gets the number of necessary pizzas of the order. He then tries to
239 * fetch all pizzas with the corresponding orderId and compares the
240 * number of those pizzas with the number of necessary pizzas. If all
241 * pizzas of an order are complete he then delivers them!
243 SpaceListener preparedPizzasListener = new SpaceListenerImpl(capi, deliverPizzasContainer) {
246 void onEntriesWritten(List<? extends Serializable> entries)
249 List<Pizza> pizzas = castEntries(entries);
251 for (Pizza pizza : pizzas) {
252 int orderId = pizza.getOrderId();
254 TransactionReference tx = capi.createTransaction(
255 Util.SPACE_TRANSACTION_TIMEOUT,
256 URI.create(Util.SERVER_ADDR));
259 GroupData entity = new GroupData();
260 entity.setState(null);
261 Order order = new Order();
262 order.setId(orderId);
263 entity.setOrder(order);
265 GroupData groupData = takeMatchingEntity(entity,
266 orderTakenContainer, tx, RequestTimeout.DEFAULT,
267 "Another waiter just checks if the order is complete");
268 int groupId = groupData.getId();
269 int numberOfPizzas = groupData.getOrder().getNumberOfPizzas();
271 Pizza pizzaTemplate = new Pizza();
272 pizzaTemplate.setOrderId(orderId);
274 List<Pizza> pizzasOfOrder = takeMatchingEntities(
275 pizzaTemplate, deliverPizzasContainer, tx,
276 RequestTimeout.DEFAULT,
277 "Cannot take the pizzas from the deliverPizzasContainer");
279 if (pizzasOfOrder.size() == numberOfPizzas) {
280 GroupData group = new GroupData();
281 group.setServingWaiter(waiterId);
282 Order completeOrder = new Order();
283 completeOrder.setId(orderId);
284 completeOrder.setGroupId(groupId);
285 group.setOrder(completeOrder);
286 sendItemsToContainer(Arrays.asList(group),
287 orderCompleteContainer, RequestTimeout.DEFAULT,
289 capi.commitTransaction(tx);
291 log.info("Not yet all pizzas prepared! Order with id "
292 + orderId + " has " + numberOfPizzas
293 + " pizzas, but only " + pizzasOfOrder.size()
294 + " pizzas are ready by now!");
295 capi.rollbackTransaction(tx);
297 } catch (NullPointerException e) {
299 } catch (Exception e) {
300 capi.rollbackTransaction(tx);
306 createNotification(preparedPizzasListener, deliverPizzasContainer);
309 private void assignGroupToTable(GroupData lockedGroup,
310 Table lockedFreeTable, TransactionReference tx)
311 throws MzsCoreException {
312 // The new group sits down at the table
313 lockedFreeTable.setGroupId(lockedGroup.getId());
315 // The new group now wants to order
316 lockedGroup.setState(GroupState.SITTING);
317 lockedGroup.setTable(lockedFreeTable);
318 lockedGroup.setTableWaiter(waiterId);
320 sendItemsToContainer(Arrays.asList(lockedFreeTable),
321 tableAssignedContainer, RequestTimeout.ZERO, tx);
322 sendItemsToContainer(Arrays.asList(lockedGroup), takeOrderContainer,
323 RequestTimeout.ZERO, tx);
326 capi.commitTransaction(tx);
327 log.info("Assigned table to group with groupId {}",
328 lockedGroup.getId());
329 } catch (Exception e) {
330 log.info("Assigning a table to group with groupId {} failed",
331 lockedGroup.getId());
332 log.info(e.getMessage());