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