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.DEFAULT, 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 SpaceListener ordersListener = 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.DEFAULT);
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 SpaceListener preparedPizzasListener = 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.DEFAULT);
305 int groupId = groupData.getId();
306 int numberOfPizzas = groupData.getOrder().getNumberOfPizzas();
308 Pizza pizzaTemplate = new Pizza();
309 pizzaTemplate.setOrderId(orderId);
311 List<Pizza> pizzasOfOrder = takeMatchingEntities(
312 pizzaTemplate, preparedPizzasContainer, tx,
313 RequestTimeout.DEFAULT,
314 "Cannot take the pizzas from the preparedPizzasContainer");
316 final List<GroupData> groupsWithCompleteOrder = Arrays.asList(groupData);
317 if (pizzasOfOrder.size() == numberOfPizzas) {
318 groupData.setServingWaiter(waiterId);
319 groupData.setState(GroupState.EATING);
320 groupData.getOrder().setStatus(OrderStatus.DELIVERED);
321 sendItemsToContainer(groupsWithCompleteOrder,
322 orderDeliveredContainer, RequestTimeout.DEFAULT,
324 sendItemsToContainer(groupsWithCompleteOrder,
325 pizzeriaGroupContainer, RequestTimeout.DEFAULT,
328 capi.commitTransaction(tx);
330 log.info("Not yet all pizzas prepared! Order with id "
331 + orderId + " has " + numberOfPizzas
332 + " pizzas, but only " + pizzasOfOrder.size()
333 + " pizzas are ready by now!");
334 capi.rollbackTransaction(tx);
336 } catch (NullPointerException e) {
338 } catch (Exception e) {
339 capi.rollbackTransaction(tx);
343 }).createSpaceListenerImpl();
346 public void listenForPreparedDeliveryPizzas() {
348 * A waiter gets informed when a new pizza is complete. He takes the
349 * orderId of the pizza and looks up the corresponding order from which
350 * he gets the number of necessary pizzas of the order. He then tries to
351 * fetch all pizzas with the corresponding orderId and compares the
352 * number of those pizzas with the number of necessary pizzas. If all
353 * pizzas of an order are complete he then delivers them!
355 SpaceListener preparedPizzasListener = getDefaultBuilder().setCref(preparedDeliveryPizzasContainer).setLookaround(true).setSpaceAction(new SpaceAction() {
358 public void onEntriesWritten(List<? extends Serializable> entries)
361 List<Pizza> pizzas = castEntries(entries);
363 for (Pizza pizza : pizzas) {
364 int orderId = pizza.getOrderId();
365 Order order = new Order();
366 order.setId(orderId);
368 TransactionReference tx = getDefaultTransaction();
371 DeliveryGroupData entity = new DeliveryGroupData();
372 entity.setDeliveryStatus(null);
373 entity.setOrder(order);
375 takeMatchingEntity(entity,
376 deliveryOrderTakenContainer, tx, RequestTimeout.DEFAULT,
377 "Another driver just checks if the delivery order is complete");
378 DeliveryGroupData groupData = takeMatchingEntity(entity,
379 pizzeriaDeliveryContainer, tx, RequestTimeout.DEFAULT,
380 "Waiter cannot take the delivery order from Space!");
381 int groupId = groupData.getId();
382 int numberOfPizzas = groupData.getOrder().getNumberOfPizzas();
384 Pizza pizzaTemplate = new Pizza();
385 pizzaTemplate.setOrderId(orderId);
387 List<Pizza> pizzasOfOrder = takeMatchingEntities(
388 pizzaTemplate, preparedDeliveryPizzasContainer, tx,
389 RequestTimeout.DEFAULT,
390 "Cannot take the pizzas from the preparedDeliveryPizzasContainer");
392 if (pizzasOfOrder.size() == numberOfPizzas) {
393 final List<DeliveryGroupData> groupsWithCompleteOrder = Arrays.asList(groupData);
394 sendItemsToContainer(groupsWithCompleteOrder,
395 deliverDeliveryOrderContainer, RequestTimeout.DEFAULT,
397 sendItemsToContainer(groupsWithCompleteOrder,
398 pizzeriaDeliveryContainer, RequestTimeout.DEFAULT,
401 capi.commitTransaction(tx);
403 log.info("Not yet all pizzas prepared! Order with id "
404 + orderId + " has " + numberOfPizzas
405 + " pizzas, but only " + pizzasOfOrder.size()
406 + " pizzas are ready by now!");
407 capi.rollbackTransaction(tx);
409 } catch (NullPointerException e) {
411 } catch (Exception e) {
412 capi.rollbackTransaction(tx);
416 }).createSpaceListenerImpl();
420 private void assignGroupToTable(GroupData lockedGroup,
421 Table lockedFreeTable, TransactionReference tx)
422 throws MzsCoreException {
423 // The new group sits down at the table
424 lockedFreeTable.setGroupId(lockedGroup.getId());
426 // The new group now wants to order
427 lockedGroup.setState(GroupState.SITTING);
428 lockedGroup.setTable(lockedFreeTable);
429 lockedGroup.setTableWaiter(waiterId);
431 final List<Table> freeTables = Arrays.asList(lockedFreeTable);
432 sendItemsToContainer(freeTables,
433 pizzeriaTableContainer, RequestTimeout.ZERO, tx);
434 sendItemsToContainer(freeTables,
435 tableAssignedContainer, RequestTimeout.ZERO, tx);
436 sendItemsToContainer(Arrays.asList(lockedGroup), takeOrderContainer,
437 RequestTimeout.ZERO, tx);
438 sendItemsToContainer(Arrays.asList(lockedGroup), pizzeriaGroupContainer,
439 RequestTimeout.ZERO, tx);
442 capi.commitTransaction(tx);
443 log.info("Assigned table to group with groupId {}",
444 lockedGroup.getId());
445 } catch (Exception e) {
446 log.info("Assigning a table to group with groupId {} failed",
447 lockedGroup.getId());
448 log.info(e.getMessage());
452 private void updatePizzeriaOrderNumber(Order order, TransactionReference tx) throws MzsCoreException {
453 /* get the id of the last order of the pizzeria and set the order accordingly and
455 final OrderId orderId = takeMatchingEntity(new OrderId(null), pizzeriaInfoContainer, tx, RequestTimeout.INFINITE, "The Order id object could not be taken from the space!");
456 final int id = orderId.getId();
457 final int nextId = id + 1;
459 final List<PizzaOrder> orderedPizzas = order.getOrderedPizzas();
460 for (PizzaOrder orderedPizza : orderedPizzas) {
461 orderedPizza.setOrderId(nextId);
463 sendItemsToContainer(Arrays.asList(new OrderId(nextId)), pizzeriaInfoContainer, RequestTimeout.DEFAULT, tx);