1 package at.ac.tuwien.sbc.valesriegler.xvsm;
3 import java.io.Serializable;
5 import java.util.ArrayList;
6 import java.util.Arrays;
7 import java.util.Collections;
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;
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;
41 * Responsible for XVSM Communication
43 * @author Gregor Riegler <gregor DOT riegler AT gmail DOT com>
46 public class XVSMConnector {
47 private static final Logger log = LoggerFactory.getLogger(XVSMConnector.class);
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;
58 private NotificationManager notificationMgr;
62 public void initSpaceCommunication() {
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);
73 public void useTablesContainer() {
74 tablesContainer = useContainer(Util.TABLES_CONTAINER, createCoordinators(new AnyCoordinator(), new LindaCoordinator(false))) ;
77 public void useTakeOrderContainer() {
78 takeOrderContainer = useContainer(Util.TAKE_ORDER, createCoordinators(new AnyCoordinator(), new LindaCoordinator(false))) ;
81 public void useGroupsContainer() {
82 groupsContainer = useContainer(Util.GROUPS_CONTAINER, createCoordinators(new AnyCoordinator(), new LindaCoordinator(false))) ;
85 public void useAssignTableContainer() {
86 assignTableContainer = useContainer(Util.ASSIGN_TABLE, createCoordinators(new AnyCoordinator(), new LindaCoordinator(false))) ;
89 public void useFreeTablesContainer() {
90 freeTablesContainer = useContainer(Util.FREE_TABLES, createCoordinators(new AnyCoordinator(), new LindaCoordinator(false)));
95 private ContainerReference useContainer(String containerName, List<Coordinator> coordinators) {
97 return Util.getOrCreateNamedContainer(Util.SERVER_ADDR, containerName, capi, coordinators);
98 } catch (MzsCoreException e) {
99 handleSpaceErrorAndTerminate(e);
106 public void sendTablesToSpace(List<Table> tables) {
107 sendItemsToContainer(tables, tablesContainer);
110 public void sendFreeTablesToSpace(List<Table> tables) {
111 sendItemsToContainer(tables, freeTablesContainer);
112 sendTablesToSpace(tables);
116 public void sendGroupsToSpace(List<GroupData> newGroups) {
117 sendItemsToContainer(newGroups, groupsContainer);
120 public void handleWaitingGroup(int id) {
123 TransactionReference tx = capi.createTransaction(RequestTimeout.INFINITE, URI.create(Util.SERVER_ADDR));
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);
134 GroupData groupData = new GroupData(null);
135 groupData.setState(GroupState.WAITING);
136 LindaSelector sel = LindaCoordinator.newSelector(groupData, 1);
137 ArrayList<GroupData> waitingGroups = null;
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);
147 GroupData group = waitingGroups.get(0);
148 group.setTable(new Table(table.getGroupId()));
149 group.setTableWaiter(id);
150 group.setState(GroupState.SITTING);
153 capi.write(groupsContainer, RequestTimeout.TRY_ONCE, tx, new Entry(group));
154 } catch (Exception e) {
156 capi.rollbackTransaction(tx);
161 capi.write(new Entry(table), tablesContainer, RequestTimeout.TRY_ONCE, tx);
162 } catch (Exception e) {
164 capi.rollbackTransaction(tx);
168 capi.commitTransaction(tx);
169 } catch (MzsCoreException e) {
174 public void handleOrderRequest(int id) {
176 TransactionReference tx = capi.createTransaction(RequestTimeout.INFINITE, URI.create(Util.SERVER_ADDR));
178 GroupData groupData = new GroupData(null);
179 groupData.setState(GroupState.SITTING);
180 LindaSelector sel = LindaCoordinator.newSelector(groupData, 1);
181 ArrayList<GroupData> sittingGroups = null;
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);
190 GroupData sittingGroup = sittingGroups.get(0);
191 Order order = sittingGroup.getOrder();
192 sittingGroup.setOrderWaiter(id);
193 sittingGroup.setState(GroupState.ORDERED);
196 capi.write(new Entry(sittingGroup), groupsContainer, RequestTimeout.TRY_ONCE, tx);
197 } catch (Exception e) {
199 capi.rollbackTransaction(tx);
203 capi.commitTransaction(tx);
205 } catch (MzsCoreException e) {
210 public void initTablesNotifications(NotificationListener listener) {
212 notificationMgr.createNotification(tablesContainer, listener, Operation.WRITE);
213 } catch (Exception e) {
214 handleSpaceErrorAndTerminate(e);
218 public void initGroupNotifications(NotificationListener listener) {
220 notificationMgr.createNotification(groupsContainer, listener, Operation.WRITE);
221 } catch (Exception e) {
222 handleSpaceErrorAndTerminate(e);
226 public void handlePaymentRequest() {
229 public void handlePizzaDistribution() {
233 private List<Coordinator> createCoordinators(Coordinator... coordinator) {
234 return Arrays.asList(coordinator);
237 private void handleSpaceErrorAndTerminate(Exception e) {
238 log.error(e.getMessage());
244 private <T extends Serializable> void sendItemsToContainer(List<T> items, ContainerReference cref) {
247 List<Entry> entries = new ArrayList<>();
248 for (Serializable item : items) {
249 entries.add(new Entry(item));
251 capi.write(entries, cref);
252 } catch (Exception e) {
253 log.info(e.getMessage());
258 public void listenForFreeTable() {
260 NotificationListener freeTableListener = new NotificationListener() {
262 public void entryOperationFinished(final Notification notification, final Operation operation, final List<? extends Serializable> entries) {
264 log.info("{} tables have become free", entries.size());
266 List<Table> tables = castEntries(entries);
267 Collections.shuffle(tables);
269 for (Table table : tables) {
271 TransactionReference tx = capi.createTransaction(RequestTimeout.INFINITE, URI.create(Util.SERVER_ADDR));
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);
278 Table lockedFreeTable = takeEntityByTemplateFromContainer(new Table(id), freeTablesContainer, tx, 1000, String.format("There was no free table found with id %d", id));
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");
283 // The new group sits down at the table
284 lockedFreeTable.setGroupId(lockedGroup.getId());
285 lockedGroup.setTable(lockedFreeTable);
287 // The new group now wants to order
288 lockedGroup.setState(GroupState.ORDER_PENDING);
290 sendItemsToContainer(Arrays.asList(lockedFreeTable), tablesContainer);
291 sendItemsToContainer(Arrays.asList(lockedGroup), groupsContainer);
292 sendItemsToContainer(Arrays.asList(lockedGroup), takeOrderContainer);
294 log.info("Assigned Table to group with groupId {}", lockedGroup.getId());
295 capi.commitTransaction(tx);
297 } catch (IllegalArgumentException e) {
298 log.error("SHOULD NEVER HAPPEN!");
300 } catch (CountNotMetException e) {
301 log.error("SHOULD NEVER HAPPEN!");
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!");
310 log.info(e.getMessage());
312 capi.rollbackTransaction(tx);
314 } catch (Exception e) {
315 log.error("SHOULD NEVER HAPPEN!");
324 notificationMgr.createNotification(freeTablesContainer, freeTableListener, Operation.WRITE);
325 log.info("Created freeTablesContainer notification for a waiter");
326 } catch (MzsCoreException e) {
328 } catch (InterruptedException e) {
336 public void listenForNewGuests() {
337 NotificationListener newGroupsListener = new NotificationListener() {
339 public void entryOperationFinished(final Notification notification, final Operation operation, final List<? extends Serializable> entries) {
341 log.info("New guest groups have arrived");
343 List<GroupData> groups = castEntries(entries);
344 Collections.shuffle(groups);
346 for (GroupData group : groups) {
348 TransactionReference tx = capi.createTransaction(1500, URI.create(Util.SERVER_ADDR));
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()));
357 // The new group sits down at the table
358 lockedFreeTable.setGroupId(lockedGroup.getId());
359 lockedGroup.setTable(lockedFreeTable);
361 // The new group now wants to order
362 lockedGroup.setState(GroupState.ORDER_PENDING);
364 sendItemsToContainer(Arrays.asList(lockedFreeTable), tablesContainer);
365 sendItemsToContainer(Arrays.asList(lockedGroup), groupsContainer);
366 sendItemsToContainer(Arrays.asList(lockedGroup), takeOrderContainer);
368 log.info("Assigned Table to group with groupId {}", lockedGroup.getId());
369 capi.commitTransaction(tx);
371 } catch (IllegalArgumentException e) {
372 log.error("SHOULD NEVER HAPPEN!");
374 } catch (CountNotMetException e) {
375 log.error("SHOULD NEVER HAPPEN!");
377 log.info(e.getMessage());
378 } catch (EntityNotFoundByTemplate e) {
379 // capi.rollbackTransaction(tx);
380 } catch (Exception e) {
381 log.error("SHOULD NEVER HAPPEN!");
383 log.info(e.getMessage());
385 capi.rollbackTransaction(tx);
387 } catch (Exception e) {
388 log.error("SHOULD NEVER HAPPEN!");
397 notificationMgr.createNotification(assignTableContainer, newGroupsListener, Operation.WRITE);
398 log.info("Created assingTableContainer notification for a waiter");
399 } catch (MzsCoreException e) {
401 } catch (InterruptedException e) {
406 private GroupData getGroupWaitingForTable(GroupData group,
407 TransactionReference tx) throws MzsCoreException {
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()));
417 private Table getFreeTableForGroup(GroupData group,
418 TransactionReference tx) throws MzsCoreException {
420 return takeEntityByTemplateFromContainer(new Table(), freeTablesContainer, tx, 1000, String.format("No free table for group with id %d could be found", group.getId()));
425 @SuppressWarnings("unchecked")
426 private <T extends Serializable> T takeEntityByTemplateFromContainer(T entity, ContainerReference ref, TransactionReference tx, long timeout, String errorMsg) throws MzsCoreException {
428 LindaSelector sel = LindaCoordinator.newSelector(entity, 1);
429 T singleEntity = null;
431 ArrayList<Serializable> entities = capi.take(ref, sel, RequestTimeout.DEFAULT, tx);
432 log.info("Returned {} entities", entities.size());
434 return (T) CapiUtil.getSingleEntry(entities);
435 } catch (CountNotMetException e) {
437 capi.rollbackTransaction(tx);
439 throw new EntityNotFoundByTemplate(errorMsg);
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());