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 tablesContainer = useContainer(Util.TABLES_CONTAINER) ;
46 takeOrderContainer = useContainer(Util.TAKE_ORDER) ;
47 ordersContainer = useContainer(Util.ORDER) ;
48 preparePizzasContainer = useContainer(Util.PREPARE_PIZZAS) ;
49 groupsContainer = useContainer(Util.GROUPS_CONTAINER) ;
50 orderCompleteContainer = useContainer(Util.ORDER_COMPLETE) ;
51 deliverPizzasContainer = useContainer(Util.DELIVER_PIZZAS);
52 paymentContainer = useContainer(Util.PAYMENT) ;
53 hasPaidContainer = useContainer(Util.HAS_PAID) ;
56 public void listenForFreeTable() {
58 NotificationListener freeTableListener = new NotificationListener() {
60 public void entryOperationFinished(final Notification notification,
61 final Operation operation,
62 final List<? extends Serializable> entries) {
64 log.info("{} tables have become free", entries.size());
66 List<Table> tables = castEntries(entries);
67 Collections.shuffle(tables);
69 for (Table table : tables) {
71 TransactionReference tx = capi.createTransaction(3000,
72 URI.create(Util.SERVER_ADDR));
75 // Acquire a lock for the free table in the
77 int id = table.getId();
78 log.info("Try to find the table with id {}", id);
80 Table tableTemplate = new Table(id);
81 Table lockedFreeTable = takeMatchingEntity(
87 "There was no free table found with id %d",
90 log.info("Table with id {} was found", id);
92 GroupData groupTemplate = new GroupData();
93 GroupData lockedGroup = takeMatchingEntity(
94 groupTemplate, assignTableContainer, tx,
95 RequestTimeout.DEFAULT,
96 "There is no group waiting for a table at the moment");
98 assignGroupToTable(lockedGroup, lockedFreeTable, tx);
100 } catch (IllegalArgumentException e) {
101 log.info("IllegalArgumentException");
103 } catch (EntityNotFoundByTemplate e) {
104 log.info(e.getMessage());
105 } catch (Exception e) {
106 log.error("AN INNER EXCEPTION");
109 } catch (TransactionException e) {
110 log.info("An unimportant TransactionException has occurred");
111 } catch (Exception e) {
112 log.error("OUTER EXCEPTION");
119 notificationMgr.createNotification(freeTablesContainer,
120 freeTableListener, Operation.WRITE);
121 log.info("Created freeTablesContainer notification for a waiter");
122 } catch (Exception e) {
123 handleSpaceErrorAndTerminate(e);
128 public void listenForNewGuests() {
129 NotificationListener newGroupsListener = new NotificationListener() {
131 public void entryOperationFinished(final Notification notification,
132 final Operation operation,
133 final List<? extends Serializable> entries) {
135 log.info("New guest groups have arrived");
137 List<GroupData> groups = castEntries(entries);
138 Collections.shuffle(groups);
140 for (GroupData group : groups) {
142 TransactionReference tx = capi.createTransaction(1500,
143 URI.create(Util.SERVER_ADDR));
146 // Acquire a lock for the group in the
147 // AssignTableContainer
148 String groupNotFound = String
149 .format("Group with id %d was already assigned a table by another waiter!",
152 GroupData lockedGroup = takeMatchingEntity(
153 new GroupData(group.getId()),
154 assignTableContainer, tx, 1000,
156 // Acquire a lock for one free table in the
158 Table lockedFreeTable = takeMatchingEntity(
162 RequestTimeout.DEFAULT,
164 "No free table for group with id %d could be found",
167 assignGroupToTable(lockedGroup, lockedFreeTable, tx);
169 } catch (IllegalArgumentException e) {
170 log.info("IllegalArgumentException");
172 } catch (EntityNotFoundByTemplate e) {
173 log.info(e.getMessage());
174 } catch (Exception e) {
175 log.error("AN INNER EXCEPTION");
178 } catch (TransactionException e) {
179 log.info("An unimportant TransactionException has occurred");
180 } catch (Exception e) {
181 log.error("OUTER EXCEPTION");
188 notificationMgr.createNotification(assignTableContainer,
189 newGroupsListener, Operation.WRITE);
190 log.info("Created assingTableContainer notification for a waiter");
191 } catch (Exception e) {
192 handleSpaceErrorAndTerminate(e);
196 public void listenForPaymentRequest() {
197 log.info("INITIALIZE PAYMENT NOTIFICATION");
198 NotificationListener paymentListener = new NotificationListener() {
200 public void entryOperationFinished(final Notification notification,
201 final Operation operation,
202 final List<? extends Serializable> entries) {
203 log.info("A PAYMENT REQUEST HAS ARRIVED!");
205 List<GroupData> groups = castEntries(entries);
207 GroupData groupData = groups.get(0);
210 TransactionReference tx = capi.createTransaction(1500,
211 URI.create(Util.SERVER_ADDR));
212 GroupData entity = new GroupData(groupData.getId());
214 // Acquire the lock so that another waiter can't do the same
220 RequestTimeout.DEFAULT,
222 "The payment request for group %d was already taken by an other waiter!",
226 groupData.setPayingWaiter(waiterId);
228 sendItemsToContainer(Arrays.asList(groupData),
229 hasPaidContainer, RequestTimeout.ZERO, tx);
231 capi.commitTransaction(tx);
233 } catch (MzsCoreException e) {
234 log.info("ERROR in listenForPaymentRequest");
241 notificationMgr.createNotification(paymentContainer,
242 paymentListener, Operation.WRITE);
243 log.info("Created payment notification for a waiter");
244 } catch (Exception e) {
245 handleSpaceErrorAndTerminate(e);
249 public void listenForOrders() {
250 NotificationListener ordersListener = new NotificationListener() {
252 public void entryOperationFinished(final Notification notification,
253 final Operation operation,
254 final List<? extends Serializable> entries) {
255 log.info("A new order has arrived!");
257 List<GroupData> groups = castEntries(entries);
258 if (groups.size() != 1)
259 throw new RuntimeException(
260 "Multiple orders in one notification?! That should not happen!");
262 GroupData groupData = groups.get(0);
265 TransactionReference tx = capi.createTransaction(1500,
266 URI.create(Util.SERVER_ADDR));
267 GroupData entity = new GroupData(groupData.getId());
268 entity.setState(GroupState.SITTING);
270 // Acquire the lock so that another waiter can't do the same
276 RequestTimeout.DEFAULT,
278 "The order for group %d was already taken by an other waiter!",
282 "Will now write taken order from group {} to space",
284 groupData.setOrderWaiter(waiterId);
285 groupData.setState(GroupState.ORDERED);
286 Order order = groupData.getOrder();
287 order.setStatus(OrderStatus.ORDERED);
289 sendItemsToContainer(Arrays.asList(groupData),
290 ordersContainer, RequestTimeout.ZERO, tx);
291 sendItemsToContainer(Arrays.asList(groupData),
292 groupsContainer, RequestTimeout.ZERO, tx);
293 sendItemsToContainer(order.getOrderedPizzas(),
294 preparePizzasContainer, RequestTimeout.ZERO, tx);
295 capi.commitTransaction(tx);
297 log.info("Waiter has taken order from group {}",
299 } catch (MzsCoreException e) {
300 log.info("ERROR in listenForOrders");
307 notificationMgr.createNotification(takeOrderContainer,
308 ordersListener, Operation.WRITE);
309 log.info("Created takeOrderContainer notification for a waiter");
310 } catch (Exception e) {
311 handleSpaceErrorAndTerminate(e);
315 public void listenForPreparedPizzas() {
317 * A waiter gets informed when a new pizza is complete. He takes the
318 * orderId of the pizza and looks up the corresponding order from which
319 * he gets the number of necessary pizzas of the order. He then tries to
320 * fetch all pizzas with the corresponding orderId and compares the
321 * number of those pizzas with the number of necessary pizzas. If all
322 * pizzas of an order are complete he then delivers them!
324 NotificationListener preparedPizzasListener = new NotificationListener() {
326 public void entryOperationFinished(final Notification notification,
327 final Operation operation,
328 final List<? extends Serializable> entries) {
330 List<Pizza> pizzas = castEntries(entries);
331 if (pizzas.size() != 1)
332 throw new RuntimeException(
333 "Multiple pizzas in one notification?! That should not happen! A cook can only prepare one at the same time!");
335 Pizza pizza = pizzas.get(0);
336 int orderId = pizza.getOrderId();
339 TransactionReference tx = capi.createTransaction(1500,
340 URI.create(Util.SERVER_ADDR));
342 GroupData entity = new GroupData();
343 entity.setState(null);
344 Order order = new Order();
345 order.setId(orderId);
346 entity.setOrder(order);
348 GroupData groupData = takeMatchingEntity(entity,
349 ordersContainer, tx, RequestTimeout.DEFAULT,
350 "Another waiter just checks if the order is complete");
351 int groupId = groupData.getId();
352 int numberOfPizzas = groupData.getOrder()
353 .getNumberOfPizzas();
355 Pizza pizzaTemplate = new Pizza();
356 pizzaTemplate.setOrderId(orderId);
358 List<Pizza> pizzasOfOrder = takeMatchingEntities(
359 pizzaTemplate, deliverPizzasContainer, tx,
360 RequestTimeout.DEFAULT,
361 "Cannot take the pizzas from the deliverPizzasContainer");
363 // for an unkown reason even pizzas not matching the orderid
364 // are returned. that's why we have to check again if the
365 // pizza really belongs to the order in question
366 Iterator<Pizza> it = pizzasOfOrder.iterator();
367 while (it.hasNext()) {
368 Pizza nextPizza = it.next();
369 if (nextPizza.getOrderId() != orderId) {
374 if (pizzasOfOrder.size() == numberOfPizzas) {
375 GroupData group = new GroupData();
376 group.setServingWaiter(waiterId);
377 Order completeOrder = new Order();
378 completeOrder.setId(orderId);
379 completeOrder.setGroupId(groupId);
380 group.setOrder(completeOrder);
381 sendItemsToContainer(Arrays.asList(group),
382 orderCompleteContainer, RequestTimeout.DEFAULT,
384 capi.commitTransaction(tx);
386 log.info("Not yet all pizzas prepared! Order with id "
387 + orderId + " has " + numberOfPizzas
388 + " pizzas, but only " + pizzasOfOrder.size()
389 + " pizzas are ready by now!");
390 capi.rollbackTransaction(tx);
393 } catch (MzsCoreException e) {
394 log.error("ERROR in listenForPreparedPizzas!");
401 notificationMgr.createNotification(deliverPizzasContainer,
402 preparedPizzasListener, Operation.WRITE);
403 log.info("Created deliverPizzasContainer notification for a waiter");
404 } catch (Exception e) {
405 handleSpaceErrorAndTerminate(e);
409 private void assignGroupToTable(GroupData lockedGroup,
410 Table lockedFreeTable, TransactionReference tx)
411 throws MzsCoreException {
412 // The new group sits down at the table
413 lockedFreeTable.setGroupId(lockedGroup.getId());
415 // The new group now wants to order
416 lockedGroup.setState(GroupState.SITTING);
417 lockedGroup.setTable(lockedFreeTable);
418 lockedGroup.setTableWaiter(waiterId);
420 sendItemsToContainer(Arrays.asList(lockedFreeTable), tablesContainer,
421 RequestTimeout.ZERO, tx);
422 sendItemsToContainer(Arrays.asList(lockedGroup), takeOrderContainer,
423 RequestTimeout.ZERO, tx);
424 sendItemsToContainer(Arrays.asList(lockedGroup), groupsContainer,
425 RequestTimeout.ZERO, tx);
428 capi.commitTransaction(tx);
429 log.info("Assigned table to group with groupId {}",
430 lockedGroup.getId());
431 } catch (Exception e) {
432 log.info("Assigning a table to group with groupId {} failed",
433 lockedGroup.getId());