]> git.somenet.org - pub/jan/sbc.git/blob - src/main/java/at/ac/tuwien/sbc/valesriegler/xvsm/XVSMConnector.java
Waiter listens for free tables and for new guests. When a table gets free he tries...
[pub/jan/sbc.git] / src / main / java / at / ac / tuwien / sbc / valesriegler / xvsm / XVSMConnector.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.List;
9
10 import org.bouncycastle.crypto.RuntimeCryptoException;
11 import org.mozartspaces.capi3.AnyCoordinator;
12 import org.mozartspaces.capi3.AnyCoordinator.AnySelector;
13 import org.mozartspaces.capi3.Coordinator;
14 import org.mozartspaces.capi3.CountNotMetException;
15 import org.mozartspaces.capi3.FifoCoordinator;
16 import org.mozartspaces.capi3.LindaCoordinator;
17 import org.mozartspaces.capi3.LindaCoordinator.LindaSelector;
18 import org.mozartspaces.core.Capi;
19 import org.mozartspaces.core.CapiUtil;
20 import org.mozartspaces.core.ContainerReference;
21 import org.mozartspaces.core.DefaultMzsCore;
22 import org.mozartspaces.core.Entry;
23 import org.mozartspaces.core.MzsConstants.RequestTimeout;
24 import org.mozartspaces.core.MzsCore;
25 import org.mozartspaces.core.MzsCoreException;
26 import org.mozartspaces.core.TransactionReference;
27 import org.mozartspaces.notifications.Notification;
28 import org.mozartspaces.notifications.NotificationListener;
29 import org.mozartspaces.notifications.NotificationManager;
30 import org.mozartspaces.notifications.Operation;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 import at.ac.tuwien.sbc.valesriegler.common.Util;
35 import at.ac.tuwien.sbc.valesriegler.types.GroupData;
36 import at.ac.tuwien.sbc.valesriegler.types.GroupState;
37 import at.ac.tuwien.sbc.valesriegler.types.Order;
38 import at.ac.tuwien.sbc.valesriegler.types.Table;
39
40 /**
41  * Responsible for XVSM Communication
42  * 
43  * @author Gregor Riegler <gregor DOT riegler AT gmail DOT com>
44  * 
45  */
46 public class XVSMConnector {
47         private static final Logger log = LoggerFactory.getLogger(XVSMConnector.class);
48
49         private ContainerReference tablesContainer;
50         private ContainerReference groupsContainer;
51         private ContainerReference assignTableContainer;
52         private ContainerReference takeOrderContainer;
53         private ContainerReference deliverPizzasContainer;
54         private ContainerReference paymentContainer;
55         private ContainerReference freeTablesContainer;
56 //      private ContainerReference notificationContainer;
57         private Capi capi;
58         private NotificationManager notificationMgr;
59
60
61         
62         public void initSpaceCommunication()  {
63                 try {
64                         MzsCore core = DefaultMzsCore.newInstanceWithoutSpace();
65                         capi = new Capi(core);
66                         notificationMgr = new NotificationManager(core);
67                 } catch (Exception e) {
68                         log.error("Space connection could not be established! Have you started the Space Server?");
69                         handleSpaceErrorAndTerminate(e);
70                 }
71         }
72         
73         public void useTablesContainer() {
74                 tablesContainer = useContainer(Util.TABLES_CONTAINER, createCoordinators(new AnyCoordinator(), new LindaCoordinator(false))) ;
75         }
76         
77         public void useTakeOrderContainer() {
78                 takeOrderContainer = useContainer(Util.TAKE_ORDER, createCoordinators(new AnyCoordinator(), new LindaCoordinator(false))) ;
79         }
80         
81         public void useGroupsContainer() {
82                 groupsContainer = useContainer(Util.GROUPS_CONTAINER, createCoordinators(new AnyCoordinator(), new LindaCoordinator(false))) ;
83         }
84         
85         public void useAssignTableContainer() {
86                 assignTableContainer = useContainer(Util.ASSIGN_TABLE, createCoordinators(new AnyCoordinator(), new LindaCoordinator(false))) ;
87         }
88         
89         public void useFreeTablesContainer() {
90                 freeTablesContainer = useContainer(Util.FREE_TABLES, createCoordinators(new AnyCoordinator(), new LindaCoordinator(false)));
91         }
92         
93         
94         
95         private ContainerReference useContainer(String containerName, List<Coordinator> coordinators) {
96                 try {
97                         return Util.getOrCreateNamedContainer(Util.SERVER_ADDR, containerName, capi, coordinators);
98                 } catch (MzsCoreException e) {
99                         handleSpaceErrorAndTerminate(e);
100                 }
101                 
102                 return null;
103         }
104
105         
106         public void sendTablesToSpace(List<Table> tables) {
107                 sendItemsToContainer(tables, tablesContainer);
108         }
109         
110         public void sendFreeTablesToSpace(List<Table> tables) {
111                 sendItemsToContainer(tables, freeTablesContainer);
112                 sendTablesToSpace(tables);
113         }
114
115
116         public void sendGroupsToSpace(List<GroupData> newGroups) {
117                 sendItemsToContainer(newGroups, groupsContainer);
118         }
119
120         public void handleWaitingGroup(int id) {
121
122                 try {
123                         TransactionReference tx = capi.createTransaction(RequestTimeout.INFINITE, URI.create(Util.SERVER_ADDR));
124                         Table table = null;
125                         try {
126                                 ArrayList<Table> tables = capi.take(tablesContainer, FifoCoordinator.newSelector(), RequestTimeout.ZERO, tx);
127                                 table = tables.get(0);
128                         } catch (Exception e) {
129                                 log.info("There is no free table");
130                                 capi.rollbackTransaction(tx);
131                                 return;
132                         }
133                         
134                         GroupData groupData = new GroupData(null);
135                         groupData.setState(GroupState.WAITING);
136                         LindaSelector sel = LindaCoordinator.newSelector(groupData, 1);
137                         ArrayList<GroupData> waitingGroups = null;
138                         
139                         try {
140                                 waitingGroups = capi.take(groupsContainer, sel, RequestTimeout.ZERO, tx);
141                         } catch (Exception e) {
142                                 log.info("There is no waiting group");
143                                 capi.rollbackTransaction(tx);
144                                 return;
145                         }
146                         
147                         GroupData group = waitingGroups.get(0);
148                         group.setTable(new Table(table.getGroupId()));
149                         group.setTableWaiter(id);
150                         group.setState(GroupState.SITTING);
151                         
152                         try {
153                                 capi.write(groupsContainer, RequestTimeout.TRY_ONCE,  tx, new Entry(group));
154                         } catch (Exception e) {
155                                 e.printStackTrace();
156                                 capi.rollbackTransaction(tx);
157                                 return;
158                         }
159                         
160                         try {
161                                 capi.write(new Entry(table), tablesContainer, RequestTimeout.TRY_ONCE, tx);
162                         } catch (Exception e) {
163                                 e.printStackTrace();
164                                 capi.rollbackTransaction(tx);
165                                 return;
166                         }
167                         
168                         capi.commitTransaction(tx);
169                 } catch (MzsCoreException e) {
170                         e.printStackTrace();
171                 }
172         }
173
174         public void handleOrderRequest(int id) {
175                 try {
176                         TransactionReference tx = capi.createTransaction(RequestTimeout.INFINITE, URI.create(Util.SERVER_ADDR));
177                                         
178                         GroupData groupData = new GroupData(null);
179                         groupData.setState(GroupState.SITTING);
180                         LindaSelector sel = LindaCoordinator.newSelector(groupData, 1);
181                         ArrayList<GroupData> sittingGroups = null;
182                         
183                         try {
184                                 sittingGroups = capi.take(groupsContainer, sel, RequestTimeout.ZERO, tx);
185                         } catch (Exception e) {
186                                 log.info("There is no sitting group");
187                                 capi.rollbackTransaction(tx);
188                                 return;
189                         }
190                         GroupData sittingGroup = sittingGroups.get(0);
191                         Order order = sittingGroup.getOrder();
192                         sittingGroup.setOrderWaiter(id);
193                         sittingGroup.setState(GroupState.ORDERED);
194                         
195                         try {
196                                 capi.write(new Entry(sittingGroup), groupsContainer, RequestTimeout.TRY_ONCE, tx);
197                         } catch (Exception e) {
198                                 e.printStackTrace();
199                                 capi.rollbackTransaction(tx);
200                                 return;
201                         }
202                         
203                         capi.commitTransaction(tx);
204                         
205                 } catch (MzsCoreException e) {
206                         e.printStackTrace();
207                 }
208         }
209
210         public void initTablesNotifications(NotificationListener listener) {
211         try {
212                 notificationMgr.createNotification(tablesContainer, listener, Operation.WRITE);
213         } catch (Exception e) {
214             handleSpaceErrorAndTerminate(e);
215         }
216         }
217         
218         public void initGroupNotifications(NotificationListener listener) {
219         try {
220                 notificationMgr.createNotification(groupsContainer, listener, Operation.WRITE);
221         } catch (Exception e) {
222            handleSpaceErrorAndTerminate(e);
223         }
224         }
225
226         public void handlePaymentRequest() {
227         }
228
229         public void handlePizzaDistribution() {
230         }
231         
232         
233         private List<Coordinator> createCoordinators(Coordinator... coordinator) {
234                 return Arrays.asList(coordinator);
235         }
236         
237         private void handleSpaceErrorAndTerminate(Exception e) {
238                 log.error(e.getMessage());
239                 e.printStackTrace();
240                 System.exit(1);
241         }
242         
243         
244         private <T extends Serializable> void sendItemsToContainer(List<T> items, ContainerReference cref) {
245                 
246                 try {
247                         List<Entry> entries = new ArrayList<>();
248                         for (Serializable item : items) {
249                                 entries.add(new Entry(item));
250                         }
251                         capi.write(entries, cref);
252                 } catch (Exception e) {
253                         log.info(e.getMessage());
254                         e.printStackTrace();
255                 }
256         }
257         
258         public void listenForFreeTable() {
259                 
260                 NotificationListener freeTableListener = new NotificationListener() {
261             @Override
262             public void entryOperationFinished(final Notification notification, final Operation operation, final List<? extends Serializable> entries) {
263                
264                                 log.info("{} tables have become free", entries.size());
265                                 
266                                 List<Table> tables = castEntries(entries);
267                                 Collections.shuffle(tables);
268                                 
269                                 for (Table table : tables) {
270                                         try {
271                                                 TransactionReference tx = capi.createTransaction(RequestTimeout.INFINITE, URI.create(Util.SERVER_ADDR));
272                                                 
273                                                 try {
274                                                         // Acquire a lock for the free table in the FreeTableContainer
275                                                         int id = table.getId();
276                                                         log.info("Try to find the table with id {}", id);
277                                                 
278                                                         Table lockedFreeTable = takeEntityByTemplateFromContainer(new Table(id), freeTablesContainer, tx, 1000, String.format("There was no free table found with id %d", id));
279                                                         
280                                                         log.info("Table with id {} was found", id);
281                                                         GroupData lockedGroup = takeEntityByTemplateFromContainer(new GroupData(), assignTableContainer, tx, 1000, "There is no group waiting for a table at the moment");
282                                         
283                                                         // The new group sits down at the table
284                                                         lockedFreeTable.setGroupId(lockedGroup.getId());
285                                                         lockedGroup.setTable(lockedFreeTable);
286                                                         
287                                                         // The new group now wants to order
288                                                         lockedGroup.setState(GroupState.ORDER_PENDING);
289                                                         
290                                                         sendItemsToContainer(Arrays.asList(lockedFreeTable), tablesContainer);
291                                                         sendItemsToContainer(Arrays.asList(lockedGroup), groupsContainer);
292                                                         sendItemsToContainer(Arrays.asList(lockedGroup), takeOrderContainer);
293                                                         
294                                                         log.info("Assigned Table to group with groupId {}", lockedGroup.getId());
295                                                         capi.commitTransaction(tx);
296                                                         
297                                                 } catch (IllegalArgumentException e) {
298                                                         log.error("SHOULD NEVER HAPPEN!");
299                                                         System.exit(1);
300                                                 }       catch (CountNotMetException e) {
301                                                         log.error("SHOULD NEVER HAPPEN!");
302                                                         System.exit(1);
303                                                         log.info(e.getMessage());
304                                                 } catch (EntityNotFoundByTemplate e) {
305                                                         // TODO check why another exception is thrown
306 //                                                      capi.rollbackTransaction(tx);
307                                                 } catch (Exception e) {
308                                                         log.error("SHOULD NEVER HAPPEN!");
309                                                         e.printStackTrace();
310                                                         log.info(e.getMessage());
311                                                         
312                                                         capi.rollbackTransaction(tx);
313                                                 }
314                                         } catch (Exception e) {
315                                                 log.error("SHOULD NEVER HAPPEN!");
316                                                 
317                                                 e.printStackTrace();
318                                         }
319                                         
320                                 }
321             }
322         };
323         try {
324                         notificationMgr.createNotification(freeTablesContainer, freeTableListener, Operation.WRITE);
325                         log.info("Created freeTablesContainer notification for a waiter");
326                 } catch (MzsCoreException e) {
327                         e.printStackTrace();
328                 } catch (InterruptedException e) {
329                         e.printStackTrace();
330                 }
331                 
332         }
333         
334
335
336         public void listenForNewGuests() {
337                 NotificationListener newGroupsListener = new NotificationListener() {
338             @Override
339             public void entryOperationFinished(final Notification notification, final Operation operation, final List<? extends Serializable> entries) {
340                
341                                 log.info("New guest groups have arrived");
342                                 
343                                 List<GroupData> groups = castEntries(entries);
344                                 Collections.shuffle(groups);
345                                 
346                                 for (GroupData group : groups) {
347                                         try {
348                                                 TransactionReference tx = capi.createTransaction(1500, URI.create(Util.SERVER_ADDR));
349                                                 
350                                                 try {
351                                                         // Acquire a lock for the group in the AssignTableContainer
352                                                         String groupNotFound = String.format("Group with id %d was already assigned a table by another waiter!", group.getId());
353                                                         GroupData lockedGroup = takeEntityByTemplateFromContainer(new GroupData(group.getId()), assignTableContainer, tx, 1000, groupNotFound);
354                                                         // Acquire a lock for one free table in the TablesContainer
355                                                         Table lockedFreeTable = takeEntityByTemplateFromContainer(new Table(), freeTablesContainer, tx, 1000, String.format("No free table for group with id %d could be found", group.getId()));
356                                                         
357                                                         // The new group sits down at the table
358                                                         lockedFreeTable.setGroupId(lockedGroup.getId());
359                                                         lockedGroup.setTable(lockedFreeTable);
360                                                         
361                                                         // The new group now wants to order
362                                                         lockedGroup.setState(GroupState.ORDER_PENDING);
363                                                         
364                                                         sendItemsToContainer(Arrays.asList(lockedFreeTable), tablesContainer);
365                                                         sendItemsToContainer(Arrays.asList(lockedGroup), groupsContainer);
366                                                         sendItemsToContainer(Arrays.asList(lockedGroup), takeOrderContainer);
367                                                         
368                                                         log.info("Assigned Table to group with groupId {}", lockedGroup.getId());
369                                                         capi.commitTransaction(tx);
370                                                         
371                                                 } catch (IllegalArgumentException e) {
372                                                         log.error("SHOULD NEVER HAPPEN!");
373                                                         System.exit(1);
374                                                 }       catch (CountNotMetException e) {
375                                                         log.error("SHOULD NEVER HAPPEN!");
376                                                         System.exit(1);
377                                                         log.info(e.getMessage());
378                                                 } catch (EntityNotFoundByTemplate e) {
379 //                                                      capi.rollbackTransaction(tx);
380                                                 } catch (Exception e) {
381                                                         log.error("SHOULD NEVER HAPPEN!");
382                                                         e.printStackTrace();
383                                                         log.info(e.getMessage());
384                                                         
385                                                         capi.rollbackTransaction(tx);
386                                                 }
387                                         } catch (Exception e) {
388                                                 log.error("SHOULD NEVER HAPPEN!");
389                                                 
390                                                 e.printStackTrace();
391                                         }
392                                         
393                                 }
394             }
395         };
396         try {
397                         notificationMgr.createNotification(assignTableContainer, newGroupsListener, Operation.WRITE);
398                         log.info("Created assingTableContainer notification for a waiter");
399                 } catch (MzsCoreException e) {
400                         e.printStackTrace();
401                 } catch (InterruptedException e) {
402                         e.printStackTrace();
403                 }
404         }
405         
406         private GroupData getGroupWaitingForTable(GroupData group,
407                         TransactionReference tx) throws MzsCoreException {
408
409
410             GroupData singleGroup = takeEntityByTemplateFromContainer(new GroupData(group.getId()), assignTableContainer, tx, 1000, String.format("Group with id %d was already assigned a table by another waiter!", group.getId()));
411                 
412                 
413                 return singleGroup;
414                 
415         }
416         
417         private Table getFreeTableForGroup(GroupData group,
418                         TransactionReference tx) throws MzsCoreException {
419                 
420                 return   takeEntityByTemplateFromContainer(new Table(), freeTablesContainer, tx, 1000, String.format("No free table for group with id %d could be found", group.getId()));
421         
422                 
423         }
424         
425         @SuppressWarnings("unchecked")
426         private <T extends Serializable> T takeEntityByTemplateFromContainer(T entity, ContainerReference ref, TransactionReference tx, long timeout, String errorMsg) throws MzsCoreException {
427                 try {
428                         LindaSelector sel = LindaCoordinator.newSelector(entity, 1);
429                         T singleEntity = null;
430                         
431                         ArrayList<Serializable> entities = capi.take(ref,  sel, RequestTimeout.DEFAULT, tx);
432                         log.info("Returned {} entities", entities.size());
433                         
434                         return (T) CapiUtil.getSingleEntry(entities);
435                 } catch (CountNotMetException e) {
436                         log.info(errorMsg);
437                         capi.rollbackTransaction(tx);
438                         
439                         throw new EntityNotFoundByTemplate(errorMsg);
440                 }
441         }
442         
443
444         
445         private <T extends Serializable> List<T> castEntries(List<? extends Serializable> entries) {
446                 List<T> newList = new ArrayList<T>();
447                 List<Entry> newEntries = (List<Entry>) entries;
448                 for (Entry entry : newEntries) {
449                         newList.add((T) entry.getValue());
450                 }
451                 return newList;
452         }
453         
454
455
456 }