/* RequestQueueImpl.java Purpose: Description: History: Fri Jan 20 09:51:39 2006, Created by tomyeh Copyright (C) 2006 Potix Corporation. All Rights Reserved. {{IS_RIGHT This program is distributed under LGPL Version 2.1 in the hope that it will be useful, but WITHOUT ANY WARRANTY. }}IS_RIGHT */ package org.zkoss.zk.ui.impl; import java.util.Collection; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.zkoss.lang.Objects; import org.zkoss.zk.au.AuRequest; import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.ComponentNotFoundException; import org.zkoss.zk.ui.Desktop; import org.zkoss.zk.ui.Page; import org.zkoss.zk.ui.sys.RequestQueue; /** * An implementation of {@link RequestQueue} behaving as * a queue of {@link AuRequest}. * There is one queue for each desktop. * * <p>Implementation Note: * Unlike only of desktop members, this class must be thread-safe. * * @author tomyeh */ public class RequestQueueImpl implements RequestQueue { private static final Logger log = LoggerFactory.getLogger(RequestQueueImpl.class); /** A list of pending {@link AuRequest}. */ private final List<AuRequest> _requests = new LinkedList<AuRequest>(); /** A list of request ID for performance measurement. */ private List<String> _pfreqIds; //-- RequestQueue --// public void addPerfRequestId(String requestId) { if (_pfreqIds == null) _pfreqIds = new LinkedList<String>(); _pfreqIds.add(requestId); } public Collection<String> clearPerfRequestIds() { final List<String> old = _pfreqIds; _pfreqIds = null; return old; } public boolean isEmpty() { while (!_requests.isEmpty()) { if (isObsolete(_requests.get(0))) _requests.remove(0); else return false; } return true; } private static boolean isObsolete(AuRequest request) { final Component comp = request.getComponent(); if (comp != null) { final Desktop dt = comp.getDesktop(); return dt != null && dt != request.getDesktop(); //Since 3.5.0, we allow a component to process events even //if it is detached (due to implementation of EventQueue) } return false; } public AuRequest nextRequest() { while (!_requests.isEmpty()) { final AuRequest request = _requests.remove(0); if (!isObsolete(request)) return request; } return null; } public void addRequests(Collection<AuRequest> requests) { for (AuRequest request : requests) { try { request.activate(); if (!isObsolete(request)) addRequest(request); } catch (ComponentNotFoundException ex) { //ignore it //ignore it since a long request might remove a timer //while clients already queues onTimer generated by the timer if (log.isDebugEnabled()) log.debug("Ignore request: " + ex.getMessage()); } } } private void addRequest(AuRequest request) { //case 1, BUSY_IGNORE: Drop any existent ignorable requests //We don't need to iterate all because requests is added one-by-one //In other words, if any temporary request, it must be the last { int last = _requests.size() - 1; if (last < 0) { //optimize the most common case _requests.add(request); return; } final AuRequest req2 = _requests.get(last); if ((req2.getOptions() & AuRequest.BUSY_IGNORE) != 0) { _requests.remove(last); //drop it if (last == 0) { _requests.add(request); return; } } } final String name = request.getCommand(); final int opts = request.getOptions(); //Since 3.0.2, redundant CTRL_GROUP is removed at the client //case 2, DUPLICATE_IGNORE: drop existent request if they are the same //as the arrival. if ((opts & AuRequest.DUPLICATE_IGNORE) != 0) { final String uuid = getUuid(request); for (Iterator<AuRequest> it = _requests.iterator(); it.hasNext();) { final AuRequest req2 = it.next(); if (req2.getCommand().equals(name) && Objects.equals(getUuid(req2), uuid)) { it.remove(); //drop req2 (the old one) break; //no need to iterate because impossible to have more } } //Case 3, REPEAT_IGNORE: drop existent if the immediate //following is the same } else if ((opts & AuRequest.REPEAT_IGNORE) != 0) { final int last = _requests.size() - 1; final AuRequest req2 = _requests.get(last); if (req2.getCommand().equals(name) && Objects.equals(getUuid(req2), getUuid(request))) { _requests.remove(last); } } _requests.add(request); } private String getUuid(AuRequest request) { final Component comp = request.getComponent(); if (comp != null) return comp.getUuid(); final Page page = request.getPage(); if (page != null) return page.getUuid(); return null; } }