Commit 4966dc18 by Tuomas Riihimäki

Moar queue

1 parent 2c6396cb
...@@ -13,4 +13,10 @@ public interface QueueBeanLocal { ...@@ -13,4 +13,10 @@ public interface QueueBeanLocal {
boolean isReserving(EventMap map, EventUser user); boolean isReserving(EventMap map, EventUser user);
Integer getQueuePosition(EventMap map, EventUser user);
boolean isQueueEnabled();
MapReservationQueueEntry remove(EventMap map, EventUser user);
} }
package fi.codecrew.moya.beans; package fi.codecrew.moya.beans;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
...@@ -23,11 +21,12 @@ import javax.ejb.Singleton; ...@@ -23,11 +21,12 @@ import javax.ejb.Singleton;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import fi.codecrew.moya.facade.PlaceSlotFacade;
import fi.codecrew.moya.model.EventMap; import fi.codecrew.moya.model.EventMap;
import fi.codecrew.moya.model.EventUser; import fi.codecrew.moya.model.EventUser;
import fi.codecrew.moya.model.LanEventProperty; import fi.codecrew.moya.model.LanEventProperty;
import fi.codecrew.moya.model.LanEventPropertyKey; import fi.codecrew.moya.model.LanEventPropertyKey;
import fi.codecrew.moya.model.map.MapReservationQueue; import fi.codecrew.moya.model.PlaceSlot;
import fi.codecrew.moya.model.map.MapReservationQueueEntry; import fi.codecrew.moya.model.map.MapReservationQueueEntry;
/** /**
...@@ -42,10 +41,11 @@ public class QueueBean implements QueueBeanLocal { ...@@ -42,10 +41,11 @@ public class QueueBean implements QueueBeanLocal {
* Default constructor. * Default constructor.
*/ */
public QueueBean() { public QueueBean() {
// TODO Auto-generated constructor stub mapqueues = new HashMap<>();
logger.info("Initialized2 QueueBean, {}", mapqueues);
} }
private final Map<EventMap, MapQueue> mapqueues = new HashMap<>(); private final Map<Integer, MapQueue> mapqueues;
private int reservingSize = 4; private int reservingSize = 4;
...@@ -104,7 +104,10 @@ public class QueueBean implements QueueBeanLocal { ...@@ -104,7 +104,10 @@ public class QueueBean implements QueueBeanLocal {
} }
} }
} }
queEntries.get(e).setSeenTime(new Date()); MapReservationQueueEntry que = queEntries.get(e);
if (que != null) {
que.setSeenTime(new Date());
}
return reserving.contains(e); return reserving.contains(e);
} }
...@@ -131,9 +134,11 @@ public class QueueBean implements QueueBeanLocal { ...@@ -131,9 +134,11 @@ public class QueueBean implements QueueBeanLocal {
if (!reserving.contains(user) && !queue.contains(user)) { if (!reserving.contains(user) && !queue.contains(user)) {
ret = new MapReservationQueueEntry(); ret = new MapReservationQueueEntry();
queEntries.put(user, ret); queEntries.put(user, ret);
queue.offer(user); boolean queStat = queue.offer(user);
logger.info("User {} not in queue, offer state {}", user, queStat);
} else { } else {
ret = queEntries.get(user); ret = queEntries.get(user);
logger.info("User {} already in queue. Not entering again {}", user, ret);
} }
} }
return ret; return ret;
...@@ -145,7 +150,9 @@ public class QueueBean implements QueueBeanLocal { ...@@ -145,7 +150,9 @@ public class QueueBean implements QueueBeanLocal {
if (reserving.contains(user)) { if (reserving.contains(user)) {
ret = 0; ret = 0;
logger.info("User in reserving queue {}", user);
} else if (queue.contains(user)) { } else if (queue.contains(user)) {
ret = 1; ret = 1;
for (EventUser eu : queue) { for (EventUser eu : queue) {
if (eu.equals(user)) { if (eu.equals(user)) {
...@@ -153,16 +160,31 @@ public class QueueBean implements QueueBeanLocal { ...@@ -153,16 +160,31 @@ public class QueueBean implements QueueBeanLocal {
} }
++ret; ++ret;
} }
logger.info("User is in queue {}, position {}", user, ret);
} else {
logger.info("Not in queue, while checking position");
} }
logger.info("Got position {} for user {}", ret, user);
return ret; return ret;
} }
public boolean isInQueue(EventUser user) {
return reserving.contains(user) || queue.contains(user);
}
public MapReservationQueueEntry getEntry(EventUser user) {
return queEntries.get(user);
}
} }
@EJB @EJB
private EventBeanLocal eventbean; private EventBeanLocal eventbean;
private AtomicLong nextReservingTimeoutCheck = new AtomicLong(); private AtomicLong nextReservingTimeoutCheck = new AtomicLong();
@EJB
private PlaceSlotFacade slotfacade;
@Lock(LockType.READ) @Lock(LockType.READ)
@Override
public boolean isReserving(EventMap map, EventUser user) { public boolean isReserving(EventMap map, EventUser user) {
// If queue is not enabled, user can always reserve // If queue is not enabled, user can always reserve
if (!isQueueEnabled()) if (!isQueueEnabled())
...@@ -201,22 +223,31 @@ public class QueueBean implements QueueBeanLocal { ...@@ -201,22 +223,31 @@ public class QueueBean implements QueueBeanLocal {
} }
private MapQueue getMapque(EventMap map) { private MapQueue getMapque(EventMap map) {
MapQueue ret = mapqueues.get(map); if (map == null) {
if (ret == null) { return null;
ret = new MapQueue();
mapqueues.put(map, ret);
} }
MapQueue ret = mapqueues.get(map.getId());
if (ret == null) {
logger.info("getMapqueue, {}", mapqueues);
synchronized (mapqueues) {
ret = new MapQueue();
mapqueues.put(map.getId(), ret);
}
}
logger.info("returning queue {} for map {}", ret, map);
return ret; return ret;
} }
@Lock(LockType.READ) @Lock(LockType.READ)
@Override
public Integer getQueuePosition(EventMap map, EventUser user) public Integer getQueuePosition(EventMap map, EventUser user)
{ {
return getMapque(map).getPosition(user); return getMapque(map).getPosition(user);
} }
@Lock(LockType.READ) @Lock(LockType.READ)
@Override
public boolean isQueueEnabled() { public boolean isQueueEnabled() {
boolean ret = false; boolean ret = false;
LanEventProperty mapque = eventbean.getProperty(LanEventPropertyKey.MAP_QUEUE); LanEventProperty mapque = eventbean.getProperty(LanEventPropertyKey.MAP_QUEUE);
...@@ -227,6 +258,7 @@ public class QueueBean implements QueueBeanLocal { ...@@ -227,6 +258,7 @@ public class QueueBean implements QueueBeanLocal {
} }
@Lock(LockType.READ) @Lock(LockType.READ)
@Override
public MapReservationQueueEntry remove(EventMap map, EventUser user) { public MapReservationQueueEntry remove(EventMap map, EventUser user) {
MapQueue queue = getMapque(map); MapQueue queue = getMapque(map);
return queue.remove(user); return queue.remove(user);
...@@ -235,8 +267,24 @@ public class QueueBean implements QueueBeanLocal { ...@@ -235,8 +267,24 @@ public class QueueBean implements QueueBeanLocal {
@Override @Override
@Lock(LockType.READ) @Lock(LockType.READ)
public MapReservationQueueEntry enterQueue(EventMap map, EventUser user) { public MapReservationQueueEntry enterQueue(EventMap map, EventUser user) {
if (!isQueueEnabled()) {
return null;
}
MapQueue queue = getMapque(map); MapQueue queue = getMapque(map);
return queue.enter(user);
MapReservationQueueEntry ret = null;
if (queue.isInQueue(user)) {
logger.info("User {} already in queue");
ret = queue.getEntry(user);
} else {
List<PlaceSlot> slots = slotfacade.findFreePlaceSlots(user, null);
logger.info("User {} not yet in queue. User has {} slots", user, slots.size());
if (!slots.isEmpty()) {
ret = queue.enter(user);
logger.info("Entered queue: {}", ret);
}
}
return ret;
} }
} }
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
*/ */
package fi.codecrew.moya.facade; package fi.codecrew.moya.facade;
import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.List; import java.util.List;
...@@ -27,6 +28,7 @@ import javax.ejb.Stateless; ...@@ -27,6 +28,7 @@ import javax.ejb.Stateless;
import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path; import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root; import javax.persistence.criteria.Root;
import org.slf4j.Logger; import org.slf4j.Logger;
...@@ -67,11 +69,15 @@ public class PlaceSlotFacade extends IntegerPkGenericFacade<PlaceSlot> { ...@@ -67,11 +69,15 @@ public class PlaceSlotFacade extends IntegerPkGenericFacade<PlaceSlot> {
CriteriaQuery<PlaceSlot> q = cb.createQuery(PlaceSlot.class); CriteriaQuery<PlaceSlot> q = cb.createQuery(PlaceSlot.class);
Root<PlaceSlot> root = q.from(PlaceSlot.class); Root<PlaceSlot> root = q.from(PlaceSlot.class);
Path<Bill> bill = root.get(PlaceSlot_.bill); Path<Bill> bill = root.get(PlaceSlot_.bill);
q.where(cb.equal(bill.get(Bill_.user), user), final List<Predicate> preds = new ArrayList<>();
cb.isNotNull(bill.get(Bill_.paidDate)), preds.add(cb.equal(bill.get(Bill_.user), user));
cb.isNull(root.get(PlaceSlot_.used)), preds.add(cb.isNotNull(bill.get(Bill_.paidDate)));
cb.equal(root.get(PlaceSlot_.product), product) preds.add(cb.isNull(root.get(PlaceSlot_.used)));
); if (product != null) {
preds.add(cb.equal(root.get(PlaceSlot_.product), product));
}
q.where(preds.toArray(new Predicate[preds.size()]));
return getEm().createQuery(q).getResultList(); return getEm().createQuery(q).getResultList();
} }
...@@ -102,18 +108,15 @@ public class PlaceSlotFacade extends IntegerPkGenericFacade<PlaceSlot> { ...@@ -102,18 +108,15 @@ public class PlaceSlotFacade extends IntegerPkGenericFacade<PlaceSlot> {
q.where(cb.equal(root.get(PlaceSlot_.product), prod), q.where(cb.equal(root.get(PlaceSlot_.product), prod),
cb.or(cb.isNull(billexp), cb.or(cb.isNull(billexp),
cb.greaterThan(billexp, Calendar.getInstance()) cb.greaterThan(billexp, Calendar.getInstance())
), ),
cb.isNull(root.get(PlaceSlot_.place)), cb.isNull(root.get(PlaceSlot_.place)),
cb.isNull(root.get(PlaceSlot_.used)) cb.isNull(root.get(PlaceSlot_.used))
); );
Long count = super.getSingleNullableResult(getEm().createQuery(q)); Long count = super.getSingleNullableResult(getEm().createQuery(q));
return count; return count;
} }
public Long totalSlotcount(Product prod) { public Long totalSlotcount(Product prod) {
CriteriaBuilder cb = getEm().getCriteriaBuilder(); CriteriaBuilder cb = getEm().getCriteriaBuilder();
CriteriaQuery<Long> q = cb.createQuery(Long.class); CriteriaQuery<Long> q = cb.createQuery(Long.class);
......
...@@ -35,14 +35,24 @@ ...@@ -35,14 +35,24 @@
<h:outputScript target="head" library="seatjs" name="d3-tip.js" /> <h:outputScript target="head" library="seatjs" name="d3-tip.js" />
<h:outputScript target="head" library="seatjs" name="seatmap.js" /> <h:outputScript target="head" library="seatjs" name="seatmap.js" />
<h:outputStylesheet library="seatjs" name="placemap.css" /> <h:outputStylesheet library="seatjs" name="placemap.css" />
<div style="margin: 5px;"> <div style="margin: 5px;">
<h:form id="placeselectform"> <h:form id="placeselectform">
<h:commandButton rendered="#{ajaxMapView.canUserBuy()}" <p:commandButton rendered="#{ajaxMapView.canUserBuy()}"
value="#{i18n['mapView.buyPlaces']}" value="#{i18n['mapView.buyPlaces']}"
action="#{ajaxMapView.buySelectedPlaces()}" /> action="#{ajaxMapView.buySelectedPlaces()}" ajax="false" />
</h:form> </h:form>
</div> </div>
<h:form>
<p:commandButton value="#{i18n['mapView.enterQueue']}"
action="#{ajaxMapView.enterQueue()}" ajax="false" />
</h:form>
queueEntry #{ajaxMapView.queueEntry} <br />
QueuePosition: #{ajaxMapView.queuePosition} <br />
Available places to select: #{ajaxMapView.placesLeftToSelect} <br />
<svg id="seatmap" style="margin: auto; border: 1px solid black;" <svg id="seatmap" style="margin: auto; border: 1px solid black;"
width="#{ajaxMapView.map.width}px" width="#{ajaxMapView.map.width}px"
height="#{ajaxMapView.map.height}px" /> height="#{ajaxMapView.map.height}px" />
...@@ -91,7 +101,7 @@ ...@@ -91,7 +101,7 @@
<h:outputLabel value="#{i18n['placeSelect.placesleft']}:" /> <h:outputLabel value="#{i18n['placeSelect.placesleft']}:" />
<h:outputText value="#{ajaxMapView.placesLeftToSelect}" /> <h:outputText value="#{ajaxMapView.placesLeftToSelect}" />
</h:panelGrid> </h:panelGrid>
</h:panelGrid> </h:panelGrid>
......
...@@ -23,6 +23,7 @@ import fi.codecrew.moya.model.EventMap; ...@@ -23,6 +23,7 @@ import fi.codecrew.moya.model.EventMap;
import fi.codecrew.moya.model.EventUser; import fi.codecrew.moya.model.EventUser;
import fi.codecrew.moya.model.LanEvent; import fi.codecrew.moya.model.LanEvent;
import fi.codecrew.moya.model.Place; import fi.codecrew.moya.model.Place;
import fi.codecrew.moya.model.map.MapReservationQueueEntry;
import fi.codecrew.moya.web.cdiview.GenericCDIView; import fi.codecrew.moya.web.cdiview.GenericCDIView;
import fi.codecrew.moya.web.cdiview.user.UserView; import fi.codecrew.moya.web.cdiview.user.UserView;
...@@ -34,8 +35,8 @@ public class AjaxMapView extends GenericCDIView { ...@@ -34,8 +35,8 @@ public class AjaxMapView extends GenericCDIView {
* *
*/ */
private static final long serialVersionUID = 8203589456357519480L; private static final long serialVersionUID = 8203589456357519480L;
@Inject // @Inject
private PlaceView placeview; // private PlaceView placeview;
private static final Logger logger = LoggerFactory.getLogger(AjaxMapView.class);; private static final Logger logger = LoggerFactory.getLogger(AjaxMapView.class);;
private String testVal = "Testval1"; private String testVal = "Testval1";
...@@ -67,6 +68,26 @@ public class AjaxMapView extends GenericCDIView { ...@@ -67,6 +68,26 @@ public class AjaxMapView extends GenericCDIView {
initMap(); initMap();
} }
private Boolean queEnabled = null;
private MapReservationQueueEntry queueEntry;
public boolean isQueueEnabled() {
if (queEnabled == null)
queEnabled = quebean.isQueueEnabled();
return queEnabled;
}
public String enterQueue()
{
logger.info("Entering queue");
if (isQueueEnabled())
queueEntry = quebean.enterQueue(initMap(), permbean.getCurrentUser());
else {
logger.warn("QueueNot enabled. Not entering queue");
}
return null;
}
private EventMap initMap() { private EventMap initMap() {
if (map == null && mapId != null) { if (map == null && mapId != null) {
map = placebean.findMap(mapId); map = placebean.findMap(mapId);
...@@ -83,9 +104,14 @@ public class AjaxMapView extends GenericCDIView { ...@@ -83,9 +104,14 @@ public class AjaxMapView extends GenericCDIView {
} }
} }
} }
return map; return map;
} }
public Integer getQueuePosition() {
return quebean.getQueuePosition(initMap(), permbean.getCurrentUser());
}
public Long getPlacesLeftToSelect() { public Long getPlacesLeftToSelect() {
Long ret = placebean.selectablePlaceCount(initMap()); Long ret = placebean.selectablePlaceCount(initMap());
logger.debug("Got {} places left for map {}", ret, initMap()); logger.debug("Got {} places left for map {}", ret, initMap());
...@@ -172,4 +198,12 @@ public class AjaxMapView extends GenericCDIView { ...@@ -172,4 +198,12 @@ public class AjaxMapView extends GenericCDIView {
public void setContext(FacesContext context) { public void setContext(FacesContext context) {
this.context = context; this.context = context;
} }
public MapReservationQueueEntry getQueueEntry() {
return queueEntry;
}
public void setQueueEntry(MapReservationQueueEntry queueEntry) {
this.queueEntry = queueEntry;
}
} }
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!