1 package at.ac.tuwien.sbc.valesriegler.xvsm;
3 import at.ac.tuwien.sbc.valesriegler.common.OrderId;
4 import at.ac.tuwien.sbc.valesriegler.common.Util;
5 import at.ac.tuwien.sbc.valesriegler.types.*;
6 import at.ac.tuwien.sbc.valesriegler.xvsm.spacehelpers.SpaceAction;
7 import org.mozartspaces.capi3.EntryLockedException;
8 import org.mozartspaces.core.MzsConstants.RequestTimeout;
9 import org.mozartspaces.core.MzsCoreException;
10 import org.mozartspaces.core.TransactionReference;
11 import org.slf4j.Logger;
12 import org.slf4j.LoggerFactory;
14 import java.io.Serializable;
15 import java.util.Arrays;
16 import java.util.Collections;
17 import java.util.List;
19 public class WaiterXVSM extends AbstractXVSMConnector {
20 private static final Logger log = LoggerFactory.getLogger(WaiterXVSM.class);
21 private final int waiterId;
23 public WaiterXVSM(int waiterId, int port) {
26 this.waiterId = waiterId;
28 freeTablesContainer = useContainer(Util.FREE_TABLES);
29 assignTableContainer = useContainer(Util.ASSIGN_TABLE);
30 takeOrderContainer = useContainer(Util.TAKE_ORDER);
31 orderTakenContainer = useContainer(Util.ORDER_TAKEN);
32 deliveryOrderTakenContainer = useContainer(Util.DELIVERY_ORDER_TAKEN);
33 preparePizzasContainer = useContainer(Util.PREPARE_PIZZAS);
34 prepareDeliveryPizzasContainer = useContainer(Util.PREPARE_DELIVERY_PIZZAS);
35 orderDeliveredContainer = useContainer(Util.ORDER_COMPLETE);
36 preparedPizzasContainer = useContainer(Util.DELIVER_PIZZAS);
37 paymentRequestContainer = useContainer(Util.PAYMENT_REQUEST);
38 paymentDoneContainer = useContainer(Util.PAYMENT_DONE);
39 tableAssignedContainer = useContainer(Util.TABLE_ASSIGNED);
40 pizzeriaInfoContainer = useContainer(Util.PIZZERIA_INFO);
41 phoneCallsContainer = useContainer(Util.PHONE_CALLS);
42 preparedDeliveryPizzasContainer = useContainer(Util.DELIVER_DELIVERY_PIZZAS);
43 deliverDeliveryOrderContainer = useContainer(Util.DELIVER_DELIVERY_ORDER);
44 pizzeriaGroupContainer = useContainer(Util.PIZZERIA_GROUP);
45 pizzeriaTableContainer = useContainer(Util.PIZZERIA_TABLE);
46 pizzeriaDeliveryContainer = useContainer(Util.PIZZERIA_DELIVERY);
49 public void listenForPhoneOrders() {
50 getDefaultBuilder("listenForPhoneOrders").setCref(phoneCallsContainer).setLookaround(true).setSpaceAction(new SpaceAction() {
52 public void onEntriesWritten(List<? extends Serializable> entries) throws Exception {
53 final List<DeliveryGroupData> phoneOrders = castEntries(entries);
55 if(inNotification.get()) Collections.shuffle(phoneOrders);
57 for (DeliveryGroupData phoneOrder : phoneOrders) {
58 final int id = phoneOrder.getId();
59 final DeliveryGroupData template = new DeliveryGroupData(id);
60 final String errorMsg = String.format("There was phone call with id %d. Another waiter already responded!", id);
62 final TransactionReference tx = getDefaultTransaction();
64 // Get the delete lock so that only one waiter can answer this particular phone call
65 takeMatchingEntity(template, phoneCallsContainer, tx, RequestTimeout.ZERO, errorMsg);
67 final DeliveryGroupData group = takeMatchingEntity(template, pizzeriaDeliveryContainer, tx, RequestTimeout.DEFAULT, errorMsg);
68 group.setWaiterIdOfOrder(WaiterXVSM.this.waiterId);
69 final Order order = group.getOrder();
70 group.setDeliveryStatus(DeliveryStatus.ORDERED);
72 updatePizzeriaOrderNumber(order, tx);
74 // send the order as a whole to the space
75 final List<DeliveryGroupData> groupsWhoHaveOrdered = Arrays.asList(group);
76 sendItemsToContainer(groupsWhoHaveOrdered,
77 deliveryOrderTakenContainer, RequestTimeout.ZERO, tx);
78 sendItemsToContainer(groupsWhoHaveOrdered,
79 pizzeriaDeliveryContainer, RequestTimeout.ZERO, tx);
80 sendItemsToContainer(order.getOrderedPizzas(),
81 prepareDeliveryPizzasContainer, RequestTimeout.ZERO, tx);
82 capi.commitTransaction(tx);
84 log.info("Waiter has taken a phone delivery call!");
85 } catch (EntityNotFoundByTemplate e) {
86 log.debug("entitynotfound: {}", e.getMessage());
87 } catch(EntryLockedException e) {
88 capi.rollbackTransaction(tx);
89 }catch(NullPointerException e) {
90 } catch (Exception e) {
96 }).createSpaceListenerImpl();
99 public void listenForFreeTable() {
100 getDefaultBuilder("listenForFreeTable").setCref(freeTablesContainer).setSpaceAction(new SpaceAction() {
103 public void onEntriesWritten(List<? extends Serializable> entries) throws Exception {
105 List<Table> tables = castEntries(entries);
107 for (Table table : tables) {
109 TransactionReference tx = getDefaultTransaction();
111 // Acquire a lock for the free table in the
112 // FreeTableContainer
113 int id = table.getId();
115 Table tableTemplate = new Table(id);
117 Table lockedFreeTable = takeMatchingEntity(tableTemplate,
118 freeTablesContainer, tx, RequestTimeout.ZERO,
119 String.format("There was no free table found with id %d", id));
120 takeMatchingEntityIfItExists(tableTemplate, pizzeriaTableContainer, tx, RequestTimeout.DEFAULT);
122 GroupData groupTemplate = new GroupData();
123 GroupData lockedGroup = takeMatchingEntity(groupTemplate,
124 assignTableContainer, tx, RequestTimeout.DEFAULT,
125 "There is no group waiting for a table at the moment");
126 takeMatchingEntityIfItExists(lockedGroup, pizzeriaGroupContainer, tx, RequestTimeout.DEFAULT);
128 assignGroupToTable(lockedGroup, lockedFreeTable, tx);
129 } catch(EntryLockedException e) {
130 capi.rollbackTransaction(tx);
131 } catch (Exception e) {
132 // log.info(e.getMessage());
136 }).createSpaceListenerImpl();
140 public void listenForNewGuests() {
141 getDefaultBuilder("listenForNewGuests").setLookaround(true).setCref(assignTableContainer).setSpaceAction(new SpaceAction() {
144 public void onEntriesWritten(List<? extends Serializable> entries)
146 log.info("New guest groups have arrived");
148 List<GroupData> groups = castEntries(entries);
150 for (GroupData group : groups) {
152 TransactionReference tx = getDefaultTransaction();
154 // Acquire a lock for the group in the
155 // AssignTableContainer
156 String groupNotFound = String.format("Group with id %d was already assigned a table by another waiter!", group.getId());
159 final GroupData templateGroup = new GroupData(group.getId());
160 GroupData lockedGroup = takeMatchingEntity(
162 assignTableContainer, tx,
163 RequestTimeout.ZERO, groupNotFound);
164 takeMatchingEntityIfItExists(templateGroup, pizzeriaGroupContainer, tx, RequestTimeout.DEFAULT);
165 // Acquire a lock for one free table in the
167 String noFreeTable = String.format("No free table for group with id %d could be found", group.getId());
168 final Table freeTable = new Table(null);
169 freeTable.setFree(true);
170 Table lockedFreeTable = takeMatchingEntity(freeTable, freeTablesContainer, tx, RequestTimeout.DEFAULT,
172 takeMatchingEntityIfItExists(lockedFreeTable, pizzeriaTableContainer, tx, RequestTimeout.DEFAULT);
174 assignGroupToTable(lockedGroup, lockedFreeTable, tx);
175 } catch(EntryLockedException e) {
176 capi.rollbackTransaction(tx);
177 } catch (Exception e) {
178 // log.info(e.getMessage());
182 }).createSpaceListenerImpl();
185 public void listenForPaymentRequest() {
186 getDefaultBuilder("listenForPayment").setLookaround(true).setCref(paymentRequestContainer).setSpaceAction(new SpaceAction() {
189 public void onEntriesWritten(List<? extends Serializable> entries)
192 List<GroupData> groups = castEntries(entries);
194 for (GroupData groupData : groups) {
195 TransactionReference tx = getDefaultTransaction();
196 GroupData entity = new GroupData(groupData.getId());
197 entity.setState(GroupState.PAY);
199 // Acquire the lock so that another waiter can't do the same
201 String paymentRequestTakenByOtherWaiter = String.format(
202 "The payment request for group %d was already taken by an other waiter!",
205 takeMatchingEntity(entity, paymentRequestContainer, tx, RequestTimeout.ZERO, paymentRequestTakenByOtherWaiter);
206 GroupData group = takeMatchingEntity(entity, pizzeriaGroupContainer, tx, RequestTimeout.DEFAULT, "Cannot get paying group!");
207 group.setPayingWaiter(waiterId);
208 group.setState(GroupState.GONE);
210 final Table tableTemplate = new Table(null);
211 tableTemplate.setGroupId(group.getId());
212 final Table table = takeMatchingEntity(tableTemplate, pizzeriaTableContainer, tx, RequestTimeout.DEFAULT, "Table was not found!");
213 table.setGroupId(-1);
214 final List<Table> tables = Arrays.asList(table);
215 sendItemsToContainer(tables, pizzeriaTableContainer, RequestTimeout.DEFAULT, tx);
216 sendItemsToContainer(tables, freeTablesContainer, RequestTimeout.DEFAULT, tx);
218 final List<GroupData> groupsPayed = Arrays.asList(group);
219 sendItemsToContainer(groupsPayed, paymentDoneContainer, RequestTimeout.DEFAULT, tx);
220 sendItemsToContainer(groupsPayed, pizzeriaGroupContainer, RequestTimeout.DEFAULT, tx);
222 capi.commitTransaction(tx);
223 } catch(EntryLockedException e) {
224 capi.rollbackTransaction(tx);
225 } catch (Exception e) {
226 log.info(e.getMessage());
230 }).createSpaceListenerImpl();
233 public void listenForOrderRequests() {
234 getDefaultBuilder("listenForOrderRequest").setLookaround(true).setCref(takeOrderContainer).setSpaceAction(new SpaceAction() {
237 public void onEntriesWritten(List<? extends Serializable> entries)
240 List<GroupData> groups = castEntries(entries);
242 for (GroupData groupData : groups) {
244 TransactionReference tx = getDefaultTransaction();
245 GroupData entity = new GroupData(groupData.getId());
246 entity.setState(GroupState.SITTING);
249 // Acquire the lock so that another waiter can't do the same thing!
250 String orderTakenByOtherWaiter = String.format(
251 "The order for group %d was already taken by an other waiter!",
253 takeMatchingEntity(entity, takeOrderContainer, tx, RequestTimeout.ZERO, orderTakenByOtherWaiter);
254 GroupData group = takeMatchingEntityIfItExists(entity, pizzeriaGroupContainer, tx, RequestTimeout.INFINITE);
256 group.setOrderWaiter(waiterId);
257 group.setState(GroupState.ORDERED);
258 Order order = group.getOrder();
259 order.setStatus(OrderStatus.ORDERED);
261 /* get the id of the last order of the pizzeria and set the order accordingly and
263 updatePizzeriaOrderNumber(order, tx);
265 // send the order as a whole to the space
266 final List<GroupData> groupsWhoHaveOrdered = Arrays.asList(group);
267 sendItemsToContainer(groupsWhoHaveOrdered,
268 orderTakenContainer, RequestTimeout.ZERO, tx);
269 sendItemsToContainer(groupsWhoHaveOrdered,
270 pizzeriaGroupContainer, RequestTimeout.ZERO, tx);
271 sendItemsToContainer(order.getOrderedPizzas(),
272 preparePizzasContainer, RequestTimeout.ZERO, tx);
273 capi.commitTransaction(tx);
275 log.info("Waiter has taken order from group {}",
277 } catch(EntryLockedException e) {
278 capi.rollbackTransaction(tx);
279 } catch (Exception e) {
280 // log.info(e.getMessage());
284 }).createSpaceListenerImpl();
287 public void listenForPreparedPizzas() {
289 * A waiter gets informed when a new pizza is complete. He takes the
290 * orderId of the pizza and looks up the corresponding order from which
291 * he gets the number of necessary pizzas of the order. He then tries to
292 * fetch all pizzas with the corresponding orderId and compares the
293 * number of those pizzas with the number of necessary pizzas. If all
294 * pizzas of an order are complete he then delivers them!
296 getDefaultBuilder("listenForPreparedPizzas").setLookaround(true).setCref(preparedPizzasContainer).setSpaceAction(new SpaceAction() {
299 public void onEntriesWritten(List<? extends Serializable> entries)
302 List<Pizza> pizzas = castEntries(entries);
304 for (Pizza pizza : pizzas) {
305 int orderId = pizza.getOrderId();
306 Order order = new Order();
307 order.setId(orderId);
309 TransactionReference tx = getDefaultTransaction();
312 GroupData entity = new GroupData();
313 entity.setState(GroupState.ORDERED);
314 entity.setOrder(order);
316 takeMatchingEntity(entity,
317 orderTakenContainer, tx, RequestTimeout.DEFAULT,
318 "Another waiter just checks if the order is complete");
319 GroupData groupData = takeMatchingEntityIfItExists(entity,
320 pizzeriaGroupContainer, tx, RequestTimeout.INFINITE);
321 int numberOfPizzas = groupData.getOrder().getNumberOfPizzas();
323 Pizza pizzaTemplate = new Pizza();
324 pizzaTemplate.setOrderId(orderId);
326 List<Pizza> pizzasOfOrder = takeMatchingEntities(
327 pizzaTemplate, preparedPizzasContainer, tx,
328 RequestTimeout.DEFAULT,
329 "Cannot take the pizzas from the preparedPizzasContainer");
331 final List<GroupData> groupsWithCompleteOrder = Arrays.asList(groupData);
332 if (pizzasOfOrder.size() == numberOfPizzas) {
333 groupData.setServingWaiter(waiterId);
334 groupData.setState(GroupState.EATING);
335 groupData.getOrder().setStatus(OrderStatus.DELIVERED);
336 sendItemsToContainer(groupsWithCompleteOrder,
337 orderDeliveredContainer, RequestTimeout.DEFAULT,
339 sendItemsToContainer(groupsWithCompleteOrder,
340 pizzeriaGroupContainer, RequestTimeout.DEFAULT,
343 capi.commitTransaction(tx);
345 log.debug("Not yet all pizzas prepared! Order with id "
346 + orderId + " has " + numberOfPizzas
347 + " pizzas, but only " + pizzasOfOrder.size()
348 + " pizzas are ready by now!");
349 capi.rollbackTransaction(tx);
351 } catch (NullPointerException e) {
353 } catch (Exception e) {
354 capi.rollbackTransaction(tx);
358 }).createSpaceListenerImpl();
361 private void assignGroupToTable(GroupData lockedGroup,
362 Table lockedFreeTable, TransactionReference tx)
363 throws MzsCoreException {
364 // The new group sits down at the table
365 lockedFreeTable.setGroupId(lockedGroup.getId());
367 // The new group now wants to order
368 lockedGroup.setState(GroupState.SITTING);
369 lockedGroup.setTable(lockedFreeTable);
370 lockedGroup.setTableWaiter(waiterId);
372 final List<Table> freeTables = Arrays.asList(lockedFreeTable);
373 sendItemsToContainer(freeTables,
374 pizzeriaTableContainer, RequestTimeout.ZERO, tx);
375 sendItemsToContainer(freeTables,
376 tableAssignedContainer, RequestTimeout.ZERO, tx);
377 sendItemsToContainer(Arrays.asList(lockedGroup), takeOrderContainer,
378 RequestTimeout.ZERO, tx);
379 sendItemsToContainer(Arrays.asList(lockedGroup), pizzeriaGroupContainer,
380 RequestTimeout.ZERO, tx);
383 capi.commitTransaction(tx);
384 log.info("Assigned table to group with groupId {}",
385 lockedGroup.getId());
386 } catch (Exception e) {
387 log.info("Assigning a table to group with groupId {} failed",
388 lockedGroup.getId());
389 log.info(e.getMessage());
393 private void updatePizzeriaOrderNumber(Order order, TransactionReference tx) throws MzsCoreException {
394 /* get the id of the last order of the pizzeria and set the order accordingly and
396 final OrderId orderId = takeMatchingEntity(new OrderId(null), pizzeriaInfoContainer, tx, RequestTimeout.INFINITE, "The Order id object could not be taken from the space!");
397 final int id = orderId.getId();
398 final int nextId = id + 1;
400 final List<PizzaOrder> orderedPizzas = order.getOrderedPizzas();
401 for (PizzaOrder orderedPizza : orderedPizzas) {
402 orderedPizza.setOrderId(nextId);
404 sendItemsToContainer(Arrays.asList(new OrderId(nextId)), pizzeriaInfoContainer, RequestTimeout.DEFAULT, tx);