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.core.MzsConstants.RequestTimeout;
8 import org.mozartspaces.core.MzsCoreException;
9 import org.mozartspaces.core.TransactionReference;
10 import org.slf4j.Logger;
11 import org.slf4j.LoggerFactory;
13 import java.io.Serializable;
14 import java.util.Arrays;
15 import java.util.Collections;
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 getDefaultBuilder("listenForPhoneOrders").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 if(inNotification.get()) Collections.shuffle(phoneOrders);
56 for (DeliveryGroupData phoneOrder : phoneOrders) {
57 final int id = phoneOrder.getId();
58 final DeliveryGroupData template = new DeliveryGroupData(id);
59 final String errorMsg = String.format("There was phone call with id %d. Another waiter already responded!", id);
61 final TransactionReference tx = getDefaultTransaction();
63 // Get the delete lock so that only one waiter can answer this particular phone call
64 takeMatchingEntity(template, phoneCallsContainer, tx, RequestTimeout.DEFAULT, errorMsg);
66 final DeliveryGroupData group = takeMatchingEntity(template, pizzeriaDeliveryContainer, tx, RequestTimeout.DEFAULT, errorMsg);
67 group.setWaiterIdOfOrder(WaiterXVSM.this.waiterId);
68 final Order order = group.getOrder();
69 group.setDeliveryStatus(DeliveryStatus.ORDERED);
71 updatePizzeriaOrderNumber(order, tx);
73 // send the order as a whole to the space
74 final List<DeliveryGroupData> groupsWhoHaveOrdered = Arrays.asList(group);
75 sendItemsToContainer(groupsWhoHaveOrdered,
76 deliveryOrderTakenContainer, RequestTimeout.ZERO, tx);
77 sendItemsToContainer(groupsWhoHaveOrdered,
78 pizzeriaDeliveryContainer, RequestTimeout.ZERO, tx);
79 sendItemsToContainer(order.getOrderedPizzas(),
80 prepareDeliveryPizzasContainer, RequestTimeout.ZERO, tx);
81 capi.commitTransaction(tx);
83 log.info("Waiter has taken a phone delivery call!");
84 } catch (Exception e) {
90 }).createSpaceListenerImpl();
93 public void listenForFreeTable() {
94 getDefaultBuilder("listenForFreeTable").setCref(freeTablesContainer).setSpaceAction(new SpaceAction() {
97 public void onEntriesWritten(List<? extends Serializable> entries) throws Exception {
99 List<Table> tables = castEntries(entries);
101 for (Table table : tables) {
103 TransactionReference tx = getDefaultTransaction();
105 // Acquire a lock for the free table in the
106 // FreeTableContainer
107 int id = table.getId();
109 Table tableTemplate = new Table(id);
111 Table lockedFreeTable = takeMatchingEntity(tableTemplate,
112 freeTablesContainer, tx, RequestTimeout.DEFAULT,
113 String.format("There was no free table found with id %d", id));
114 takeMatchingEntityIfItExists(tableTemplate, pizzeriaTableContainer, tx, RequestTimeout.DEFAULT);
116 GroupData groupTemplate = new GroupData();
117 GroupData lockedGroup = takeMatchingEntity(groupTemplate,
118 assignTableContainer, tx, RequestTimeout.DEFAULT,
119 "There is no group waiting for a table at the moment");
120 takeMatchingEntityIfItExists(lockedGroup, pizzeriaGroupContainer, tx, RequestTimeout.DEFAULT);
122 assignGroupToTable(lockedGroup, lockedFreeTable, tx);
123 } catch (Exception e) {
124 // log.info(e.getMessage());
128 }).createSpaceListenerImpl();
132 public void listenForNewGuests() {
133 getDefaultBuilder("listenForNewGuests").setLookaround(true).setCref(assignTableContainer).setSpaceAction(new SpaceAction() {
136 public void onEntriesWritten(List<? extends Serializable> entries)
138 log.info("New guest groups have arrived");
140 List<GroupData> groups = castEntries(entries);
142 for (GroupData group : groups) {
144 TransactionReference tx = getDefaultTransaction();
146 // Acquire a lock for the group in the
147 // AssignTableContainer
148 String groupNotFound = String.format("Group with id %d was already assigned a table by another waiter!", group.getId());
151 final GroupData templateGroup = new GroupData(group.getId());
152 GroupData lockedGroup = takeMatchingEntity(
154 assignTableContainer, tx,
155 RequestTimeout.DEFAULT, groupNotFound);
156 takeMatchingEntityIfItExists(templateGroup, pizzeriaGroupContainer, tx, RequestTimeout.DEFAULT);
157 // Acquire a lock for one free table in the
159 String noFreeTable = String.format("No free table for group with id %d could be found", group.getId());
160 final Table freeTable = new Table(null);
161 freeTable.setFree(true);
162 Table lockedFreeTable = takeMatchingEntity(freeTable, freeTablesContainer, tx, RequestTimeout.DEFAULT,
164 takeMatchingEntityIfItExists(lockedFreeTable, pizzeriaTableContainer, tx, RequestTimeout.DEFAULT);
166 assignGroupToTable(lockedGroup, lockedFreeTable, tx);
167 } catch (Exception e) {
168 // log.info(e.getMessage());
172 }).createSpaceListenerImpl();
175 public void listenForPaymentRequest() {
176 getDefaultBuilder("listenForPayment").setLookaround(true).setCref(paymentRequestContainer).setSpaceAction(new SpaceAction() {
179 public void onEntriesWritten(List<? extends Serializable> entries)
182 List<GroupData> groups = castEntries(entries);
184 for (GroupData groupData : groups) {
185 TransactionReference tx = getDefaultTransaction();
186 GroupData entity = new GroupData(groupData.getId());
187 entity.setState(GroupState.PAY);
189 // Acquire the lock so that another waiter can't do the same
191 String paymentRequestTakenByOtherWaiter = String.format(
192 "The payment request for group %d was already taken by an other waiter!",
195 takeMatchingEntity(entity, paymentRequestContainer, tx, RequestTimeout.DEFAULT, paymentRequestTakenByOtherWaiter);
196 GroupData group = takeMatchingEntity(entity, pizzeriaGroupContainer, tx, RequestTimeout.DEFAULT, "Cannot get paying group!");
197 group.setPayingWaiter(waiterId);
198 group.setState(GroupState.GONE);
200 final Table tableTemplate = new Table(null);
201 tableTemplate.setGroupId(group.getId());
202 final Table table = takeMatchingEntity(tableTemplate, pizzeriaTableContainer, tx, RequestTimeout.DEFAULT, "Table was not found!");
203 table.setGroupId(-1);
204 final List<Table> tables = Arrays.asList(table);
205 sendItemsToContainer(tables, pizzeriaTableContainer, RequestTimeout.DEFAULT, tx);
206 sendItemsToContainer(tables, freeTablesContainer, RequestTimeout.DEFAULT, tx);
208 final List<GroupData> groupsPayed = Arrays.asList(group);
209 sendItemsToContainer(groupsPayed, paymentDoneContainer, RequestTimeout.DEFAULT, tx);
210 sendItemsToContainer(groupsPayed, pizzeriaGroupContainer, RequestTimeout.DEFAULT, tx);
212 capi.commitTransaction(tx);
213 } catch (Exception e) {
214 log.info(e.getMessage());
218 }).createSpaceListenerImpl();
221 public void listenForOrderRequests() {
222 getDefaultBuilder("listenForOrderRequest").setLookaround(true).setCref(takeOrderContainer).setSpaceAction(new SpaceAction() {
225 public void onEntriesWritten(List<? extends Serializable> entries)
228 List<GroupData> groups = castEntries(entries);
230 for (GroupData groupData : groups) {
232 TransactionReference tx = getDefaultTransaction();
233 GroupData entity = new GroupData(groupData.getId());
234 entity.setState(GroupState.SITTING);
237 // Acquire the lock so that another waiter can't do the same thing!
238 String orderTakenByOtherWaiter = String.format(
239 "The order for group %d was already taken by an other waiter!",
241 takeMatchingEntity(entity, takeOrderContainer, tx, RequestTimeout.DEFAULT, orderTakenByOtherWaiter);
242 GroupData group = takeMatchingEntityIfItExists(entity, pizzeriaGroupContainer, tx, RequestTimeout.INFINITE);
244 group.setOrderWaiter(waiterId);
245 group.setState(GroupState.ORDERED);
246 Order order = group.getOrder();
247 order.setStatus(OrderStatus.ORDERED);
249 /* get the id of the last order of the pizzeria and set the order accordingly and
251 updatePizzeriaOrderNumber(order, tx);
253 // send the order as a whole to the space
254 final List<GroupData> groupsWhoHaveOrdered = Arrays.asList(group);
255 sendItemsToContainer(groupsWhoHaveOrdered,
256 orderTakenContainer, RequestTimeout.ZERO, tx);
257 sendItemsToContainer(groupsWhoHaveOrdered,
258 pizzeriaGroupContainer, RequestTimeout.ZERO, tx);
259 sendItemsToContainer(order.getOrderedPizzas(),
260 preparePizzasContainer, RequestTimeout.ZERO, tx);
261 capi.commitTransaction(tx);
263 log.info("Waiter has taken order from group {}",
265 } catch (Exception e) {
266 // log.info(e.getMessage());
270 }).createSpaceListenerImpl();
273 public void listenForPreparedPizzas() {
275 * A waiter gets informed when a new pizza is complete. He takes the
276 * orderId of the pizza and looks up the corresponding order from which
277 * he gets the number of necessary pizzas of the order. He then tries to
278 * fetch all pizzas with the corresponding orderId and compares the
279 * number of those pizzas with the number of necessary pizzas. If all
280 * pizzas of an order are complete he then delivers them!
282 getDefaultBuilder("listenForPreparedPizzas").setLookaround(true).setCref(preparedPizzasContainer).setSpaceAction(new SpaceAction() {
285 public void onEntriesWritten(List<? extends Serializable> entries)
287 log.info("NEW PIZZAS ARRived");
289 List<Pizza> pizzas = castEntries(entries);
291 for (Pizza pizza : pizzas) {
292 int orderId = pizza.getOrderId();
293 Order order = new Order();
294 order.setId(orderId);
296 TransactionReference tx = getDefaultTransaction();
299 GroupData entity = new GroupData();
300 entity.setState(GroupState.ORDERED);
301 entity.setOrder(order);
303 takeMatchingEntity(entity,
304 orderTakenContainer, tx, RequestTimeout.DEFAULT,
305 "Another waiter just checks if the order is complete");
306 GroupData groupData = takeMatchingEntityIfItExists(entity,
307 pizzeriaGroupContainer, tx, RequestTimeout.INFINITE);
308 int numberOfPizzas = groupData.getOrder().getNumberOfPizzas();
310 Pizza pizzaTemplate = new Pizza();
311 pizzaTemplate.setOrderId(orderId);
313 List<Pizza> pizzasOfOrder = takeMatchingEntities(
314 pizzaTemplate, preparedPizzasContainer, tx,
315 RequestTimeout.DEFAULT,
316 "Cannot take the pizzas from the preparedPizzasContainer");
318 final List<GroupData> groupsWithCompleteOrder = Arrays.asList(groupData);
319 if (pizzasOfOrder.size() == numberOfPizzas) {
320 groupData.setServingWaiter(waiterId);
321 groupData.setState(GroupState.EATING);
322 groupData.getOrder().setStatus(OrderStatus.DELIVERED);
323 sendItemsToContainer(groupsWithCompleteOrder,
324 orderDeliveredContainer, RequestTimeout.DEFAULT,
326 sendItemsToContainer(groupsWithCompleteOrder,
327 pizzeriaGroupContainer, RequestTimeout.DEFAULT,
330 capi.commitTransaction(tx);
332 log.info("Not yet all pizzas prepared! Order with id "
333 + orderId + " has " + numberOfPizzas
334 + " pizzas, but only " + pizzasOfOrder.size()
335 + " pizzas are ready by now!");
336 capi.rollbackTransaction(tx);
338 } catch (NullPointerException e) {
340 } catch (Exception e) {
341 capi.rollbackTransaction(tx);
345 }).createSpaceListenerImpl();
348 private void assignGroupToTable(GroupData lockedGroup,
349 Table lockedFreeTable, TransactionReference tx)
350 throws MzsCoreException {
351 // The new group sits down at the table
352 lockedFreeTable.setGroupId(lockedGroup.getId());
354 // The new group now wants to order
355 lockedGroup.setState(GroupState.SITTING);
356 lockedGroup.setTable(lockedFreeTable);
357 lockedGroup.setTableWaiter(waiterId);
359 final List<Table> freeTables = Arrays.asList(lockedFreeTable);
360 sendItemsToContainer(freeTables,
361 pizzeriaTableContainer, RequestTimeout.ZERO, tx);
362 sendItemsToContainer(freeTables,
363 tableAssignedContainer, RequestTimeout.ZERO, tx);
364 sendItemsToContainer(Arrays.asList(lockedGroup), takeOrderContainer,
365 RequestTimeout.ZERO, tx);
366 sendItemsToContainer(Arrays.asList(lockedGroup), pizzeriaGroupContainer,
367 RequestTimeout.ZERO, tx);
370 capi.commitTransaction(tx);
371 log.info("Assigned table to group with groupId {}",
372 lockedGroup.getId());
373 } catch (Exception e) {
374 log.info("Assigning a table to group with groupId {} failed",
375 lockedGroup.getId());
376 log.info(e.getMessage());
380 private void updatePizzeriaOrderNumber(Order order, TransactionReference tx) throws MzsCoreException {
381 /* get the id of the last order of the pizzeria and set the order accordingly and
383 final OrderId orderId = takeMatchingEntity(new OrderId(null), pizzeriaInfoContainer, tx, RequestTimeout.INFINITE, "The Order id object could not be taken from the space!");
384 final int id = orderId.getId();
385 final int nextId = id + 1;
387 final List<PizzaOrder> orderedPizzas = order.getOrderedPizzas();
388 for (PizzaOrder orderedPizza : orderedPizzas) {
389 orderedPizza.setOrderId(nextId);
391 sendItemsToContainer(Arrays.asList(new OrderId(nextId)), pizzeriaInfoContainer, RequestTimeout.DEFAULT, tx);