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 at.ac.tuwien.sbc.valesriegler.xvsm.spacehelpers.SpaceListener;
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.List;
18 public class WaiterXVSM extends AbstractXVSMConnector {
19 private static final Logger log = LoggerFactory.getLogger(WaiterXVSM.class);
20 private final int waiterId;
22 public WaiterXVSM(int waiterId, int port) {
25 this.waiterId = waiterId;
27 freeTablesContainer = useContainer(Util.FREE_TABLES);
28 assignTableContainer = useContainer(Util.ASSIGN_TABLE);
29 takeOrderContainer = useContainer(Util.TAKE_ORDER);
30 orderTakenContainer = useContainer(Util.ORDER_TAKEN);
31 deliveryOrderTakenContainer = useContainer(Util.DELIVERY_ORDER_TAKEN);
32 preparePizzasContainer = useContainer(Util.PREPARE_PIZZAS);
33 prepareDeliveryPizzasContainer = useContainer(Util.PREPARE_DELIVERY_PIZZAS);
34 orderDeliveredContainer = useContainer(Util.ORDER_COMPLETE);
35 preparedPizzasContainer = useContainer(Util.DELIVER_PIZZAS);
36 paymentRequestContainer = useContainer(Util.PAYMENT_REQUEST);
37 paymentDoneContainer = useContainer(Util.PAYMENT_DONE);
38 tableAssignedContainer = useContainer(Util.TABLE_ASSIGNED);
39 pizzeriaInfoContainer = useContainer(Util.PIZZERIA_INFO);
40 phoneCallsContainer = useContainer(Util.PHONE_CALLS);
41 preparedDeliveryPizzasContainer = useContainer(Util.DELIVER_DELIVERY_PIZZAS);
42 deliverDeliveryOrderContainer = useContainer(Util.DELIVER_DELIVERY_ORDER);
43 pizzeriaGroupContainer = useContainer(Util.PIZZERIA_GROUP);
44 pizzeriaTableContainer = useContainer(Util.PIZZERIA_TABLE);
45 pizzeriaDeliveryContainer = useContainer(Util.PIZZERIA_DELIVERY);
48 public void listenForPhoneOrders() {
49 SpaceListener phoneListener = getDefaultBuilder().setCref(phoneCallsContainer).setLookaround(true).setSpaceAction(new SpaceAction() {
51 public void onEntriesWritten(List<? extends Serializable> entries) throws Exception {
52 final List<DeliveryGroupData> phoneOrders = castEntries(entries);
54 for (DeliveryGroupData phoneOrder : phoneOrders) {
55 final int id = phoneOrder.getId();
56 final DeliveryGroupData template = new DeliveryGroupData(id);
57 final String errorMsg = String.format("There was phone call with id %d. Another waiter already responded!", id);
59 final TransactionReference tx = getDefaultTransaction();
61 // Get the the delete lock so that only one waiter can answer this particular phone call
62 takeMatchingEntity(template, phoneCallsContainer, tx, RequestTimeout.DEFAULT, errorMsg);
64 final DeliveryGroupData group = takeMatchingEntity(template, pizzeriaDeliveryContainer, tx, RequestTimeout.INFINITE, errorMsg);
65 group.setWaiterIdOfOrder(WaiterXVSM.this.waiterId);
66 final Order order = group.getOrder();
67 group.setDeliveryStatus(DeliveryStatus.ORDERED);
69 updatePizzeriaOrderNumber(order, tx);
71 // send the order as a whole to the space
72 final List<DeliveryGroupData> groupsWhoHaveOrdered = Arrays.asList(group);
73 sendItemsToContainer(groupsWhoHaveOrdered,
74 deliveryOrderTakenContainer, RequestTimeout.ZERO, tx);
75 sendItemsToContainer(groupsWhoHaveOrdered,
76 pizzeriaDeliveryContainer, RequestTimeout.ZERO, tx);
77 sendItemsToContainer(order.getOrderedPizzas(),
78 prepareDeliveryPizzasContainer, RequestTimeout.ZERO, tx);
79 capi.commitTransaction(tx);
81 log.info("Waiter has taken a phone delivery call!");
82 } catch (Exception e) {
87 }).createSpaceListenerImpl();
90 public void listenForFreeTable() {
91 SpaceListener listener = getDefaultBuilder().setCref(freeTablesContainer).setSpaceAction(new SpaceAction() {
94 public void onEntriesWritten(List<? extends Serializable> entries) throws Exception {
96 List<Table> tables = castEntries(entries);
98 for (Table table : tables) {
100 TransactionReference tx = getDefaultTransaction();
102 // Acquire a lock for the free table in the
103 // FreeTableContainer
104 int id = table.getId();
106 Table tableTemplate = new Table(id);
108 Table lockedFreeTable = takeMatchingEntity(tableTemplate,
109 freeTablesContainer, tx, RequestTimeout.DEFAULT,
110 String.format("There was no free table found with id %d", id));
111 takeMatchingEntityIfItExists(tableTemplate, pizzeriaTableContainer, tx, RequestTimeout.DEFAULT);
113 GroupData groupTemplate = new GroupData();
114 GroupData lockedGroup = takeMatchingEntity(groupTemplate,
115 assignTableContainer, tx, RequestTimeout.DEFAULT,
116 "There is no group waiting for a table at the moment");
117 takeMatchingEntityIfItExists(lockedGroup, pizzeriaGroupContainer, tx, RequestTimeout.DEFAULT);
119 assignGroupToTable(lockedGroup, lockedFreeTable, tx);
120 } catch (Exception e) {
121 // log.info(e.getMessage());
125 }).createSpaceListenerImpl();
129 public void listenForNewGuests() {
130 SpaceListener listener = getDefaultBuilder().setLookaround(true).setCref(assignTableContainer).setSpaceAction(new SpaceAction() {
133 public void onEntriesWritten(List<? extends Serializable> entries)
135 log.info("New guest groups have arrived");
137 List<GroupData> groups = castEntries(entries);
139 for (GroupData group : groups) {
141 TransactionReference tx = getDefaultTransaction();
143 // Acquire a lock for the group in the
144 // AssignTableContainer
145 String groupNotFound = String.format("Group with id %d was already assigned a table by another waiter!", group.getId());
148 final GroupData templateGroup = new GroupData(group.getId());
149 GroupData lockedGroup = takeMatchingEntity(
151 assignTableContainer, tx,
152 RequestTimeout.DEFAULT, groupNotFound);
153 takeMatchingEntityIfItExists(templateGroup, pizzeriaGroupContainer, tx, RequestTimeout.DEFAULT);
154 // Acquire a lock for one free table in the
156 String noFreeTable = String.format("No free table for group with id %d could be found", group.getId());
157 final Table freeTable = new Table(null);
158 freeTable.setFree(true);
159 Table lockedFreeTable = takeMatchingEntity(freeTable, freeTablesContainer, tx, RequestTimeout.DEFAULT,
161 takeMatchingEntityIfItExists(lockedFreeTable, pizzeriaTableContainer, tx, RequestTimeout.DEFAULT);
163 assignGroupToTable(lockedGroup, lockedFreeTable, tx);
164 } catch (Exception e) {
165 // log.info(e.getMessage());
169 }).createSpaceListenerImpl();
172 public void listenForPaymentRequest() {
173 SpaceListener paymentListener = getDefaultBuilder().setCref(paymentRequestContainer).setSpaceAction(new SpaceAction() {
176 public void onEntriesWritten(List<? extends Serializable> entries)
179 List<GroupData> groups = castEntries(entries);
181 for (GroupData groupData : groups) {
182 TransactionReference tx = getDefaultTransaction();
183 GroupData entity = new GroupData(groupData.getId());
184 entity.setState(GroupState.PAY);
186 // Acquire the lock so that another waiter can't do the same
188 String paymentRequestTakenByOtherWaiter = String.format(
189 "The payment request for group %d was already taken by an other waiter!",
192 takeMatchingEntity(entity, paymentRequestContainer, tx, RequestTimeout.DEFAULT, paymentRequestTakenByOtherWaiter);
193 GroupData group = takeMatchingEntity(entity, pizzeriaGroupContainer, tx, RequestTimeout.DEFAULT, "Cannot get paying group!");
194 group.setPayingWaiter(waiterId);
195 group.setState(GroupState.GONE);
197 final Table tableTemplate = new Table(null);
198 tableTemplate.setGroupId(group.getId());
199 final Table table = takeMatchingEntity(tableTemplate, pizzeriaTableContainer, tx, RequestTimeout.DEFAULT, "Table was not found!");
200 table.setGroupId(-1);
201 final List<Table> tables = Arrays.asList(table);
202 sendItemsToContainer(tables, pizzeriaTableContainer, RequestTimeout.DEFAULT, tx);
203 sendItemsToContainer(tables, freeTablesContainer, RequestTimeout.DEFAULT, tx);
205 final List<GroupData> groupsPayed = Arrays.asList(group);
206 sendItemsToContainer(groupsPayed, paymentDoneContainer, RequestTimeout.DEFAULT, tx);
207 sendItemsToContainer(groupsPayed, pizzeriaGroupContainer, RequestTimeout.DEFAULT, tx);
209 capi.commitTransaction(tx);
210 } catch (Exception e) {
211 log.info(e.getMessage());
215 }).createSpaceListenerImpl();
218 public void listenForOrderRequests() {
219 getDefaultBuilder().setCref(takeOrderContainer).setSpaceAction(new SpaceAction() {
222 public void onEntriesWritten(List<? extends Serializable> entries)
225 List<GroupData> groups = castEntries(entries);
227 for (GroupData groupData : groups) {
229 TransactionReference tx = getDefaultTransaction();
230 GroupData entity = new GroupData(groupData.getId());
231 entity.setState(GroupState.SITTING);
234 // Acquire the lock so that another waiter can't do the same thing!
235 String orderTakenByOtherWaiter = String.format(
236 "The order for group %d was already taken by an other waiter!",
238 takeMatchingEntity(entity, takeOrderContainer, tx, RequestTimeout.DEFAULT, orderTakenByOtherWaiter);
239 GroupData group = takeMatchingEntityIfItExists(entity, pizzeriaGroupContainer, tx, RequestTimeout.INFINITE);
241 group.setOrderWaiter(waiterId);
242 group.setState(GroupState.ORDERED);
243 Order order = group.getOrder();
244 order.setStatus(OrderStatus.ORDERED);
246 /* get the id of the last order of the pizzeria and set the order accordingly and
248 updatePizzeriaOrderNumber(order, tx);
250 // send the order as a whole to the space
251 final List<GroupData> groupsWhoHaveOrdered = Arrays.asList(group);
252 sendItemsToContainer(groupsWhoHaveOrdered,
253 orderTakenContainer, RequestTimeout.ZERO, tx);
254 sendItemsToContainer(groupsWhoHaveOrdered,
255 pizzeriaGroupContainer, RequestTimeout.ZERO, tx);
256 sendItemsToContainer(order.getOrderedPizzas(),
257 preparePizzasContainer, RequestTimeout.ZERO, tx);
258 capi.commitTransaction(tx);
260 log.info("Waiter has taken order from group {}",
262 } catch (Exception e) {
263 // log.info(e.getMessage());
267 }).createSpaceListenerImpl();
270 public void listenForPreparedPizzas() {
272 * A waiter gets informed when a new pizza is complete. He takes the
273 * orderId of the pizza and looks up the corresponding order from which
274 * he gets the number of necessary pizzas of the order. He then tries to
275 * fetch all pizzas with the corresponding orderId and compares the
276 * number of those pizzas with the number of necessary pizzas. If all
277 * pizzas of an order are complete he then delivers them!
279 getDefaultBuilder().setLookaround(true).setCref(preparedPizzasContainer).setSpaceAction(new SpaceAction() {
282 public void onEntriesWritten(List<? extends Serializable> entries)
284 log.info("NEW PIZZAS ARRived");
286 List<Pizza> pizzas = castEntries(entries);
288 for (Pizza pizza : pizzas) {
289 int orderId = pizza.getOrderId();
290 Order order = new Order();
291 order.setId(orderId);
293 TransactionReference tx = getDefaultTransaction();
296 GroupData entity = new GroupData();
297 entity.setState(GroupState.ORDERED);
298 entity.setOrder(order);
300 takeMatchingEntity(entity,
301 orderTakenContainer, tx, RequestTimeout.DEFAULT,
302 "Another waiter just checks if the order is complete");
303 GroupData groupData = takeMatchingEntityIfItExists(entity,
304 pizzeriaGroupContainer, tx, RequestTimeout.INFINITE);
305 int numberOfPizzas = groupData.getOrder().getNumberOfPizzas();
307 Pizza pizzaTemplate = new Pizza();
308 pizzaTemplate.setOrderId(orderId);
310 List<Pizza> pizzasOfOrder = takeMatchingEntities(
311 pizzaTemplate, preparedPizzasContainer, tx,
312 RequestTimeout.DEFAULT,
313 "Cannot take the pizzas from the preparedPizzasContainer");
315 final List<GroupData> groupsWithCompleteOrder = Arrays.asList(groupData);
316 if (pizzasOfOrder.size() == numberOfPizzas) {
317 groupData.setServingWaiter(waiterId);
318 groupData.setState(GroupState.EATING);
319 groupData.getOrder().setStatus(OrderStatus.DELIVERED);
320 sendItemsToContainer(groupsWithCompleteOrder,
321 orderDeliveredContainer, RequestTimeout.DEFAULT,
323 sendItemsToContainer(groupsWithCompleteOrder,
324 pizzeriaGroupContainer, RequestTimeout.DEFAULT,
327 capi.commitTransaction(tx);
329 log.info("Not yet all pizzas prepared! Order with id "
330 + orderId + " has " + numberOfPizzas
331 + " pizzas, but only " + pizzasOfOrder.size()
332 + " pizzas are ready by now!");
333 capi.rollbackTransaction(tx);
335 } catch (NullPointerException e) {
337 } catch (Exception e) {
338 capi.rollbackTransaction(tx);
342 }).createSpaceListenerImpl();
345 public void listenForPreparedDeliveryPizzas() {
347 * A waiter gets informed when a new pizza is complete. He takes the
348 * orderId of the pizza and looks up the corresponding order from which
349 * he gets the number of necessary pizzas of the order. He then tries to
350 * fetch all pizzas with the corresponding orderId and compares the
351 * number of those pizzas with the number of necessary pizzas. If all
352 * pizzas of an order are complete he then delivers them!
354 getDefaultBuilder().setCref(preparedDeliveryPizzasContainer).setLookaround(true).setSpaceAction(new SpaceAction() {
357 public void onEntriesWritten(List<? extends Serializable> entries)
360 List<Pizza> pizzas = castEntries(entries);
362 for (Pizza pizza : pizzas) {
363 int orderId = pizza.getOrderId();
364 Order order = new Order();
365 order.setId(orderId);
367 TransactionReference tx = getDefaultTransaction();
370 DeliveryGroupData entity = new DeliveryGroupData();
371 entity.setDeliveryStatus(null);
372 entity.setOrder(order);
374 takeMatchingEntity(entity,
375 deliveryOrderTakenContainer, tx, RequestTimeout.DEFAULT,
376 "Another driver just checks if the delivery order is complete");
377 DeliveryGroupData groupData = takeMatchingEntity(entity,
378 pizzeriaDeliveryContainer, tx, RequestTimeout.INFINITE,
379 "Waiter cannot take the delivery order from Space!");
380 int groupId = groupData.getId();
381 int numberOfPizzas = groupData.getOrder().getNumberOfPizzas();
383 Pizza pizzaTemplate = new Pizza();
384 pizzaTemplate.setOrderId(orderId);
386 List<Pizza> pizzasOfOrder = takeMatchingEntities(
387 pizzaTemplate, preparedDeliveryPizzasContainer, tx,
388 RequestTimeout.DEFAULT,
389 "Cannot take the pizzas from the preparedDeliveryPizzasContainer");
391 if (pizzasOfOrder.size() == numberOfPizzas) {
392 final List<DeliveryGroupData> groupsWithCompleteOrder = Arrays.asList(groupData);
393 sendItemsToContainer(groupsWithCompleteOrder,
394 deliverDeliveryOrderContainer, RequestTimeout.DEFAULT,
396 sendItemsToContainer(groupsWithCompleteOrder,
397 pizzeriaDeliveryContainer, RequestTimeout.DEFAULT,
400 capi.commitTransaction(tx);
402 log.info("Not yet all pizzas prepared! Order with id "
403 + orderId + " has " + numberOfPizzas
404 + " pizzas, but only " + pizzasOfOrder.size()
405 + " pizzas are ready by now!");
406 capi.rollbackTransaction(tx);
408 } catch (NullPointerException e) {
410 } catch (Exception e) {
411 capi.rollbackTransaction(tx);
415 }).createSpaceListenerImpl();
419 private void assignGroupToTable(GroupData lockedGroup,
420 Table lockedFreeTable, TransactionReference tx)
421 throws MzsCoreException {
422 // The new group sits down at the table
423 lockedFreeTable.setGroupId(lockedGroup.getId());
425 // The new group now wants to order
426 lockedGroup.setState(GroupState.SITTING);
427 lockedGroup.setTable(lockedFreeTable);
428 lockedGroup.setTableWaiter(waiterId);
430 final List<Table> freeTables = Arrays.asList(lockedFreeTable);
431 sendItemsToContainer(freeTables,
432 pizzeriaTableContainer, RequestTimeout.ZERO, tx);
433 sendItemsToContainer(freeTables,
434 tableAssignedContainer, RequestTimeout.ZERO, tx);
435 sendItemsToContainer(Arrays.asList(lockedGroup), takeOrderContainer,
436 RequestTimeout.ZERO, tx);
437 sendItemsToContainer(Arrays.asList(lockedGroup), pizzeriaGroupContainer,
438 RequestTimeout.ZERO, tx);
441 capi.commitTransaction(tx);
442 log.info("Assigned table to group with groupId {}",
443 lockedGroup.getId());
444 } catch (Exception e) {
445 log.info("Assigning a table to group with groupId {} failed",
446 lockedGroup.getId());
447 log.info(e.getMessage());
451 private void updatePizzeriaOrderNumber(Order order, TransactionReference tx) throws MzsCoreException {
452 /* get the id of the last order of the pizzeria and set the order accordingly and
454 final OrderId orderId = takeMatchingEntity(new OrderId(null), pizzeriaInfoContainer, tx, RequestTimeout.INFINITE, "The Order id object could not be taken from the space!");
455 final int id = orderId.getId();
456 final int nextId = id + 1;
458 final List<PizzaOrder> orderedPizzas = order.getOrderedPizzas();
459 for (PizzaOrder orderedPizza : orderedPizzas) {
460 orderedPizza.setOrderId(nextId);
462 sendItemsToContainer(Arrays.asList(new OrderId(nextId)), pizzeriaInfoContainer, RequestTimeout.DEFAULT, tx);