]> git.somenet.org - pub/jan/sbc.git/blob - src/main/java/at/ac/tuwien/sbc/valesriegler/xvsm/WaiterXVSM.java
Space waiters pay and overall remaining space workflow refactoring
[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 java.io.Serializable;
4 import java.net.URI;
5 import java.util.ArrayList;
6 import java.util.Arrays;
7 import java.util.Collections;
8 import java.util.Iterator;
9 import java.util.List;
10
11 import javax.swing.text.html.parser.Entity;
12
13 import org.mozartspaces.capi3.AnyCoordinator;
14 import org.mozartspaces.capi3.LindaCoordinator;
15 import org.mozartspaces.core.MzsConstants;
16 import org.mozartspaces.core.MzsConstants.RequestTimeout;
17 import org.mozartspaces.core.MzsCoreException;
18 import org.mozartspaces.core.TransactionException;
19 import org.mozartspaces.core.TransactionReference;
20 import org.mozartspaces.notifications.Notification;
21 import org.mozartspaces.notifications.NotificationListener;
22 import org.mozartspaces.notifications.Operation;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
25
26 import at.ac.tuwien.sbc.valesriegler.common.Util;
27 import at.ac.tuwien.sbc.valesriegler.types.GroupData;
28 import at.ac.tuwien.sbc.valesriegler.types.GroupState;
29 import at.ac.tuwien.sbc.valesriegler.types.Order;
30 import at.ac.tuwien.sbc.valesriegler.types.OrderStatus;
31 import at.ac.tuwien.sbc.valesriegler.types.Pizza;
32 import at.ac.tuwien.sbc.valesriegler.types.Table;
33
34 public class WaiterXVSM extends AbstractXVSMConnector {
35         private static final Logger log = LoggerFactory.getLogger(WaiterXVSM.class);
36         private final int waiterId;
37
38         public WaiterXVSM(int waiterId) {
39                 super();
40
41                 this.waiterId = waiterId;
42
43                 freeTablesContainer = useContainer(Util.FREE_TABLES);
44                 assignTableContainer = useContainer(Util.ASSIGN_TABLE) ;
45                 tablesContainer = useContainer(Util.TABLES_CONTAINER) ;
46                 takeOrderContainer = useContainer(Util.TAKE_ORDER) ;
47                 ordersContainer = useContainer(Util.ORDER) ;
48                 preparePizzasContainer = useContainer(Util.PREPARE_PIZZAS) ;
49                 groupsContainer = useContainer(Util.GROUPS_CONTAINER) ;
50                 orderCompleteContainer = useContainer(Util.ORDER_COMPLETE) ;
51                 deliverPizzasContainer = useContainer(Util.DELIVER_PIZZAS);
52                 paymentContainer = useContainer(Util.PAYMENT) ;
53                 hasPaidContainer = useContainer(Util.HAS_PAID) ;
54         }
55
56         public void listenForFreeTable() {
57
58                 NotificationListener freeTableListener = new NotificationListener() {
59                         @Override
60                         public void entryOperationFinished(final Notification notification,
61                                         final Operation operation,
62                                         final List<? extends Serializable> entries) {
63
64                                 log.info("{} tables have become free", entries.size());
65
66                                 List<Table> tables = castEntries(entries);
67                                 Collections.shuffle(tables);
68
69                                 for (Table table : tables) {
70                                         try {
71                                                 TransactionReference tx = capi.createTransaction(3000,
72                                                                 URI.create(Util.SERVER_ADDR));
73
74                                                 try {
75                                                         // Acquire a lock for the free table in the
76                                                         // FreeTableContainer
77                                                         int id = table.getId();
78                                                         log.info("Try to find the table with id {}", id);
79
80                                                         Table tableTemplate = new Table(id);
81                                                         Table lockedFreeTable = takeMatchingEntity(
82                                                                         tableTemplate,
83                                                                         freeTablesContainer,
84                                                                         tx,
85                                                                         1000,
86                                                                         String.format(
87                                                                                         "There was no free table found with id %d",
88                                                                                         id));
89
90                                                         log.info("Table with id {} was found", id);
91
92                                                         GroupData groupTemplate = new GroupData();
93                                                         GroupData lockedGroup = takeMatchingEntity(
94                                                                         groupTemplate, assignTableContainer, tx,
95                                                                         RequestTimeout.DEFAULT,
96                                                                         "There is no group waiting for a table at the moment");
97
98                                                         assignGroupToTable(lockedGroup, lockedFreeTable, tx);
99
100                                                 } catch (IllegalArgumentException e) {
101                                                         log.info("IllegalArgumentException");
102                                                         e.printStackTrace();
103                                                 } catch (EntityNotFoundByTemplate e) {
104                                                         log.info(e.getMessage());
105                                                 } catch (Exception e) {
106                                                         log.error("AN INNER EXCEPTION");
107                                                         e.printStackTrace();
108                                                 }
109                                         } catch (TransactionException e) {
110                                                 log.info("An unimportant TransactionException has occurred");
111                                         } catch (Exception e) {
112                                                 log.error("OUTER EXCEPTION");
113                                         }
114
115                                 }
116                         }
117                 };
118                 try {
119                         notificationMgr.createNotification(freeTablesContainer,
120                                         freeTableListener, Operation.WRITE);
121                         log.info("Created freeTablesContainer notification for a waiter");
122                 } catch (Exception e) {
123                         handleSpaceErrorAndTerminate(e);
124                 }
125
126         }
127
128         public void listenForNewGuests() {
129                 NotificationListener newGroupsListener = new NotificationListener() {
130                         @Override
131                         public void entryOperationFinished(final Notification notification,
132                                         final Operation operation,
133                                         final List<? extends Serializable> entries) {
134
135                                 log.info("New guest groups have arrived");
136
137                                 List<GroupData> groups = castEntries(entries);
138                                 Collections.shuffle(groups);
139
140                                 for (GroupData group : groups) {
141                                         try {
142                                                 TransactionReference tx = capi.createTransaction(1500,
143                                                                 URI.create(Util.SERVER_ADDR));
144
145                                                 try {
146                                                         // Acquire a lock for the group in the
147                                                         // AssignTableContainer
148                                                         String groupNotFound = String
149                                                                         .format("Group with id %d was already assigned a table by another waiter!",
150                                                                                         group.getId());
151
152                                                         GroupData lockedGroup = takeMatchingEntity(
153                                                                         new GroupData(group.getId()),
154                                                                         assignTableContainer, tx, 1000,
155                                                                         groupNotFound);
156                                                         // Acquire a lock for one free table in the
157                                                         // TablesContainer
158                                                         Table lockedFreeTable = takeMatchingEntity(
159                                                                         new Table(null),
160                                                                         freeTablesContainer,
161                                                                         tx,
162                                                                         RequestTimeout.DEFAULT,
163                                                                         String.format(
164                                                                                         "No free table for group with id %d could be found",
165                                                                                         group.getId()));
166
167                                                         assignGroupToTable(lockedGroup, lockedFreeTable, tx);
168
169                                                 } catch (IllegalArgumentException e) {
170                                                         log.info("IllegalArgumentException");
171                                                         e.printStackTrace();
172                                                 } catch (EntityNotFoundByTemplate e) {
173                                                         log.info(e.getMessage());
174                                                 } catch (Exception e) {
175                                                         log.error("AN INNER EXCEPTION");
176                                                         e.printStackTrace();
177                                                 }
178                                         } catch (TransactionException e) {
179                                                 log.info("An unimportant TransactionException has occurred");
180                                         } catch (Exception e) {
181                                                 log.error("OUTER EXCEPTION");
182                                         }
183
184                                 }
185                         }
186                 };
187                 try {
188                         notificationMgr.createNotification(assignTableContainer,
189                                         newGroupsListener, Operation.WRITE);
190                         log.info("Created assingTableContainer notification for a waiter");
191                 } catch (Exception e) {
192                         handleSpaceErrorAndTerminate(e);
193                 }
194         }
195
196         public void listenForPaymentRequest() {
197                 log.info("INITIALIZE PAYMENT NOTIFICATION");
198                 NotificationListener paymentListener = new NotificationListener() {
199                         @Override
200                         public void entryOperationFinished(final Notification notification,
201                                         final Operation operation,
202                                         final List<? extends Serializable> entries) {
203                                 log.info("A PAYMENT REQUEST HAS ARRIVED!");
204
205                                 List<GroupData> groups = castEntries(entries);
206                         
207                                 GroupData groupData = groups.get(0);
208
209                                 try {
210                                         TransactionReference tx = capi.createTransaction(1500,
211                                                         URI.create(Util.SERVER_ADDR));
212                                         GroupData entity = new GroupData(groupData.getId());
213
214                                         // Acquire the lock so that another waiter can't do the same
215                                         // thing!
216                                         takeMatchingEntity(
217                                                         entity,
218                                                         paymentContainer,
219                                                         tx,
220                                                         RequestTimeout.DEFAULT,
221                                                         String.format(
222                                                                         "The payment request for group %d was already taken by an other waiter!",
223                                                                         groupData.getId()));
224
225                                 
226                                         groupData.setPayingWaiter(waiterId);
227                                         
228                                         sendItemsToContainer(Arrays.asList(groupData),
229                                                         hasPaidContainer, RequestTimeout.ZERO, tx);
230
231                                         capi.commitTransaction(tx);
232
233                                 } catch (MzsCoreException e) {
234                                         log.info("ERROR in listenForPaymentRequest");
235                                         e.printStackTrace();
236                                 }
237                         }
238                 };
239
240                 try {
241                         notificationMgr.createNotification(paymentContainer,
242                                         paymentListener, Operation.WRITE);
243                         log.info("Created payment notification for a waiter");
244                 } catch (Exception e) {
245                         handleSpaceErrorAndTerminate(e);
246                 }
247         }
248
249         public void listenForOrders() {
250                 NotificationListener ordersListener = new NotificationListener() {
251                         @Override
252                         public void entryOperationFinished(final Notification notification,
253                                         final Operation operation,
254                                         final List<? extends Serializable> entries) {
255                                 log.info("A new order has arrived!");
256
257                                 List<GroupData> groups = castEntries(entries);
258                                 if (groups.size() != 1)
259                                         throw new RuntimeException(
260                                                         "Multiple orders in one notification?! That should not happen!");
261
262                                 GroupData groupData = groups.get(0);
263
264                                 try {
265                                         TransactionReference tx = capi.createTransaction(1500,
266                                                         URI.create(Util.SERVER_ADDR));
267                                         GroupData entity = new GroupData(groupData.getId());
268                                         entity.setState(GroupState.SITTING);
269
270                                         // Acquire the lock so that another waiter can't do the same
271                                         // thing!
272                                         takeMatchingEntity(
273                                                         entity,
274                                                         takeOrderContainer,
275                                                         tx,
276                                                         RequestTimeout.DEFAULT,
277                                                         String.format(
278                                                                         "The order for group %d was already taken by an other waiter!",
279                                                                         groupData.getId()));
280
281                                         log.info(
282                                                         "Will now write taken order from group {} to space",
283                                                         groupData.getId());
284                                         groupData.setOrderWaiter(waiterId);
285                                         groupData.setState(GroupState.ORDERED);
286                                         Order order = groupData.getOrder();
287                                         order.setStatus(OrderStatus.ORDERED);
288
289                                         sendItemsToContainer(Arrays.asList(groupData),
290                                                         ordersContainer, RequestTimeout.ZERO, tx);
291                                         sendItemsToContainer(Arrays.asList(groupData),
292                                                         groupsContainer, RequestTimeout.ZERO, tx);
293                                         sendItemsToContainer(order.getOrderedPizzas(),
294                                                         preparePizzasContainer, RequestTimeout.ZERO, tx);
295                                         capi.commitTransaction(tx);
296
297                                         log.info("Waiter has taken order from group {}",
298                                                         groupData.getId());
299                                 } catch (MzsCoreException e) {
300                                         log.info("ERROR in listenForOrders");
301                                         e.printStackTrace();
302                                 }
303                         }
304                 };
305
306                 try {
307                         notificationMgr.createNotification(takeOrderContainer,
308                                         ordersListener, Operation.WRITE);
309                         log.info("Created takeOrderContainer notification for a waiter");
310                 } catch (Exception e) {
311                         handleSpaceErrorAndTerminate(e);
312                 }
313         }
314
315         public void listenForPreparedPizzas() {
316                 /**
317                  * A waiter gets informed when a new pizza is complete. He takes the
318                  * orderId of the pizza and looks up the corresponding order from which
319                  * he gets the number of necessary pizzas of the order. He then tries to
320                  * fetch all pizzas with the corresponding orderId and compares the
321                  * number of those pizzas with the number of necessary pizzas. If all
322                  * pizzas of an order are complete he then delivers them!
323                  */
324                 NotificationListener preparedPizzasListener = new NotificationListener() {
325                         @Override
326                         public void entryOperationFinished(final Notification notification,
327                                         final Operation operation,
328                                         final List<? extends Serializable> entries) {
329
330                                 List<Pizza> pizzas = castEntries(entries);
331                                 if (pizzas.size() != 1)
332                                         throw new RuntimeException(
333                                                         "Multiple pizzas in one notification?! That should not happen! A cook can only prepare one at the same time!");
334
335                                 Pizza pizza = pizzas.get(0);
336                                 int orderId = pizza.getOrderId();
337
338                                 try {
339                                         TransactionReference tx = capi.createTransaction(1500,
340                                                         URI.create(Util.SERVER_ADDR));
341
342                                         GroupData entity = new GroupData();
343                                         entity.setState(null);
344                                         Order order = new Order();
345                                         order.setId(orderId);
346                                         entity.setOrder(order);
347
348                                         GroupData groupData = takeMatchingEntity(entity,
349                                                         ordersContainer, tx, RequestTimeout.DEFAULT,
350                                                         "Another waiter just checks if the order is complete");
351                                         int groupId = groupData.getId();
352                                         int numberOfPizzas = groupData.getOrder()
353                                                         .getNumberOfPizzas();
354
355                                         Pizza pizzaTemplate = new Pizza();
356                                         pizzaTemplate.setOrderId(orderId);
357
358                                         List<Pizza> pizzasOfOrder = takeMatchingEntities(
359                                                         pizzaTemplate, deliverPizzasContainer, tx,
360                                                         RequestTimeout.DEFAULT,
361                                                         "Cannot take the pizzas from the deliverPizzasContainer");
362
363                                         // for an unkown reason even pizzas not matching the orderid
364                                         // are returned. that's why we have to check again if the
365                                         // pizza really belongs to the order in question
366                                         Iterator<Pizza> it = pizzasOfOrder.iterator();
367                                         while (it.hasNext()) {
368                                                 Pizza nextPizza = it.next();
369                                                 if (nextPizza.getOrderId() != orderId) {
370                                                         it.remove();
371                                                 }
372                                         }
373
374                                         if (pizzasOfOrder.size() == numberOfPizzas) {
375                                                 GroupData group = new GroupData();
376                                                 group.setServingWaiter(waiterId);
377                                                 Order completeOrder = new Order();
378                                                 completeOrder.setId(orderId);
379                                                 completeOrder.setGroupId(groupId);
380                                                 group.setOrder(completeOrder);
381                                                 sendItemsToContainer(Arrays.asList(group),
382                                                                 orderCompleteContainer, RequestTimeout.DEFAULT,
383                                                                 tx);
384                                                 capi.commitTransaction(tx);
385                                         } else {
386                                                 log.info("Not yet all pizzas prepared! Order with id "
387                                                                 + orderId + " has " + numberOfPizzas
388                                                                 + " pizzas, but only " + pizzasOfOrder.size()
389                                                                 + " pizzas are ready by now!");
390                                                 capi.rollbackTransaction(tx);
391                                         }
392
393                                 } catch (MzsCoreException e) {
394                                         log.error("ERROR in listenForPreparedPizzas!");
395                                         e.printStackTrace();
396                                 }
397                         }
398                 };
399
400                 try {
401                         notificationMgr.createNotification(deliverPizzasContainer,
402                                         preparedPizzasListener, Operation.WRITE);
403                         log.info("Created deliverPizzasContainer notification for a waiter");
404                 } catch (Exception e) {
405                         handleSpaceErrorAndTerminate(e);
406                 }
407         }
408
409         private void assignGroupToTable(GroupData lockedGroup,
410                         Table lockedFreeTable, TransactionReference tx)
411                         throws MzsCoreException {
412                 // The new group sits down at the table
413                 lockedFreeTable.setGroupId(lockedGroup.getId());
414
415                 // The new group now wants to order
416                 lockedGroup.setState(GroupState.SITTING);
417                 lockedGroup.setTable(lockedFreeTable);
418                 lockedGroup.setTableWaiter(waiterId);
419
420                 sendItemsToContainer(Arrays.asList(lockedFreeTable), tablesContainer,
421                                 RequestTimeout.ZERO, tx);
422                 sendItemsToContainer(Arrays.asList(lockedGroup), takeOrderContainer,
423                                 RequestTimeout.ZERO, tx);
424                 sendItemsToContainer(Arrays.asList(lockedGroup), groupsContainer,
425                                 RequestTimeout.ZERO, tx);
426
427                 try {
428                         capi.commitTransaction(tx);
429                         log.info("Assigned table to group with groupId {}",
430                                         lockedGroup.getId());
431                 } catch (Exception e) {
432                         log.info("Assigning a table to group with groupId {} failed",
433                                         lockedGroup.getId());
434                 }
435         }
436
437 }