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