]> git.somenet.org - pub/jan/sbc.git/blob - src/main/java/at/ac/tuwien/sbc/valesriegler/xvsm/CookXVSM.java
[XVSM] Some fixes for making sure that Cook only prepares normal pizzas when there...
[pub/jan/sbc.git] / src / main / java / at / ac / tuwien / sbc / valesriegler / xvsm / CookXVSM.java
1 package at.ac.tuwien.sbc.valesriegler.xvsm;
2
3 import at.ac.tuwien.sbc.valesriegler.common.Util;
4 import at.ac.tuwien.sbc.valesriegler.types.*;
5 import at.ac.tuwien.sbc.valesriegler.xvsm.spacehelpers.SpaceAction;
6 import org.mozartspaces.capi3.EntryLockedException;
7 import org.mozartspaces.core.MzsConstants;
8 import org.mozartspaces.core.MzsConstants.RequestTimeout;
9 import org.mozartspaces.core.MzsCoreException;
10 import org.mozartspaces.core.RequestContext;
11 import org.mozartspaces.core.TransactionReference;
12 import org.slf4j.Logger;
13 import org.slf4j.LoggerFactory;
14
15 import java.io.Serializable;
16 import java.net.URI;
17 import java.util.Arrays;
18 import java.util.Collections;
19 import java.util.List;
20
21 public class CookXVSM extends AbstractXVSMConnector {
22     private static final Logger log = LoggerFactory.getLogger(CookXVSM.class);
23
24     private int cookId;
25     public CookXVSM(int id, int port) {
26         super(port);
27
28         this.cookId = id;
29         orderTakenContainer = useContainer(Util.ORDER_TAKEN);
30         deliveryOrderTakenContainer = useContainer(Util.DELIVERY_ORDER_TAKEN);
31         preparedPizzasContainer = useContainer(Util.DELIVER_PIZZAS);
32         preparePizzasContainer = useContainer(Util.PREPARE_PIZZAS);
33         prepareDeliveryPizzasContainer = useContainer(Util.PREPARE_DELIVERY_PIZZAS);
34         pizzaInProgressContainer = useContainer(Util.PIZZAS_IN_PROGRESS);
35         preparedDeliveryPizzasContainer = useContainer(Util.DELIVER_DELIVERY_PIZZAS);
36         pizzeriaGroupContainer = useContainer(Util.PIZZERIA_GROUP);
37         pizzeriaDeliveryContainer = useContainer(Util.PIZZERIA_DELIVERY);
38     }
39
40     public void listenForPizzas() {
41        getDefaultBuilder("listenForNormalPizzas").setLookaround(true).setCref(preparePizzasContainer).setTimeout(15000).setSpaceAction(new SpaceAction() {
42
43            @Override
44            public void onEntriesWritten(List<? extends Serializable> entries)
45                    throws Exception {
46
47                List<PizzaOrder> pizzas = castEntries(entries);
48
49                sortOrShufflePizzas(pizzas, inNotification.get());
50
51                for (PizzaOrder pizzaOrder : pizzas) {
52
53                    TransactionReference tx = capi.createTransaction(9000, URI.create(String.format(Util.SERVER_ADDR, port)));
54                    String pizzaAlreadyCooked = String.format("Normal pizza with id %d has already been cooked by another cook", pizzaOrder.getId());
55
56                    try {
57                        if (!mayPrepareCustomerPizza(pizzaOrder, tx)) {
58                            capi.rollbackTransaction(tx);
59                            continue;
60                        }
61
62                        // Require the lock for preparing the pizza
63                        PizzaOrder order = takeMatchingEntity(new PizzaOrder(pizzaOrder.getId()), preparePizzasContainer, tx, RequestTimeout.ZERO, pizzaAlreadyCooked);
64
65                        // tell the space that you prepare the pizza -> without a transaction!!
66                        Pizza pizzaInProgress = Pizza.createPizzaFromPizzaOrder(order, cookId, true);
67                        pizzaInProgress.setStatus(PizzaOrderStatus.IN_PREPARATION);
68
69                        notifyCustomerPizzaInProgress(order, pizzaInProgress);
70
71                        PizzaOrder pizza = createPizza(order);
72
73                        notifyCustomerPizzaDone(pizza, tx);
74                        capi.commitTransaction(tx);
75                        log.debug("I have completed preparing a pizza for order {}!", pizza.getOrderId());
76                    } catch (NullPointerException e) {
77                        // the strange nullpointer exception from the space
78                    } catch (EntityNotFoundByTemplate e) {
79                        log.info("entitynotfound: {}", e.getMessage());
80                    } catch (EntryLockedException e) {
81                        capi.rollbackTransaction(tx);
82                    } catch (Exception e) {
83                        log.error("outer cook");
84                        log.error(e.getMessage());
85                    }
86
87                }
88            }
89        }).createSpaceListenerImpl();
90
91     }
92
93     private void sortOrShufflePizzas(List<PizzaOrder> pizzas, boolean notification) {
94         if (notification) Collections.shuffle(pizzas);
95         else {
96             Collections.sort(pizzas);
97         }
98     }
99
100     public void listenForDeliveryPizzas() {
101         getDefaultBuilder("listenForDeliveryPizzas").setLookaround(true).setCref(prepareDeliveryPizzasContainer).setTimeout(15000).setSpaceAction(new SpaceAction() {
102
103             @Override
104             public void onEntriesWritten(List<? extends Serializable> entries)
105                     throws Exception {
106
107                 List<PizzaOrder> pizzas = castEntries(entries);
108
109                 sortOrShufflePizzas(pizzas, inNotification.get());
110
111                 for (PizzaOrder pizzaOrder : pizzas) {
112
113                     final RequestContext requestContext = new RequestContext();
114                     TransactionReference tx = capi.createTransaction(12000, URI.create(String.format(Util.SERVER_ADDR, port)));
115                     String pizzaAlreadyCooked = String.format("Delivery Pizza with id %d has already been cooked by another cook", pizzaOrder.getId());
116
117                     try {
118                         if (!mayPrepareDeliveryPizza(tx, pizzaOrder)) {
119                             capi.rollbackTransaction(tx);
120                             continue;
121                         }
122
123                         // Require the lock for preparing the pizza
124                         PizzaOrder order = takeMatchingEntity(new PizzaOrder(pizzaOrder.getId()), prepareDeliveryPizzasContainer, tx, RequestTimeout.ZERO, pizzaAlreadyCooked);
125
126                         // tell the space that you prepare the pizza -> without a transaction!!
127                         Pizza pizzaInProgress = Pizza.createPizzaFromPizzaOrder(order, cookId, true);
128                         pizzaInProgress.setStatus(PizzaOrderStatus.IN_PREPARATION);
129
130                         notifyDeliveryPizzaInProgress(order, pizzaInProgress);
131
132                         log.debug("before creating!");
133
134                         PizzaOrder pizza = createPizza(order);
135
136                         log.debug("after creating!");
137
138
139                         log.debug("after prepareddeliverypizzascon");
140
141                         notifyDeliveryPizzaDone(pizza, tx);
142
143                         log.debug("after notifydone");
144
145                         capi.commitTransaction(tx);
146                         log.debug("I have completed preparing a delivery pizza for order {}!", pizza.getOrderId());
147                     } catch (NullPointerException e) {
148                         // the strange nullpointer exception from the space
149                     } catch (EntityNotFoundByTemplate e) {
150                         log.info("entitynotfound: {}", e.getMessage());
151                     } catch (EntryLockedException e) {
152                         capi.rollbackTransaction(tx);
153                     } catch (Exception e) {
154                         log.error("outer cook");
155                         log.error(e.getMessage());
156                     }
157
158                 }
159             }
160         }).createSpaceListenerImpl();
161
162     }
163
164     /**
165      * A cook may prepare a pizza if there is no current delivery order or if at least a pizza of the same order is
166      * in preparation or has been done!
167      */
168     private boolean mayPrepareCustomerPizza(PizzaOrder pizzaOrder, TransactionReference tx) throws MzsCoreException {
169         boolean mayPrepare = false;
170
171         List<PizzaOrder> deliveryPizzas = readMatchingEntities(new PizzaOrder(), prepareDeliveryPizzasContainer, tx, RequestTimeout.DEFAULT, "mayPrepareCustomerPizza: Cannot access prepareDeliveryPizzasContainer", MzsConstants.Selecting.COUNT_MAX);
172         if (!deliveryPizzas.isEmpty()) {
173             Pizza pizza = new Pizza();
174             pizza.setIdOfOrder(pizzaOrder.getOrderId());
175             final List<Pizza> pizzasAlreadyDone = readMatchingEntities(pizza, preparedPizzasContainer, tx, RequestTimeout.DEFAULT, "mayPrepareCustomerPizza: Cannot access preparedPizzasContainer", MzsConstants.Selecting.COUNT_MAX);
176             if(! pizzasAlreadyDone.isEmpty()) mayPrepare = true;
177             else {
178                 final List<Pizza> pizzasOfOrderInProgress = readMatchingEntities(pizza, pizzaInProgressContainer, tx, RequestTimeout.DEFAULT, "mayPrepareCustomerPizza: Cannot access pizzaInProgressContainer", MzsConstants.Selecting.COUNT_MAX);
179                 if (! pizzasOfOrderInProgress.isEmpty()) mayPrepare = true;
180                 else mayPrepare = false;
181             }
182         }
183         else mayPrepare = true;
184         log.warn("Cook may prepare Customer pizza: {} for order {}", mayPrepare, pizzaOrder.getOrderId());
185         return mayPrepare;
186     }
187
188
189     /**
190      * A cook may prepare a delivery pizza if no customer group order is open
191      */
192     private boolean mayPrepareDeliveryPizza(TransactionReference tx, PizzaOrder pizzaOrder) throws MzsCoreException {
193         boolean mayPrepare = false;
194
195         Pizza pizza = new Pizza();
196         pizza.setDeliveryPizza(false);
197         final List<Pizza> preparedNonDeliveryPizzas  = readMatchingEntities(pizza, preparedPizzasContainer, tx, RequestTimeout.DEFAULT, "mayPrepareDeliveryPizza: cannot access preparedPizzasContainer", MzsConstants.Selecting.COUNT_MAX);
198         if(! preparedNonDeliveryPizzas.isEmpty()) {
199             log.warn("PreparedNonDeliveryPizzas NOT empty!");
200            mayPrepare = false;
201         }
202         else {
203             final List<Pizza> nonDeliveryPizzasInProgress = readMatchingEntities(pizza, pizzaInProgressContainer, tx, RequestTimeout.DEFAULT, "mayPrepareDeliveryPizza: cannot access pizzaInProgressContainer", MzsConstants.Selecting.COUNT_MAX);
204             if (! nonDeliveryPizzasInProgress.isEmpty()) mayPrepare = false;
205             else mayPrepare = true;
206         }
207         log.warn("Cook may prepare Delivery pizza: {} for order {}", mayPrepare, pizzaOrder.getOrderId());
208         return mayPrepare;
209     }
210
211     private void notifyCustomerPizzaDone(PizzaOrder pizza, TransactionReference tx) throws MzsCoreException {
212         sendItemsToContainer(Arrays.asList(pizza), preparedPizzasContainer, RequestTimeout.DEFAULT, tx);
213         final GroupData group = new GroupData();
214         final Order groupOrder = new Order();
215         groupOrder.setId(pizza.getOrderId());
216         group.setOrder(groupOrder);
217         group.setState(GroupState.ORDERED);
218         GroupData groupData = takeMatchingEntity(group, pizzeriaGroupContainer, tx, RequestTimeout.INFINITE, "Cannot take the group from pizzeriaGroupContainer");
219         final List<PizzaOrder> orderedPizzas = groupData.getOrder().getOrderedPizzas();
220         for (PizzaOrder orderedPizza : orderedPizzas) {
221             if (orderedPizza.getId() == pizza.getId()) {
222                 orderedPizza.setStatus(PizzaOrderStatus.DONE);
223                 orderedPizza.setCookId(pizza.getCookId());
224             }
225         }
226         sendItemsToContainer(Arrays.asList(groupData), pizzeriaGroupContainer, RequestTimeout.DEFAULT, tx);
227     }
228
229     private void notifyDeliveryPizzaDone(PizzaOrder pizza, TransactionReference tx) throws MzsCoreException {
230         sendItemsToContainer(Arrays.asList(pizza), preparedDeliveryPizzasContainer, RequestTimeout.DEFAULT, tx);
231         final DeliveryGroupData group = new DeliveryGroupData();
232         final Order groupOrder = new Order();
233         groupOrder.setId(pizza.getOrderId());
234         group.setOrder(groupOrder);
235         group.setDeliveryStatus(null);
236         DeliveryGroupData groupData = takeMatchingEntity(group, pizzeriaDeliveryContainer, tx, RequestTimeout.INFINITE, "Cannot take the delivery order from pizzeriaDeliveryContainer");
237         final List<PizzaOrder> orderedPizzas = groupData.getOrder().getOrderedPizzas();
238         for (PizzaOrder orderedPizza : orderedPizzas) {
239             if (orderedPizza.getId() == pizza.getId()) {
240                 orderedPizza.setStatus(PizzaOrderStatus.DONE);
241                 orderedPizza.setCookId(pizza.getCookId());
242             }
243         }
244         sendItemsToContainer(Arrays.asList(groupData), pizzeriaDeliveryContainer, RequestTimeout.DEFAULT, tx);
245     }
246
247     private void notifyDeliveryPizzaInProgress(PizzaOrder order, Pizza pizzaInProgress) throws MzsCoreException {
248         try {
249             log.info("I say that I now prepare a delivery pizza for order {}", pizzaInProgress.getOrderId());
250             final DeliveryGroupData groupTemplate = new DeliveryGroupData();
251             final Order groupOrder = new Order();
252             groupOrder.setId(order.getOrderId());
253             groupTemplate.setOrder(groupOrder);
254             groupTemplate.setDeliveryStatus(null);
255             final TransactionReference inPreparationTx = getDefaultTransaction();
256             final DeliveryGroupData groupFromSpace = takeMatchingEntity(groupTemplate, pizzeriaDeliveryContainer, inPreparationTx, RequestTimeout.DEFAULT, "Cannot take the delivery order from pizzeriaDeliveryContainer");
257             final List<PizzaOrder> orderedPizzas = groupFromSpace.getOrder().getOrderedPizzas();
258             for (PizzaOrder orderedPizza : orderedPizzas) {
259                 if (orderedPizza.getId() == pizzaInProgress.getId()) {
260                     orderedPizza.setStatus(PizzaOrderStatus.IN_PREPARATION);
261                     orderedPizza.setCookId(pizzaInProgress.getCookId());
262                 }
263             }
264             sendItemsToContainer(Arrays.asList(groupFromSpace), pizzeriaDeliveryContainer, RequestTimeout.DEFAULT, inPreparationTx);
265             sendItemsToContainer(Arrays.asList(pizzaInProgress), pizzaInProgressContainer, RequestTimeout.DEFAULT, inPreparationTx);
266             log.debug("before inprogress comit!");
267             capi.commitTransaction(inPreparationTx);
268         }  catch(NullPointerException e) {
269         } catch (Exception e) {
270             log.error("notifyDeliveryPizzaInProgress: {}", e.getMessage());
271             e.printStackTrace();
272         }
273     }
274
275     private void notifyCustomerPizzaInProgress(PizzaOrder order, Pizza pizzaInProgress) {
276         try {
277             log.info("I say that I now prepare a pizza for order {}", pizzaInProgress.getOrderId());
278             final GroupData groupTemplate = new GroupData();
279             final Order groupOrder = new Order();
280             groupOrder.setId(order.getOrderId());
281             groupTemplate.setOrder(groupOrder);
282             groupTemplate.setState(null);
283             final TransactionReference inPreparationTx = getDefaultTransaction();
284             final GroupData groupFromSpace = takeMatchingEntity(groupTemplate, pizzeriaGroupContainer, inPreparationTx, 100, "Cannot take the order from pizzeriaGroupContainer");
285             final List<PizzaOrder> orderedPizzas = groupFromSpace.getOrder().getOrderedPizzas();
286             for (PizzaOrder orderedPizza : orderedPizzas) {
287                 if (orderedPizza.getId() == pizzaInProgress.getId()) {
288                     orderedPizza.setStatus(PizzaOrderStatus.IN_PREPARATION);
289                     orderedPizza.setCookId(pizzaInProgress.getCookId());
290                 }
291             }
292             sendItemsToContainer(Arrays.asList(groupFromSpace), pizzeriaGroupContainer, RequestTimeout.ZERO, inPreparationTx);
293             sendItemsToContainer(Arrays.asList(pizzaInProgress), pizzaInProgressContainer, RequestTimeout.ZERO, inPreparationTx);
294             capi.commitTransaction(inPreparationTx);
295         }  catch(NullPointerException e) {
296         } catch (Exception e) {
297             log.error("notifyCustomerPizzaInProgress: {}", e.getMessage());
298             e.printStackTrace();
299         }
300     }
301
302     private PizzaOrder createPizza(PizzaOrder order) throws InterruptedException {
303         long duration = order.getPizzaType().duration;
304         if (! Util.runSimulation) {
305             Thread.sleep(duration * 1000);
306         }
307
308         PizzaOrder pizza = Pizza.createPizzaFromPizzaOrder(order, cookId, false);
309         pizza.setStatus(PizzaOrderStatus.DONE);
310         return pizza;
311     }
312
313 }