package actions; import java.util.Date; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import javax.persistence.EntityManager; import javax.persistence.EntityTransaction; import javax.persistence.NoResultException; import javax.persistence.Query; import controllers.routes; import models.Product; import play.Logger; import play.libs.F; import play.libs.F.Promise; import play.mvc.Action; import play.mvc.Http.Context; import play.mvc.Result; import play.mvc.Results; import services.ProductService; import services.ServicesInstances; import tools.converters.FromStringConverter; import play.db.jpa.JPA; import play.db.jpa.Transactional; /** * Action which checks if a product is out-of-stock. If it's the case, it returns appropriated view. It's invoked when user * tries to add a product to his shopping cart. * * @author bartosz * */ public class OutOfStockAction extends Action<OutOfStockAction> { @Override public Promise<Result> call(Context ctx) throws Throwable { Logger.debug("Invoking OutOfStock before adding a product to the shopping cart"); String[] parts = Context.current().request().path().split("/"); final int productId = FromStringConverter.toInt(parts[parts.length-1]); try { // We can't use service even with @Transactional annotation; an exception "no EntityManager is bound" // is thrown every time. JPA.withTransaction is possible workaround. Boolean inStock = JPA.withTransaction(new F.Function0<Boolean>() { @Override public Boolean apply() throws Throwable { Query inStockQuery = JPA.em().createQuery("SELECT p FROM Product p WHERE p.id = :productId AND p.inStock = :inStock"); inStockQuery.setParameter("productId", productId); inStockQuery.setParameter("inStock", Product.IN_STOCK); Product product = null; try { product = (Product) inStockQuery.getSingleResult(); } catch (NoResultException nre) { } catch (Exception e) { Logger.error("An error occurred on checking product ("+productId+") availability", e); } return product != null; } }); if (inStock.booleanValue() == true) { return delegate.call(ctx); } } catch (Exception e) { Logger.error("An error occurred on checking if product is in stock for path "+Context.current().request().path(), e); } return F.Promise.pure(redirect(routes.ProductController.productUnavailable(productId))); } }