Commit 4d268fed by Tuomas Riihimäki

Initial QueueBean implementation

1 parent cb32afc5
package fi.codecrew.moya.beans;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicLong;
import javax.ejb.Asynchronous;
import javax.ejb.EJB;
import javax.ejb.LocalBean;
import javax.ejb.Singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fi.codecrew.moya.model.EventMap;
import fi.codecrew.moya.model.EventUser;
import fi.codecrew.moya.model.LanEventProperty;
......@@ -25,6 +34,7 @@ import fi.codecrew.moya.model.map.MapReservationQueueEntry;
@Singleton
@LocalBean
public class QueueBean implements QueueBeanLocal {
private static final Logger logger = LoggerFactory.getLogger(QueueBean.class);
/**
* Default constructor.
......@@ -36,61 +46,128 @@ public class QueueBean implements QueueBeanLocal {
private final Map<EventMap, MapQueue> mapqueues = new HashMap<>();
private static class MapQueue {
private final Set<MapReservationQueueEntry> reserving = new HashSet<>();
private final List<MapReservationQueueEntry> queue = new ArrayList<>();
for (MapReservationQueueEntry r : reserving) {
if (new Date().after(r.getReservationTimeout())) {
reserving.remove(r);
// private final Set<MapReservationQueueEntry> reserving = new HashSet<>();
private final Set<EventUser> reserving = Collections.newSetFromMap(new ConcurrentHashMap<EventUser, Boolean>());
private final LinkedBlockingQueue<EventUser> queue = new LinkedBlockingQueue<>();
private final ConcurrentMap<EventUser, MapReservationQueueEntry> queEntries = new ConcurrentHashMap<>();
// public boolean enterReserving( EventUser user) {
// timeoutReserving();
//
// if (reserving.size() < 3 && !queue.isEmpty() && queue.get(0).equals(entry)) {
// entry = queue.get(0);
// entry.removeFromQueue();
// }
// }
private void timeoutEntries() {
// give 10 seconds mercy ( and give us some time to go through all entries)
Date now = new Date(System.currentTimeMillis() + 1000 * 15);
for (EventUser r : reserving) {
MapReservationQueueEntry entry = queEntries.get(r);
if (entry.getReservationTimeout() == null || now.after(entry.getReservationTimeout())) {
this.remove(entry.getUser());
}
}
}
public boolean isReserving(EventUser user) {
for(MapReservationQueueEntry r : reserving) {
if(r.getUser().equals(user)) {
return true;
// Set idle time to the past.
// Idle timeout after 60 seconds
Date idleTimeout = new Date(System.currentTimeMillis() - 1000 * 60);
for (EventUser q : queue) {
MapReservationQueueEntry entry = queEntries.get(q);
if (entry.getSeenTime() == null) {
entry.setSeenTime(new Date());
continue;
}
if (idleTimeout.after(entry.getSeenTime())) {
remove(entry.getUser());
}
}
return false;
}
public boolean enterReserving( EventUser user) {
timeoutReserving();
if (reserving.size() < 3 && !queue.isEmpty() && queue.get(0).equals(entry)) {
entry = queue.get(0);
entry.removeFromQueue();
public boolean isReserving(EventUser e) {
queEntries.get(e).setSeenTime(new Date());
return reserving.contains(e);
}
public MapReservationQueueEntry remove(EventUser user)
{
MapReservationQueueEntry ret = null;
synchronized (queue) {
if (reserving.remove(user)) {
logger.info("Removed user {} from reserving queue", user);
}
// There should neve be more than one instance, but make sure
while (!queue.remove(user)) {
logger.info("Removed user {} from queue");
}
ret = queEntries.remove(user);
}
return ret;
}
private void timeoutReserving() {
public MapReservationQueueEntry enter(EventUser user) {
MapReservationQueueEntry ret = null;
synchronized (queue) {
if (!reserving.contains(user) && !queue.contains(user)) {
ret = new MapReservationQueueEntry();
queEntries.put(user, ret);
queue.offer(user);
} else {
ret = queEntries.get(user);
}
}
return ret;
}
}
public boolean enterReserving(EventMap map, EventUser user) {
}
@EJB
private EventBeanLocal eventbean;
private AtomicLong nextReservingTimeoutCheck = new AtomicLong();
public boolean isReserving(EventMap map, EventUser user) {
// If queue is not enabled, user can always reserve
if (!isQueueEnabled())
return true;
return getMapque(map).isReserving(user);
boolean ret = getMapque(map).isReserving(user);
long now = System.currentTimeMillis();
long nextTime = nextReservingTimeoutCheck.get();
// Update next checktime to 120 seconds in to the future, so we should have plenty of time
// to do the checks we need..
if (now > nextTime && nextReservingTimeoutCheck.compareAndSet(nextTime, now + 1000 * 120)) {
logger.info("Launcing reservingTimeout check ");
checkReservingTimeouts();
logger.info("Done launching reservingTimeoutCheck");
}
return ret;
}
@Asynchronous
public void checkReservingTimeouts() {
try {
for (MapQueue m : mapqueues.values()) {
m.timeoutEntries();
}
} catch (Throwable t) {
logger.warn("Exception while checking reservingTimeouts");
}
}
private MapQueue getMapque(EventMap map) {
MapQueue ret = mapqueues.get(map);
if(ret == null){
ret = new MapQueue();
mapqueues.put(map, ret);
}
return ret;
MapQueue ret = mapqueues.get(map);
if (ret == null) {
ret = new MapQueue();
mapqueues.put(map, ret);
}
return ret;
}
public boolean isQueueEnabled() {
......@@ -102,30 +179,15 @@ public class QueueBean implements QueueBeanLocal {
}
public MapReservationQueueEntry remove(EventMap map, EventUser user) {
MapQueue queue = getMapque(map);
return queue.remove(user);
}
@Override
public MapReservationQueueEntry enterQueue(EventMap map, EventUser user) {
if (!queue.containsKey(map)) {
queue.put(map, new ArrayList<MapReservationQueueEntry>());
}
List<MapReservationQueueEntry> quelist = queue.get(map);
MapReservationQueueEntry ret = null;
for (MapReservationQueueEntry qe : quelist) {
if (user.equals(qe.getUser())) {
ret = qe;
break;
}
}
if (ret == null) {
ret = new MapReservationQueueEntry();
ret.setCreated(new Date());
ret.setUser(user);
ret.addToQueue(quelist.get(quelist.size() - 1));
quelist.add(ret);
}
return ret;
MapQueue queue = getMapque(map);
return queue.enter(user);
}
}
......@@ -28,8 +28,8 @@ import fi.codecrew.moya.model.GenericEntity;
//- placecountWeight ( 1 = more places go first, 0 = fully random
//- queueTimeWeight ( 1 = fifo, 0 = fully random )
@Entity
@Table(name = "map_reservation_queue")
//@Entity
// @Table(name = "map_reservation_queue")
public class MapReservationQueue extends GenericEntity {
@ManyToOne
......
......@@ -10,6 +10,7 @@ import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -22,8 +23,8 @@ import fi.codecrew.moya.model.GenericEntity;
//- enteredQueue
//- enteredSelection
@Entity
@Table(name = "map_reservation_queue_entry")
// @Entity
// @Table(name = "map_reservation_queue_entry")
public class MapReservationQueueEntry extends GenericEntity {
/**
......@@ -44,35 +45,37 @@ public class MapReservationQueueEntry extends GenericEntity {
@Temporal(TemporalType.TIMESTAMP)
private Date reservationTimeout;
@OneToOne()
@JoinColumn(nullable = true)
private MapReservationQueueEntry previous;
@OneToOne(mappedBy = "previous")
private MapReservationQueueEntry next;
@Transient
private Date seenTime;
// @OneToOne()
// @JoinColumn(nullable = true)
// private MapReservationQueueEntry previous;
//
// @OneToOne(mappedBy = "previous")
// private MapReservationQueueEntry next;
private static final Logger logger = LoggerFactory.getLogger(MapReservationQueueEntry.class);
public void removeFromQueue() {
if (previous != null) {
if (!this.equals(previous.getNext())) {
logger.warn("WTF!! Previous entrys next value does not match this! This '{}', Previous '{}', Next of previous '{}'", this, getPrevious(), getPrevious().getNext());
}
previous.setNext(next);
previous = null;
next = null;
}
}
public void addToQueue(MapReservationQueueEntry previous) {
if (previous != null) {
next = previous.getNext();
previous.setNext(this);
if (next != null) {
next.setPrevious(this);
}
}
}
// public void removeFromQueue() {
// if (previous != null) {
// if (!this.equals(previous.getNext())) {
// logger.warn("WTF!! Previous entrys next value does not match this! This '{}', Previous '{}', Next of previous '{}'", this, getPrevious(), getPrevious().getNext());
// }
// previous.setNext(next);
// previous = null;
// next = null;
// }
// }
//
// public void addToQueue(MapReservationQueueEntry previous) {
// if (previous != null) {
// next = previous.getNext();
// previous.setNext(this);
// if (next != null) {
// next.setPrevious(this);
// }
// }
// }
public MapReservationQueue getQueue() {
return queue;
......@@ -98,22 +101,6 @@ public class MapReservationQueueEntry extends GenericEntity {
this.created = created;
}
public MapReservationQueueEntry getPrevious() {
return previous;
}
public void setPrevious(MapReservationQueueEntry previous) {
this.previous = previous;
}
public MapReservationQueueEntry getNext() {
return next;
}
public void setNext(MapReservationQueueEntry next) {
this.next = next;
}
public Date getReservationTimeout() {
return reservationTimeout;
}
......@@ -122,4 +109,12 @@ public class MapReservationQueueEntry extends GenericEntity {
this.reservationTimeout = reservationTimeout;
}
public Date getSeenTime() {
return seenTime;
}
public void setSeenTime(Date seenTime) {
this.seenTime = seenTime;
}
}
......@@ -5,6 +5,7 @@ import java.util.Map;
import javax.ejb.EJB;
import javax.enterprise.context.ConversationScoped;
import javax.enterprise.context.RequestScoped;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!