1 package at.ac.tuwien.sbc.valesriegler.xvsm;
3 import java.io.Serializable;
5 import java.util.ArrayList;
6 import java.util.Arrays;
7 import java.util.Collections;
8 import java.util.Iterator;
11 import javax.swing.text.html.parser.Entity;
13 import org.mozartspaces.capi3.AnyCoordinator;
14 import org.mozartspaces.capi3.LindaCoordinator;
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);
55 public void listenForFreeTable() {
57 NotificationListener freeTableListener = new NotificationListener() {
59 public void entryOperationFinished(final Notification notification,
60 final Operation operation,
61 final List<? extends Serializable> entries) {
63 log.info("{} tables have become free", entries.size());
65 List<Table> tables = castEntries(entries);
66 Collections.rotate(tables, waiterId);
68 for (Table table : tables) {
70 TransactionReference tx = capi.createTransaction(3000,
71 URI.create(Util.SERVER_ADDR));
74 // Acquire a lock for the free table in the
76 int id = table.getId();
77 log.info("Try to find the table with id {}", id);
79 Table tableTemplate = new Table(id);
80 Table lockedFreeTable = takeMatchingEntity(
86 "There was no free table found with id %d",
89 log.info("Table with id {} was found", id);
91 GroupData groupTemplate = new GroupData();
92 GroupData lockedGroup = takeMatchingEntity(
93 groupTemplate, assignTableContainer, tx,
94 RequestTimeout.DEFAULT,
95 "There is no group waiting for a table at the moment");
97 assignGroupToTable(lockedGroup, lockedFreeTable, tx);
99 } catch (IllegalArgumentException e) {
100 log.info("IllegalArgumentException");
102 } catch (EntityNotFoundByTemplate e) {
103 log.info(e.getMessage());
104 } catch (Exception e) {
105 log.error("AN INNER EXCEPTION");
108 } catch (TransactionException e) {
109 log.info("An unimportant TransactionException has occurred");
110 } catch (Exception e) {
111 log.error("OUTER EXCEPTION");
118 notificationMgr.createNotification(freeTablesContainer,
119 freeTableListener, Operation.WRITE);
120 log.info("Created freeTablesContainer notification for a waiter");
121 } catch (Exception e) {
122 handleSpaceErrorAndTerminate(e);
127 public void listenForNewGuests() {
128 NotificationListener newGroupsListener = new NotificationListener() {
130 public void entryOperationFinished(final Notification notification,
131 final Operation operation,
132 final List<? extends Serializable> entries) {
134 log.info("New guest groups have arrived");
136 List<GroupData> groups = castEntries(entries);
137 Collections.rotate(groups, waiterId);
139 for (GroupData group : groups) {
141 TransactionReference tx = capi.createTransaction(1500,
142 URI.create(Util.SERVER_ADDR));
145 // Acquire a lock for the group in the
146 // AssignTableContainer
147 String groupNotFound = String
148 .format("Group with id %d was already assigned a table by another waiter!",
151 GroupData lockedGroup = takeMatchingEntity(
152 new GroupData(group.getId()),
153 assignTableContainer, tx, 1000,
155 // Acquire a lock for one free table in the
157 Table lockedFreeTable = takeMatchingEntity(
161 RequestTimeout.DEFAULT,
163 "No free table for group with id %d could be found",
166 assignGroupToTable(lockedGroup, lockedFreeTable, tx);
168 } catch (IllegalArgumentException e) {
169 log.info("IllegalArgumentException");
171 } catch (EntityNotFoundByTemplate e) {
172 log.info(e.getMessage());
173 } catch (Exception e) {
174 log.error("AN INNER EXCEPTION");
177 } catch (TransactionException e) {
178 log.info("An unimportant TransactionException has occurred");
179 } catch (Exception e) {
180 log.error("OUTER EXCEPTION");
187 notificationMgr.createNotification(assignTableContainer,
188 newGroupsListener, Operation.WRITE);
189 log.info("Created assingTableContainer notification for a waiter");
190 } catch (Exception e) {
191 handleSpaceErrorAndTerminate(e);
195 public void listenForPaymentRequest() {
196 log.info("INITIALIZE PAYMENT NOTIFICATION");
197 NotificationListener paymentListener = new NotificationListener() {
199 public void entryOperationFinished(final Notification notification,
200 final Operation operation,
201 final List<? extends Serializable> entries) {
202 log.info("A PAYMENT REQUEST HAS ARRIVED!");
204 List<GroupData> groups = castEntries(entries);
206 GroupData groupData = groups.get(0);
209 TransactionReference tx = capi.createTransaction(1500,
210 URI.create(Util.SERVER_ADDR));
211 GroupData entity = new GroupData(groupData.getId());
213 // Acquire the lock so that another waiter can't do the same
217 paymentRequestContainer,
219 RequestTimeout.DEFAULT,
221 "The payment request for group %d was already taken by an other waiter!",
225 groupData.setPayingWaiter(waiterId);
227 sendItemsToContainer(Arrays.asList(groupData),
228 paymentDoneContainer, RequestTimeout.ZERO, tx);
230 capi.commitTransaction(tx);
232 } catch (MzsCoreException e) {
233 log.info("ERROR in listenForPaymentRequest");
240 notificationMgr.createNotification(paymentRequestContainer,
241 paymentListener, Operation.WRITE);
242 log.info("Created payment notification for a waiter");
243 } catch (Exception e) {
244 handleSpaceErrorAndTerminate(e);
248 public void listenForOrderRequests() {
249 NotificationListener ordersListener = new NotificationListener() {
251 public void entryOperationFinished(final Notification notification,
252 final Operation operation,
253 final List<? extends Serializable> entries) {
254 log.info("A new order has arrived!");
256 List<GroupData> groups = castEntries(entries);
257 if (groups.size() != 1)
258 throw new RuntimeException(
259 "Multiple orders in one notification?! That should not happen!");
261 GroupData groupData = groups.get(0);
264 TransactionReference tx = capi.createTransaction(1500,
265 URI.create(Util.SERVER_ADDR));
266 GroupData entity = new GroupData(groupData.getId());
267 entity.setState(GroupState.SITTING);
269 // Acquire the lock so that another waiter can't do the same
275 RequestTimeout.DEFAULT,
277 "The order for group %d was already taken by an other waiter!",
281 "Will now write taken order from group {} to space",
283 groupData.setOrderWaiter(waiterId);
284 groupData.setState(GroupState.ORDERED);
285 Order order = groupData.getOrder();
286 order.setStatus(OrderStatus.ORDERED);
288 sendItemsToContainer(Arrays.asList(groupData),
289 orderTakenContainer, RequestTimeout.ZERO, tx);
290 sendItemsToContainer(order.getOrderedPizzas(),
291 preparePizzasContainer, RequestTimeout.ZERO, tx);
292 capi.commitTransaction(tx);
294 log.info("Waiter has taken order from group {}",
296 } catch (MzsCoreException e) {
297 log.info("ERROR in listenForOrders");
304 notificationMgr.createNotification(takeOrderContainer,
305 ordersListener, Operation.WRITE);
306 log.info("Created takeOrderContainer notification for a waiter");
307 } catch (Exception e) {
308 handleSpaceErrorAndTerminate(e);
312 public void listenForPreparedPizzas() {
314 * A waiter gets informed when a new pizza is complete. He takes the
315 * orderId of the pizza and looks up the corresponding order from which
316 * he gets the number of necessary pizzas of the order. He then tries to
317 * fetch all pizzas with the corresponding orderId and compares the
318 * number of those pizzas with the number of necessary pizzas. If all
319 * pizzas of an order are complete he then delivers them!
321 NotificationListener preparedPizzasListener = new NotificationListener() {
323 public void entryOperationFinished(final Notification notification,
324 final Operation operation,
325 final List<? extends Serializable> entries) {
327 List<Pizza> pizzas = castEntries(entries);
328 if (pizzas.size() != 1)
329 throw new RuntimeException(
330 "Multiple pizzas in one notification?! That should not happen! A cook can only prepare one at the same time!");
332 Pizza pizza = pizzas.get(0);
333 int orderId = pizza.getOrderId();
336 TransactionReference tx = capi.createTransaction(1500,
337 URI.create(Util.SERVER_ADDR));
339 GroupData entity = new GroupData();
340 entity.setState(null);
341 Order order = new Order();
342 order.setId(orderId);
343 entity.setOrder(order);
345 GroupData groupData = takeMatchingEntity(entity,
346 orderTakenContainer, tx, RequestTimeout.DEFAULT,
347 "Another waiter just checks if the order is complete");
348 int groupId = groupData.getId();
349 int numberOfPizzas = groupData.getOrder()
350 .getNumberOfPizzas();
352 Pizza pizzaTemplate = new Pizza();
353 pizzaTemplate.setOrderId(orderId);
355 List<Pizza> pizzasOfOrder = takeMatchingEntities(
356 pizzaTemplate, deliverPizzasContainer, tx,
357 RequestTimeout.DEFAULT,
358 "Cannot take the pizzas from the deliverPizzasContainer");
360 // for an unkown reason even pizzas not matching the orderid
361 // are returned. that's why we have to check again if the
362 // pizza really belongs to the order in question
363 Iterator<Pizza> it = pizzasOfOrder.iterator();
364 while (it.hasNext()) {
365 Pizza nextPizza = it.next();
366 if (nextPizza.getOrderId() != orderId) {
371 if (pizzasOfOrder.size() == numberOfPizzas) {
372 GroupData group = new GroupData();
373 group.setServingWaiter(waiterId);
374 Order completeOrder = new Order();
375 completeOrder.setId(orderId);
376 completeOrder.setGroupId(groupId);
377 group.setOrder(completeOrder);
378 sendItemsToContainer(Arrays.asList(group),
379 orderCompleteContainer, RequestTimeout.DEFAULT,
381 capi.commitTransaction(tx);
383 log.info("Not yet all pizzas prepared! Order with id "
384 + orderId + " has " + numberOfPizzas
385 + " pizzas, but only " + pizzasOfOrder.size()
386 + " pizzas are ready by now!");
387 capi.rollbackTransaction(tx);
390 } catch (MzsCoreException e) {
391 log.error("ERROR in listenForPreparedPizzas!");
398 notificationMgr.createNotification(deliverPizzasContainer,
399 preparedPizzasListener, Operation.WRITE);
400 log.info("Created deliverPizzasContainer notification for a waiter");
401 } catch (Exception e) {
402 handleSpaceErrorAndTerminate(e);
406 private void assignGroupToTable(GroupData lockedGroup,
407 Table lockedFreeTable, TransactionReference tx)
408 throws MzsCoreException {
409 // The new group sits down at the table
410 lockedFreeTable.setGroupId(lockedGroup.getId());
412 // The new group now wants to order
413 lockedGroup.setState(GroupState.SITTING);
414 lockedGroup.setTable(lockedFreeTable);
415 lockedGroup.setTableWaiter(waiterId);
417 sendItemsToContainer(Arrays.asList(lockedFreeTable), tableAssignedContainer,
418 RequestTimeout.ZERO, tx);
419 sendItemsToContainer(Arrays.asList(lockedGroup), takeOrderContainer,
420 RequestTimeout.ZERO, tx);
423 capi.commitTransaction(tx);
424 log.info("Assigned table to group with groupId {}",
425 lockedGroup.getId());
426 } catch (Exception e) {
427 log.info("Assigning a table to group with groupId {} failed",
428 lockedGroup.getId());