1 package at.ac.tuwien.sbc.valesriegler.xvsm;
3 import java.io.Serializable;
5 import java.util.Arrays;
6 import java.util.Collections;
7 import java.util.Iterator;
10 import org.mozartspaces.capi3.AnyCoordinator;
11 import org.mozartspaces.core.ContainerReference;
12 import org.mozartspaces.core.MzsConstants;
13 import org.mozartspaces.core.MzsConstants.RequestTimeout;
14 import org.mozartspaces.core.MzsCoreException;
15 import org.mozartspaces.core.TransactionException;
16 import org.mozartspaces.core.TransactionReference;
17 import org.mozartspaces.notifications.Notification;
18 import org.mozartspaces.notifications.NotificationListener;
19 import org.mozartspaces.notifications.Operation;
20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory;
23 import at.ac.tuwien.sbc.valesriegler.common.Util;
24 import at.ac.tuwien.sbc.valesriegler.types.GroupData;
25 import at.ac.tuwien.sbc.valesriegler.types.GroupState;
26 import at.ac.tuwien.sbc.valesriegler.types.Order;
27 import at.ac.tuwien.sbc.valesriegler.types.OrderStatus;
28 import at.ac.tuwien.sbc.valesriegler.types.Pizza;
29 import at.ac.tuwien.sbc.valesriegler.types.Table;
31 public class WaiterXVSM extends AbstractXVSMConnector {
32 private static final Logger log = LoggerFactory.getLogger(WaiterXVSM.class);
33 private final int waiterId;
35 public WaiterXVSM(int waiterId) {
38 this.waiterId = waiterId;
40 freeTablesContainer = useContainer(Util.FREE_TABLES);
41 assignTableContainer = useContainer(Util.ASSIGN_TABLE);
42 takeOrderContainer = useContainer(Util.TAKE_ORDER);
43 orderTakenContainer = useContainer(Util.ORDER_TAKEN);
44 preparePizzasContainer = useContainer(Util.PREPARE_PIZZAS);
45 orderCompleteContainer = useContainer(Util.ORDER_COMPLETE);
46 deliverPizzasContainer = useContainer(Util.DELIVER_PIZZAS);
47 paymentRequestContainer = useContainer(Util.PAYMENT_REQUEST);
48 paymentDoneContainer = useContainer(Util.PAYMENT_DONE);
49 tableAssignedContainer = useContainer(Util.TABLE_ASSIGNED);
52 public void listenForFreeTable() {
53 SpaceListener listener = new SpaceListenerImpl(capi, freeTablesContainer) {
56 void onEntriesWritten(List<? extends Serializable> entries) throws Exception {
58 // log.info("{} tables have become free", entries.size());
60 List<Table> tables = castEntries(entries);
61 Collections.rotate(tables, waiterId);
63 for (Table table : tables) {
65 TransactionReference tx = capi.createTransaction(
66 Util.SPACE_TRANSACTION_TIMEOUT,
67 URI.create(Util.SERVER_ADDR));
69 // Acquire a lock for the free table in the
71 int id = table.getId();
73 Table tableTemplate = new Table(id);
74 Table lockedFreeTable = takeMatchingEntity(tableTemplate,
75 freeTablesContainer, tx, RequestTimeout.DEFAULT,
76 String.format("There was no free table found with id %d", id));
79 GroupData groupTemplate = new GroupData();
80 GroupData lockedGroup = takeMatchingEntity(groupTemplate,
81 assignTableContainer, tx, RequestTimeout.DEFAULT,
82 "There is no group waiting for a table at the moment");
84 assignGroupToTable(lockedGroup, lockedFreeTable, tx);
89 createNotification(listener, freeTablesContainer);
94 public void listenForNewGuests() {
95 SpaceListener listener = new SpaceListenerImpl(capi, assignTableContainer) {
98 void onEntriesWritten(List<? extends Serializable> entries)
100 log.info("New guest groups have arrived");
102 List<GroupData> groups = castEntries(entries);
103 Collections.rotate(groups, waiterId);
105 for (GroupData group : groups) {
107 TransactionReference tx = capi.createTransaction(
108 Util.SPACE_TRANSACTION_TIMEOUT,
109 URI.create(Util.SERVER_ADDR));
111 // Acquire a lock for the group in the
112 // AssignTableContainer
113 String groupNotFound = String.format("Group with id %d was already assigned a table by another waiter!", group.getId());
115 GroupData lockedGroup = takeMatchingEntity(
116 new GroupData(group.getId()),
117 assignTableContainer, tx,
118 RequestTimeout.DEFAULT, groupNotFound);
119 // Acquire a lock for one free table in the
121 String noFreeTable = String.format("No free table for group with id %d could be found", group.getId());
122 Table lockedFreeTable = takeMatchingEntity(new Table(null), freeTablesContainer, tx, RequestTimeout.DEFAULT,
125 assignGroupToTable(lockedGroup, lockedFreeTable, tx);
130 createNotification(listener, assignTableContainer);
133 public void listenForPaymentRequest() {
134 SpaceListener paymentListener = new SpaceListenerImpl(capi, paymentRequestContainer) {
137 void onEntriesWritten(List<? extends Serializable> entries)
140 List<GroupData> groups = castEntries(entries);
142 for (GroupData groupData : groups) {
143 TransactionReference tx = capi.createTransaction(
144 Util.SPACE_TRANSACTION_TIMEOUT,
145 URI.create(Util.SERVER_ADDR));
146 GroupData entity = new GroupData(groupData.getId());
148 // Acquire the lock so that another waiter can't do the same
150 String paymentRequestTakenByOtherWaiter = String.format(
151 "The payment request for group %d was already taken by an other waiter!",
153 takeMatchingEntity(entity, paymentRequestContainer, tx, RequestTimeout.DEFAULT, paymentRequestTakenByOtherWaiter);
155 groupData.setPayingWaiter(waiterId);
157 sendItemsToContainer(Arrays.asList(groupData), paymentDoneContainer, RequestTimeout.ZERO, tx);
159 capi.commitTransaction(tx);
164 createNotification(paymentListener, paymentRequestContainer);
167 public void listenForOrderRequests() {
168 SpaceListener ordersListener = new SpaceListenerImpl(capi, takeOrderContainer) {
171 void onEntriesWritten(List<? extends Serializable> entries)
174 List<GroupData> groups = castEntries(entries);
176 for (GroupData groupData : groups) {
178 TransactionReference tx = capi.createTransaction(
179 Util.SPACE_TRANSACTION_TIMEOUT,
180 URI.create(Util.SERVER_ADDR));
181 GroupData entity = new GroupData(groupData.getId());
182 entity.setState(GroupState.SITTING);
184 // Acquire the lock so that another waiter can't do the same thing!
185 String orderTakenByOtherWaiter = String.format(
186 "The order for group %d was already taken by an other waiter!",
188 takeMatchingEntity(entity, takeOrderContainer, tx, RequestTimeout.DEFAULT, orderTakenByOtherWaiter);
190 groupData.setOrderWaiter(waiterId);
191 groupData.setState(GroupState.ORDERED);
192 Order order = groupData.getOrder();
193 order.setStatus(OrderStatus.ORDERED);
195 sendItemsToContainer(Arrays.asList(groupData),
196 orderTakenContainer, RequestTimeout.ZERO, tx);
197 sendItemsToContainer(order.getOrderedPizzas(),
198 preparePizzasContainer, RequestTimeout.ZERO, tx);
199 capi.commitTransaction(tx);
201 log.info("Waiter has taken order from group {}",
207 createNotification(ordersListener, takeOrderContainer);
210 public void listenForPreparedPizzas() {
212 * A waiter gets informed when a new pizza is complete. He takes the
213 * orderId of the pizza and looks up the corresponding order from which
214 * he gets the number of necessary pizzas of the order. He then tries to
215 * fetch all pizzas with the corresponding orderId and compares the
216 * number of those pizzas with the number of necessary pizzas. If all
217 * pizzas of an order are complete he then delivers them!
219 SpaceListener preparedPizzasListener = new SpaceListenerImpl(capi, deliverPizzasContainer) {
222 void onEntriesWritten(List<? extends Serializable> entries)
225 List<Pizza> pizzas = castEntries(entries);
227 for (Pizza pizza : pizzas) {
228 int orderId = pizza.getOrderId();
230 TransactionReference tx = capi.createTransaction(
231 Util.SPACE_TRANSACTION_TIMEOUT,
232 URI.create(Util.SERVER_ADDR));
235 GroupData entity = new GroupData();
236 entity.setState(null);
237 Order order = new Order();
238 order.setId(orderId);
239 entity.setOrder(order);
241 GroupData groupData = takeMatchingEntity(entity,
242 orderTakenContainer, tx, RequestTimeout.DEFAULT,
243 "Another waiter just checks if the order is complete");
244 int groupId = groupData.getId();
245 int numberOfPizzas = groupData.getOrder().getNumberOfPizzas();
247 Pizza pizzaTemplate = new Pizza();
248 pizzaTemplate.setOrderId(orderId);
250 List<Pizza> pizzasOfOrder = takeMatchingEntities(
251 pizzaTemplate, deliverPizzasContainer, tx,
252 RequestTimeout.DEFAULT,
253 "Cannot take the pizzas from the deliverPizzasContainer");
255 // for an unkown reason even pizzas not matching the orderid
256 // are returned. that's why we have to check again if the
257 // pizza really belongs to the order in question
258 Iterator<Pizza> it = pizzasOfOrder.iterator();
259 while (it.hasNext()) {
260 Pizza nextPizza = it.next();
261 if (nextPizza.getOrderId() != orderId) {
267 if (pizzasOfOrder.size() == numberOfPizzas) {
268 GroupData group = new GroupData();
269 group.setServingWaiter(waiterId);
270 Order completeOrder = new Order();
271 completeOrder.setId(orderId);
272 completeOrder.setGroupId(groupId);
273 group.setOrder(completeOrder);
274 sendItemsToContainer(Arrays.asList(group),
275 orderCompleteContainer, RequestTimeout.DEFAULT,
277 capi.commitTransaction(tx);
279 log.info("Not yet all pizzas prepared! Order with id "
280 + orderId + " has " + numberOfPizzas
281 + " pizzas, but only " + pizzasOfOrder.size()
282 + " pizzas are ready by now!");
283 capi.rollbackTransaction(tx);
285 } catch (NullPointerException e) {
287 } catch (Exception e) {
288 capi.rollbackTransaction(tx);
294 createNotification(preparedPizzasListener, deliverPizzasContainer);
297 private void assignGroupToTable(GroupData lockedGroup,
298 Table lockedFreeTable, TransactionReference tx)
299 throws MzsCoreException {
300 // The new group sits down at the table
301 lockedFreeTable.setGroupId(lockedGroup.getId());
303 // The new group now wants to order
304 lockedGroup.setState(GroupState.SITTING);
305 lockedGroup.setTable(lockedFreeTable);
306 lockedGroup.setTableWaiter(waiterId);
308 sendItemsToContainer(Arrays.asList(lockedFreeTable),
309 tableAssignedContainer, RequestTimeout.ZERO, tx);
310 sendItemsToContainer(Arrays.asList(lockedGroup), takeOrderContainer,
311 RequestTimeout.ZERO, tx);
314 capi.commitTransaction(tx);
315 log.info("Assigned table to group with groupId {}",
316 lockedGroup.getId());
317 } catch (Exception e) {
318 log.info("Assigning a table to group with groupId {} failed",
319 lockedGroup.getId());