]> git.somenet.org - pub/jan/sbc.git/blob - src/main/java/at/ac/tuwien/sbc/valesriegler/xvsm/WaiterXVSM.java
[XVSM] Create initial Pizzeria Recovery support.
[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 org.mozartspaces.core.MzsConstants;
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;
12
13 import java.io.Serializable;
14 import java.util.Arrays;
15 import java.util.List;
16
17 public class WaiterXVSM extends AbstractXVSMConnector {
18     private static final Logger log = LoggerFactory.getLogger(WaiterXVSM.class);
19     private final int waiterId;
20
21     public WaiterXVSM(int waiterId, int port) {
22         super(port);
23
24         this.waiterId = waiterId;
25
26         freeTablesContainer = useContainer(Util.FREE_TABLES);
27         assignTableContainer = useContainer(Util.ASSIGN_TABLE);
28         takeOrderContainer = useContainer(Util.TAKE_ORDER);
29         orderTakenContainer = useContainer(Util.ORDER_TAKEN);
30         deliveryOrderTakenContainer = useContainer(Util.DELIVERY_ORDER_TAKEN);
31         preparePizzasContainer = useContainer(Util.PREPARE_PIZZAS);
32         prepareDeliveryPizzasContainer = useContainer(Util.PREPARE_DELIVERY_PIZZAS);
33         orderCompleteContainer = useContainer(Util.ORDER_COMPLETE);
34         preparedPizzasContainer = useContainer(Util.DELIVER_PIZZAS);
35         paymentRequestContainer = useContainer(Util.PAYMENT_REQUEST);
36         paymentDoneContainer = useContainer(Util.PAYMENT_DONE);
37         tableAssignedContainer = useContainer(Util.TABLE_ASSIGNED);
38         pizzeriaInfoContainer = useContainer(Util.PIZZERIA_INFO);
39         phoneCallsContainer = useContainer(Util.PHONE_CALLS);
40         preparedDeliveryPizzasContainer = useContainer(Util.DELIVER_DELIVERY_PIZZAS);
41         deliverDeliveryOrder = useContainer(Util.DELIVER_DELIVERY_ORDER);
42     }
43
44     public void listenForPhoneOrders() {
45         SpaceListener phoneListener = new SpaceListenerImpl(capi, phoneCallsContainer, true) {
46             @Override
47             void onEntriesWritten(List<? extends Serializable> entries) throws Exception {
48                 final List<DeliveryGroupData> phoneOrders = castEntries(entries);
49
50                 for (DeliveryGroupData phoneOrder : phoneOrders) {
51                     final int id = phoneOrder.getId();
52                     final DeliveryGroupData template = new DeliveryGroupData(id);
53                     final String errorMsg = String.format("There was phone call with id %d", id);
54
55                     final TransactionReference tx = getDefaultTransaction();
56                     try {
57                         final DeliveryGroupData groupFromSpace = takeMatchingEntity(template, phoneCallsContainer, tx, RequestTimeout.DEFAULT, errorMsg);
58                         groupFromSpace.setWaiterIdOfOrder(WaiterXVSM.this.waiterId);
59                         final Order order = groupFromSpace.getOrder();
60                         groupFromSpace.setDeliveryStatus(DeliveryStatus.ORDERED);
61
62                         updatePizzeriaOrderNumber(order, tx);
63
64
65                         // send the order as a whole to the space
66                         final List<DeliveryGroupData> groupsWhoHaveOrdered = Arrays.asList(groupFromSpace);
67                         sendItemsToContainer(groupsWhoHaveOrdered,
68                                 deliveryOrderTakenContainer, RequestTimeout.ZERO, tx);
69                         sendItemsToContainer(order.getOrderedPizzas(),
70                                 prepareDeliveryPizzasContainer, RequestTimeout.ZERO, tx);
71                         capi.commitTransaction(tx);
72
73                         log.info("Waiter has taken a phone delivery call!");
74                     } catch (Exception e) {
75                     }
76
77
78                 }
79
80             }
81         };
82         createNotification(phoneListener, phoneCallsContainer);
83     }
84
85     private void updatePizzeriaOrderNumber(Order order, TransactionReference tx) throws MzsCoreException {
86     /*  get the id of the last order of the pizzeria and set the order accordingly and
87         update the space */
88         final OrderId orderId = takeMatchingEntity(new OrderId(null), pizzeriaInfoContainer, tx, RequestTimeout.INFINITE, "The Order id object could not be taken from the space!");
89         final int id = orderId.getId();
90         final int nextId = id + 1;
91         order.setId(nextId);
92         final List<PizzaOrder> orderedPizzas = order.getOrderedPizzas();
93         for (PizzaOrder orderedPizza : orderedPizzas) {
94             orderedPizza.setOrderId(nextId);
95         }
96         sendItemsToContainer(Arrays.asList(new OrderId(nextId)), pizzeriaInfoContainer, RequestTimeout.DEFAULT, tx);
97     }
98
99
100     public void listenForFreeTable() {
101         SpaceListener listener = new SpaceListenerImpl(capi, freeTablesContainer, false) {
102
103             @Override
104             void onEntriesWritten(List<? extends Serializable> entries) throws Exception {
105
106                 List<Table> tables = castEntries(entries);
107
108                 for (Table table : tables) {
109
110                     TransactionReference tx = getDefaultTransaction();
111
112                     // Acquire a lock for the free table in the
113                     // FreeTableContainer
114                     int id = table.getId();
115
116                     Table tableTemplate = new Table(id);
117                     try {
118                         Table lockedFreeTable = takeMatchingEntity(tableTemplate,
119                                 freeTablesContainer, tx, RequestTimeout.DEFAULT,
120                                 String.format("There was no free table found with id %d", id));
121
122
123                         GroupData groupTemplate = new GroupData();
124                         GroupData lockedGroup = takeMatchingEntity(groupTemplate,
125                                 assignTableContainer, tx, RequestTimeout.DEFAULT,
126                                 "There is no group waiting for a table at the moment");
127
128                         assignGroupToTable(lockedGroup, lockedFreeTable, tx);
129                     } catch (Exception e) {
130 //                                              log.info(e.getMessage());
131                     }
132                 }
133             }
134         };
135
136         createNotification(listener, freeTablesContainer);
137     }
138
139     public void listenForNewGuests() {
140         SpaceListener listener = new SpaceListenerImpl(capi, assignTableContainer) {
141
142             @Override
143             void onEntriesWritten(List<? extends Serializable> entries)
144                     throws Exception {
145                 log.info("New guest groups have arrived");
146
147                 List<GroupData> groups = castEntries(entries);
148
149                 for (GroupData group : groups) {
150
151                     TransactionReference tx = getDefaultTransaction();
152
153                     // Acquire a lock for the group in the
154                     // AssignTableContainer
155                     String groupNotFound = String.format("Group with id %d was already assigned a table by another waiter!", group.getId());
156
157                     try {
158                         GroupData lockedGroup = takeMatchingEntity(
159                                 new GroupData(group.getId()),
160                                 assignTableContainer, tx,
161                                 RequestTimeout.DEFAULT, groupNotFound);
162                         // Acquire a lock for one free table in the
163                         // TablesContainer
164                         String noFreeTable = String.format("No free table for group with id %d could be found", group.getId());
165                         Table lockedFreeTable = takeMatchingEntity(new Table(null), freeTablesContainer, tx, RequestTimeout.DEFAULT,
166                                 noFreeTable);
167
168                         assignGroupToTable(lockedGroup, lockedFreeTable, tx);
169                     } catch (Exception e) {
170 //                                              log.info(e.getMessage());
171                     }
172                 }
173             }
174         };
175
176         createNotification(listener, assignTableContainer);
177     }
178
179     public void listenForPaymentRequest() {
180         SpaceListener paymentListener = new SpaceListenerImpl(capi, paymentRequestContainer) {
181
182             @Override
183             void onEntriesWritten(List<? extends Serializable> entries)
184                     throws Exception {
185
186                 List<GroupData> groups = castEntries(entries);
187
188                 for (GroupData groupData : groups) {
189                     TransactionReference tx = getDefaultTransaction();
190                     GroupData entity = new GroupData(groupData.getId());
191
192                     // Acquire the lock so that another waiter can't do the same
193                     // thing!
194                     String paymentRequestTakenByOtherWaiter = String.format(
195                             "The payment request for group %d was already taken by an other waiter!",
196                             groupData.getId());
197                     try {
198                         takeMatchingEntity(entity, paymentRequestContainer, tx, RequestTimeout.DEFAULT, paymentRequestTakenByOtherWaiter);
199
200                         groupData.setPayingWaiter(waiterId);
201
202                         final List<GroupData> groupsPayed = Arrays.asList(groupData);
203                         sendItemsToContainer(groupsPayed, paymentDoneContainer, RequestTimeout.ZERO, tx);
204
205                         capi.commitTransaction(tx);
206                     } catch (Exception e) {
207 //                                              log.info(e.getMessage());
208                     }
209                 }
210             }
211         };
212
213         createNotification(paymentListener, paymentRequestContainer);
214     }
215
216     public void listenForOrderRequests() {
217         SpaceListener ordersListener = new SpaceListenerImpl(capi, takeOrderContainer) {
218
219             @Override
220             void onEntriesWritten(List<? extends Serializable> entries)
221                     throws Exception {
222
223                 List<GroupData> groups = castEntries(entries);
224
225                 for (GroupData groupData : groups) {
226
227                     TransactionReference tx = getDefaultTransaction();
228                     GroupData entity = new GroupData(groupData.getId());
229                     entity.setState(GroupState.SITTING);
230
231                     try {
232                         // Acquire the lock so that another waiter can't do the same thing!
233                         String orderTakenByOtherWaiter = String.format(
234                                 "The order for group %d was already taken by an other waiter!",
235                                 groupData.getId());
236                         takeMatchingEntity(entity, takeOrderContainer, tx, RequestTimeout.DEFAULT, orderTakenByOtherWaiter);
237
238                         groupData.setOrderWaiter(waiterId);
239                         groupData.setState(GroupState.ORDERED);
240                         Order order = groupData.getOrder();
241                         order.setStatus(OrderStatus.ORDERED);
242
243                         /*  get the id of the last order of the pizzeria and set the order accordingly and
244                             update the space */
245                         updatePizzeriaOrderNumber(order, tx);
246
247                         // send the order as a whole to the space
248                         final List<GroupData> groupsWhoHaveOrdered = Arrays.asList(groupData);
249                         sendItemsToContainer(groupsWhoHaveOrdered,
250                                 orderTakenContainer, RequestTimeout.ZERO, tx);
251                         sendItemsToContainer(order.getOrderedPizzas(),
252                                 preparePizzasContainer, RequestTimeout.ZERO, tx);
253                         capi.commitTransaction(tx);
254
255                         log.info("Waiter has taken order from group {}",
256                                 groupData.getId());
257                     } catch (Exception e) {
258 //                                              log.info(e.getMessage());
259                     }
260                 }
261             }
262         };
263
264         createNotification(ordersListener, takeOrderContainer);
265     }
266
267     public void listenForPreparedPizzas() {
268         /**
269          * A waiter gets informed when a new pizza is complete. He takes the
270          * orderId of the pizza and looks up the corresponding order from which
271          * he gets the number of necessary pizzas of the order. He then tries to
272          * fetch all pizzas with the corresponding orderId and compares the
273          * number of those pizzas with the number of necessary pizzas. If all
274          * pizzas of an order are complete he then delivers them!
275          */
276         SpaceListener preparedPizzasListener = new SpaceListenerImpl(capi, preparedPizzasContainer) {
277
278             @Override
279             void onEntriesWritten(List<? extends Serializable> entries)
280                     throws Exception {
281
282                 List<Pizza> pizzas = castEntries(entries);
283
284                 for (Pizza pizza : pizzas) {
285                     int orderId = pizza.getOrderId();
286                     Order order = new Order();
287                     order.setId(orderId);
288
289                     TransactionReference tx = getDefaultTransaction();
290                     final boolean isDeliveryPizza = pizza.isDeliveryPizza();
291
292                     try {
293                         GroupData entity = new GroupData();
294                         entity.setState(null);
295                         entity.setOrder(order);
296
297                         GroupData groupData = takeMatchingEntity(entity,
298                                 orderTakenContainer, tx, RequestTimeout.DEFAULT,
299                                 "Another waiter just checks if the order is complete");
300                         int groupId = groupData.getId();
301                         int numberOfPizzas = groupData.getOrder().getNumberOfPizzas();
302
303                         Pizza pizzaTemplate = new Pizza();
304                         pizzaTemplate.setOrderId(orderId);
305
306                         List<Pizza> pizzasOfOrder = takeMatchingEntities(
307                                 pizzaTemplate, preparedPizzasContainer, tx,
308                                 RequestTimeout.DEFAULT,
309                                 "Cannot take the pizzas from the preparedPizzasContainer");
310
311                         if (pizzasOfOrder.size() == numberOfPizzas) {
312                             GroupData group = new GroupData();
313                             group.setServingWaiter(waiterId);
314                             Order completeOrder = new Order();
315                             completeOrder.setId(orderId);
316                             completeOrder.setGroupId(groupId);
317                             group.setOrder(completeOrder);
318                             final List<GroupData> groupsWithCompleteOrder = Arrays.asList(group);
319                             sendItemsToContainer(groupsWithCompleteOrder,
320                                     orderCompleteContainer, RequestTimeout.DEFAULT,
321                                     tx);
322
323                             capi.commitTransaction(tx);
324                         } else {
325                             log.info("Not yet all pizzas prepared! Order with id "
326                                     + orderId + " has " + numberOfPizzas
327                                     + " pizzas, but only " + pizzasOfOrder.size()
328                                     + " pizzas are ready by now!");
329                             capi.rollbackTransaction(tx);
330                         }
331                     } catch (NullPointerException e) {
332
333                     } catch (Exception e) {
334                         capi.rollbackTransaction(tx);
335                     }
336                 }
337             }
338         };
339
340         createNotification(preparedPizzasListener, preparedPizzasContainer);
341     }
342
343
344     public void listenForPreparedDeliveryPizzas() {
345         /**
346          * A waiter gets informed when a new pizza is complete. He takes the
347          * orderId of the pizza and looks up the corresponding order from which
348          * he gets the number of necessary pizzas of the order. He then tries to
349          * fetch all pizzas with the corresponding orderId and compares the
350          * number of those pizzas with the number of necessary pizzas. If all
351          * pizzas of an order are complete he then delivers them!
352          */
353         SpaceListener preparedPizzasListener = new SpaceListenerImpl(capi, preparedDeliveryPizzasContainer, true) {
354
355             @Override
356             void onEntriesWritten(List<? extends Serializable> entries)
357                     throws Exception {
358
359                 List<Pizza> pizzas = castEntries(entries);
360
361                 for (Pizza pizza : pizzas) {
362                     int orderId = pizza.getOrderId();
363                     Order order = new Order();
364                     order.setId(orderId);
365
366                     TransactionReference tx = getDefaultTransaction();
367
368                     try {
369                         DeliveryGroupData entity = new DeliveryGroupData();
370                         entity.setDeliveryStatus(null);
371                         entity.setOrder(order);
372
373                         DeliveryGroupData groupData = takeMatchingEntity(entity,
374                                 deliveryOrderTakenContainer, tx, MzsConstants.RequestTimeout.DEFAULT,
375                                 "Another driver just checks if the delivery order is complete");
376                         int groupId = groupData.getId();
377                         int numberOfPizzas = groupData.getOrder().getNumberOfPizzas();
378
379                         Pizza pizzaTemplate = new Pizza();
380                         pizzaTemplate.setOrderId(orderId);
381
382                         List<Pizza> pizzasOfOrder = takeMatchingEntities(
383                                 pizzaTemplate, preparedDeliveryPizzasContainer, tx,
384                                 MzsConstants.RequestTimeout.DEFAULT,
385                                 "Cannot take the pizzas from the preparedDeliveryPizzasContainer");
386
387                         if (pizzasOfOrder.size() == numberOfPizzas) {
388                             DeliveryGroupData group = new DeliveryGroupData();
389                             Order completeOrder = new Order();
390                             completeOrder.setId(orderId);
391                             completeOrder.setGroupId(groupId);
392                             group.setOrder(completeOrder);
393                             final List<DeliveryGroupData> groupsWithCompleteOrder = Arrays.asList(group);
394                             sendItemsToContainer(groupsWithCompleteOrder,
395                                     deliverDeliveryOrder, MzsConstants.RequestTimeout.DEFAULT,
396                                     tx);
397
398                             capi.commitTransaction(tx);
399                         } else {
400                             log.info("Not yet all pizzas prepared! Order with id "
401                                     + orderId + " has " + numberOfPizzas
402                                     + " pizzas, but only " + pizzasOfOrder.size()
403                                     + " pizzas are ready by now!");
404                             capi.rollbackTransaction(tx);
405                         }
406                     } catch (NullPointerException e) {
407
408                     } catch (Exception e) {
409                         capi.rollbackTransaction(tx);
410                     }
411                 }
412             }
413         };
414
415         createNotification(preparedPizzasListener, preparedDeliveryPizzasContainer);
416     }
417
418     private void assignGroupToTable(GroupData lockedGroup,
419                                     Table lockedFreeTable, TransactionReference tx)
420             throws MzsCoreException {
421         // The new group sits down at the table
422         lockedFreeTable.setGroupId(lockedGroup.getId());
423
424         // The new group now wants to order
425         lockedGroup.setState(GroupState.SITTING);
426         lockedGroup.setTable(lockedFreeTable);
427         lockedGroup.setTableWaiter(waiterId);
428
429         final List<Table> freeTables = Arrays.asList(lockedFreeTable);
430         sendItemsToContainer(freeTables,
431                 tableAssignedContainer, RequestTimeout.ZERO, tx);
432         sendItemsToContainer(Arrays.asList(lockedGroup), takeOrderContainer,
433                 RequestTimeout.ZERO, tx);
434
435         try {
436             capi.commitTransaction(tx);
437             log.info("Assigned table to group with groupId {}",
438                     lockedGroup.getId());
439         } catch (Exception e) {
440             log.info("Assigning a table to group with groupId {} failed",
441                     lockedGroup.getId());
442             log.info(e.getMessage());
443         }
444     }
445 }