]> git.somenet.org - pub/jan/sbc.git/blob - src/main/java/at/ac/tuwien/sbc/valesriegler/xvsm/WaiterXVSM.java
[XVSM] Some fixes for making sure that Cook only prepares normal pizzas when there...
[pub/jan/sbc.git] / src / main / java / at / ac / tuwien / sbc / valesriegler / xvsm / WaiterXVSM.java
1 package at.ac.tuwien.sbc.valesriegler.xvsm;
2
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;
13
14 import java.io.Serializable;
15 import java.util.Arrays;
16 import java.util.Collections;
17 import java.util.List;
18
19 public class WaiterXVSM extends AbstractXVSMConnector {
20     private static final Logger log = LoggerFactory.getLogger(WaiterXVSM.class);
21     private final int waiterId;
22
23     public WaiterXVSM(int waiterId, int port) {
24         super(port);
25
26         this.waiterId = waiterId;
27
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);
47     }
48
49     public void listenForPhoneOrders() {
50         getDefaultBuilder("listenForPhoneOrders").setCref(phoneCallsContainer).setLookaround(true).setSpaceAction(new SpaceAction() {
51             @Override
52             public void onEntriesWritten(List<? extends Serializable> entries) throws Exception {
53                 final List<DeliveryGroupData> phoneOrders = castEntries(entries);
54
55                 if(inNotification.get()) Collections.shuffle(phoneOrders);
56
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);
61
62                     final TransactionReference tx = getDefaultTransaction();
63                     try {
64                         // Get the  delete lock so that only one waiter can answer this particular phone call
65                         takeMatchingEntity(template, phoneCallsContainer, tx, RequestTimeout.ZERO, errorMsg);
66
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);
71
72                         updatePizzeriaOrderNumber(order, tx);
73
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);
83
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) {
91                         e.printStackTrace();
92                     }
93                 }
94
95             }
96         }).createSpaceListenerImpl();
97     }
98
99     public void listenForFreeTable() {
100         getDefaultBuilder("listenForFreeTable").setCref(freeTablesContainer).setSpaceAction(new SpaceAction() {
101
102             @Override
103             public void onEntriesWritten(List<? extends Serializable> entries) throws Exception {
104
105                 List<Table> tables = castEntries(entries);
106
107                 for (Table table : tables) {
108
109                     TransactionReference tx = getDefaultTransaction();
110
111                     // Acquire a lock for the free table in the
112                     // FreeTableContainer
113                     int id = table.getId();
114
115                     Table tableTemplate = new Table(id);
116                     try {
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);
121
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);
127
128                         assignGroupToTable(lockedGroup, lockedFreeTable, tx);
129                     }  catch(EntryLockedException e) {
130                         capi.rollbackTransaction(tx);
131                     } catch (Exception e) {
132 //                                              log.info(e.getMessage());
133                     }
134                 }
135             }
136         }).createSpaceListenerImpl();
137     }
138
139
140     public void listenForNewGuests() {
141         getDefaultBuilder("listenForNewGuests").setLookaround(true).setCref(assignTableContainer).setSpaceAction(new SpaceAction() {
142
143             @Override
144             public void onEntriesWritten(List<? extends Serializable> entries)
145                     throws Exception {
146                 log.info("New guest groups have arrived");
147
148                 List<GroupData> groups = castEntries(entries);
149
150                 for (GroupData group : groups) {
151
152                     TransactionReference tx = getDefaultTransaction();
153
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());
157
158                     try {
159                         final GroupData templateGroup = new GroupData(group.getId());
160                         GroupData lockedGroup = takeMatchingEntity(
161                                 templateGroup,
162                                 assignTableContainer, tx,
163                                 RequestTimeout.ZERO, groupNotFound);
164                         takeMatchingEntityIfItExists(templateGroup, pizzeriaGroupContainer, tx, RequestTimeout.DEFAULT);
165                         // Acquire a lock for one free table in the
166                         // TablesContainer
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,
171                                 noFreeTable);
172                         takeMatchingEntityIfItExists(lockedFreeTable, pizzeriaTableContainer, tx, RequestTimeout.DEFAULT);
173
174                         assignGroupToTable(lockedGroup, lockedFreeTable, tx);
175                     }  catch(EntryLockedException e) {
176                         capi.rollbackTransaction(tx);
177                     } catch (Exception e) {
178 //                                              log.info(e.getMessage());
179                     }
180                 }
181             }
182         }).createSpaceListenerImpl();
183     }
184
185     public void listenForPaymentRequest() {
186         getDefaultBuilder("listenForPayment").setLookaround(true).setCref(paymentRequestContainer).setSpaceAction(new SpaceAction() {
187
188             @Override
189             public void onEntriesWritten(List<? extends Serializable> entries)
190                     throws Exception {
191
192                 List<GroupData> groups = castEntries(entries);
193
194                 for (GroupData groupData : groups) {
195                     TransactionReference tx = getDefaultTransaction();
196                     GroupData entity = new GroupData(groupData.getId());
197                     entity.setState(GroupState.PAY);
198
199                     // Acquire the lock so that another waiter can't do the same
200                     // thing!
201                     String paymentRequestTakenByOtherWaiter = String.format(
202                             "The payment request for group %d was already taken by an other waiter!",
203                             groupData.getId());
204                     try {
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);
209
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);
217
218                         final List<GroupData> groupsPayed = Arrays.asList(group);
219                         sendItemsToContainer(groupsPayed, paymentDoneContainer, RequestTimeout.DEFAULT, tx);
220                         sendItemsToContainer(groupsPayed, pizzeriaGroupContainer, RequestTimeout.DEFAULT, tx);
221
222                         capi.commitTransaction(tx);
223                     }  catch(EntryLockedException e) {
224                         capi.rollbackTransaction(tx);
225                     } catch (Exception e) {
226                                                 log.info(e.getMessage());
227                     }
228                 }
229             }
230         }).createSpaceListenerImpl();
231     }
232
233     public void listenForOrderRequests() {
234         getDefaultBuilder("listenForOrderRequest").setLookaround(true).setCref(takeOrderContainer).setSpaceAction(new SpaceAction() {
235
236             @Override
237             public void onEntriesWritten(List<? extends Serializable> entries)
238                     throws Exception {
239
240                 List<GroupData> groups = castEntries(entries);
241
242                 for (GroupData groupData : groups) {
243
244                     TransactionReference tx = getDefaultTransaction();
245                     GroupData entity = new GroupData(groupData.getId());
246                     entity.setState(GroupState.SITTING);
247
248                     try {
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!",
252                                 groupData.getId());
253                         takeMatchingEntity(entity, takeOrderContainer, tx, RequestTimeout.ZERO, orderTakenByOtherWaiter);
254                         GroupData group = takeMatchingEntityIfItExists(entity, pizzeriaGroupContainer, tx, RequestTimeout.INFINITE);
255
256                         group.setOrderWaiter(waiterId);
257                         group.setState(GroupState.ORDERED);
258                         Order order = group.getOrder();
259                         order.setStatus(OrderStatus.ORDERED);
260
261                         /*  get the id of the last order of the pizzeria and set the order accordingly and
262                             update the space */
263                         updatePizzeriaOrderNumber(order, tx);
264
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);
274
275                         log.info("Waiter has taken order from group {}",
276                                 group.getId());
277                     }  catch(EntryLockedException e) {
278                         capi.rollbackTransaction(tx);
279                     } catch (Exception e) {
280 //                                              log.info(e.getMessage());
281                     }
282                 }
283             }
284         }).createSpaceListenerImpl();
285     }
286
287     public void listenForPreparedPizzas() {
288         /**
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!
295          */
296         getDefaultBuilder("listenForPreparedPizzas").setLookaround(true).setCref(preparedPizzasContainer).setSpaceAction(new SpaceAction() {
297
298             @Override
299             public void onEntriesWritten(List<? extends Serializable> entries)
300                     throws Exception {
301
302                 List<Pizza> pizzas = castEntries(entries);
303
304                 for (Pizza pizza : pizzas) {
305                     int orderId = pizza.getOrderId();
306                     Order order = new Order();
307                     order.setId(orderId);
308
309                     TransactionReference tx = getDefaultTransaction();
310
311                     try {
312                         GroupData entity = new GroupData();
313                         entity.setState(GroupState.ORDERED);
314                         entity.setOrder(order);
315
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();
322
323                         Pizza pizzaTemplate = new Pizza();
324                         pizzaTemplate.setOrderId(orderId);
325
326                         List<Pizza> pizzasOfOrder = takeMatchingEntities(
327                                 pizzaTemplate, preparedPizzasContainer, tx,
328                                 RequestTimeout.DEFAULT,
329                                 "Cannot take the pizzas from the preparedPizzasContainer");
330
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,
338                                     tx);
339                             sendItemsToContainer(groupsWithCompleteOrder,
340                                     pizzeriaGroupContainer, RequestTimeout.DEFAULT,
341                                     tx);
342
343                             capi.commitTransaction(tx);
344                         } else {
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);
350                         }
351                     } catch (NullPointerException e) {
352
353                     } catch (Exception e) {
354                         capi.rollbackTransaction(tx);
355                     }
356                 }
357             }
358         }).createSpaceListenerImpl();
359     }
360
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());
366
367         // The new group now wants to order
368         lockedGroup.setState(GroupState.SITTING);
369         lockedGroup.setTable(lockedFreeTable);
370         lockedGroup.setTableWaiter(waiterId);
371
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);
381
382         try {
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());
390         }
391     }
392
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
395         update the space */
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;
399         order.setId(nextId);
400         final List<PizzaOrder> orderedPizzas = order.getOrderedPizzas();
401         for (PizzaOrder orderedPizza : orderedPizzas) {
402             orderedPizza.setOrderId(nextId);
403         }
404         sendItemsToContainer(Arrays.asList(new OrderId(nextId)), pizzeriaInfoContainer, RequestTimeout.DEFAULT, tx);
405     }
406 }