QueueBean.java 6.48 KB
package fi.codecrew.moya.beans.map;

import java.util.Date;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

import javax.annotation.security.DeclareRoles;
import javax.annotation.security.RolesAllowed;
import javax.ejb.Asynchronous;
import javax.ejb.EJB;
import javax.ejb.LocalBean;
import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ejb.Singleton;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import fi.codecrew.moya.beans.EventBeanLocal;
import fi.codecrew.moya.beans.PermissionBeanLocal;
import fi.codecrew.moya.beans.PlaceBeanLocal;
import fi.codecrew.moya.enums.apps.MapPermission;
import fi.codecrew.moya.facade.PlaceSlotFacade;
import fi.codecrew.moya.model.EventMap;
import fi.codecrew.moya.model.EventUser;
import fi.codecrew.moya.model.LanEventPropertyKey;
import fi.codecrew.moya.model.PlaceSlot;
import fi.codecrew.moya.model.map.MapReservationQueueEntry;

/**
 * Session Bean implementation class QueueBean
 */
@Singleton
@LocalBean
@Lock(LockType.READ)
@DeclareRoles({ MapPermission.S_MANAGE_MAPS })
public class QueueBean implements QueueBeanLocal {
	private static final Logger logger = LoggerFactory.getLogger(QueueBean.class);

	/**
	 * Default constructor.
	 */
	public QueueBean() {
		logger.info("Initialized2 QueueBean, {}", mapqueues);
	}

	@EJB
	private PlaceBeanLocal placebean;

	private final ConcurrentHashMap<Integer, MapQueue> mapqueues = new ConcurrentHashMap<Integer, MapQueue>();

	
	@EJB
	private EventBeanLocal eventbean;
	private AtomicLong nextReservingTimeoutCheck = new AtomicLong();
	@EJB
	private PlaceSlotFacade slotfacade;
	@EJB
	private PermissionBeanLocal permbean;

	@Lock(LockType.READ)
	@Override
	public boolean isReserving(EventMap map, EventUser user) {
		// If queue is not enabled, user can always reserve

		if (!isQueueEnabled())
			return true;
		if (!permbean.isCurrentUser(user) && !permbean.hasPermission(MapPermission.MANAGE_OTHERS))
			throw new RuntimeException("Use " + permbean.getCurrentUser() + "tried to enter to queue in behalf of another user: " + user);

		if (map == null || user == null) {
			logger.warn("Can not check map {}, user {}", map, user);
			return false;
		}
		boolean ret = getMapque(map).isReserving(user);

		// Do some housekeeping, but only on each 120

		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;

	}

	@Lock(LockType.READ)
	@Asynchronous
	private void checkReservingTimeouts() {
		try {
			final long oldTime = nextReservingTimeoutCheck.get();
			for (MapQueue m : mapqueues.values()) {
				m.timeoutEntries();
			}

			// DO housekeeping every 10 seconds.
			nextReservingTimeoutCheck.compareAndSet(oldTime, System.currentTimeMillis() + 1000 * 10);
		} catch (Exception t) {
			logger.warn("Exception while checking reservingTimeouts", t);
		}
	}

	@Lock(LockType.READ)
	private MapQueue getMapque(EventMap map) {
		if (map == null) {
			return null;
		}
		MapQueue ret = mapqueues.get(map.getId());

		if (ret == null) {
			ret = new MapQueue(map);
			MapQueue nret = mapqueues.putIfAbsent(map.getId(), ret);
			if (nret != null) {
				ret = nret;
			}
		}
		logger.info("returning queue {} for map {}", ret, map);
		return ret;
	}

	@Lock(LockType.READ)
	@Override
	public Date getReservationTimeout(EventMap map)
	{
		Date d = null;
		MapReservationQueueEntry ret = getMapque(map).getEntry(permbean.getCurrentUser());
		if (ret != null)
			d = ret.getReservationTimeout();
		return d;
	}

	public Date getReservingTimeout(EventMap map)
	{
		MapReservationQueueEntry ret = getMapque(map).getEntry(permbean.getCurrentUser());
		Date time = null;
		if (ret != null)
			time = ret.getReservationTimeout();
		return time;
	}

	@Lock(LockType.READ)
	@Override
	public Integer getQueuePosition(EventMap map, EventUser user)
	{
		if (!permbean.isCurrentUser(user) && !permbean.hasPermission(MapPermission.MANAGE_OTHERS))
			throw new RuntimeException("Use " + permbean.getCurrentUser() + "tried to get queuepos in behalf of another user: " + user);

		return getMapque(map).getPosition(permbean.getCurrentUser());
	}

	@Lock(LockType.READ)
	@Override
	public boolean isQueueEnabled() {
		return eventbean.getPropertyBoolean(LanEventPropertyKey.MAP_QUEUE);
	}

	@Lock(LockType.READ)
	@Override
	public MapReservationQueueEntry remove(EventMap map, EventUser user) {
		if (!permbean.isCurrentUser(user) && !permbean.hasPermission(MapPermission.MANAGE_OTHERS))
			throw new RuntimeException("Use " + permbean.getCurrentUser() + "tried to enter to queue in behalf of another user: " + user);

		MapQueue queue = getMapque(map);
		return queue.remove(user);
	}

	@Override
	@Lock(LockType.READ)
	@RolesAllowed(MapPermission.S_MANAGE_MAPS)
	public void forceAddToReserving(EventMap map, EventUser u, Date time) {
		MapQueue q = getMapque(map);
		List<PlaceSlot> slots = slotfacade.findFreePlaceSlots(u, map);
		q.forceAdd(u, time, slots);

	}

	@Override
	@Lock(LockType.READ)
	public MapReservationQueueEntry enterQueue(EventMap map, EventUser user) {
		if (!isQueueEnabled()) {
			return null;
		}

		if (!permbean.isCurrentUser(user) && !permbean.hasPermission(MapPermission.MANAGE_OTHERS))
			throw new RuntimeException("Use " + permbean.getCurrentUser() + "tried to enter to queue in behalf of another user: " + user);

		if (user == null || user.isAnonymous()) {
			return null;
		}
		MapQueue queue = getMapque(map);

		MapReservationQueueEntry ret = null;
		if (queue.isInQueue(user)) {
			logger.info("User {} already in queue");
			ret = queue.getEntry(user);
		} else {
			List<PlaceSlot> slots = slotfacade.findFreePlaceSlots(user, map);
			logger.info("User {} not yet in queue. User has {} slots", user, slots.size());
			if (!slots.isEmpty() && slots.size() >= queue.getMinimumSlotsInQueue()) {
				ret = queue.enter(user, slots);
			}
		}
		return ret;

	}

	@Lock(LockType.READ)
	@RolesAllowed({MapPermission.S_MANAGE_MAPS, MapPermission.S_BUY_PLACES})
	@Override
	public MapQueue getMapQueue(EventMap map) {
		return getMapque(map);

	}

	@Override
	@Lock(LockType.READ)
	@RolesAllowed(MapPermission.S_MANAGE_MAPS)
	public void forceRemove(EventMap e, EventUser u) {
		MapQueue q = getMapque(e);
		q.remove(u);
	}

}