/** * Copyright 2010 JBoss Inc * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package bitronix.tm.utils; import java.util.*; /** * Positional object container. Objects can be added to a scheduler at a certain position (or priority) and can be * retrieved later on in their position + added order. All the objects of a scheduler can be iterated in order or * objects of a cetain position can be retrieved for iteration. * <p>© <a href="http://www.bitronix.be">Bitronix Software</a></p> * * @author lorban */ public class Scheduler { public static final int DEFAULT_POSITION = 0; public static final int ALWAYS_FIRST_POSITION = Integer.MIN_VALUE; public static final int ALWAYS_LAST_POSITION = Integer.MAX_VALUE; public static final Object DEFAULT_POSITION_KEY = new Integer(DEFAULT_POSITION); public static final Object ALWAYS_FIRST_POSITION_KEY = new Integer(ALWAYS_FIRST_POSITION); public static final Object ALWAYS_LAST_POSITION_KEY = new Integer(ALWAYS_LAST_POSITION); private List keys = new ArrayList(); private Map objects = new TreeMap(); private int size = 0; public Scheduler() { } public synchronized void add(Object obj, int position) { Integer key = new Integer(position); List synchronizationsList = (List) objects.get(key); if (synchronizationsList == null) { if (!keys.contains(key)) { keys.add(key); Collections.sort(keys); } synchronizationsList = new ArrayList(); objects.put(key, synchronizationsList); } synchronizationsList.add(obj); size++; } public synchronized void remove(Object obj) { Iterator it = iterator(); while (it.hasNext()) { Object o = it.next(); if (o == obj) { it.remove(); return; } } throw new NoSuchElementException("no such element: " + obj); } public synchronized SortedSet getNaturalOrderPositions() { return new TreeSet(objects.keySet()); } public synchronized SortedSet getReverseOrderPositions() { TreeSet result = new TreeSet(Collections.reverseOrder()); result.addAll(getNaturalOrderPositions()); return result; } public synchronized List getByNaturalOrderForPosition(Object positionKey) { return (List) objects.get(positionKey); } public synchronized List getByReverseOrderForPosition(Object positionKey) { List result = new ArrayList(getByNaturalOrderForPosition(positionKey)); Collections.reverse(result); return result; } public synchronized int size() { return size; } public Iterator iterator() { return new SchedulerIterator(this); } public String toString() { return "a Scheduler with " + size() + " object(s) in " + getNaturalOrderPositions().size() + " position(s)"; } private class SchedulerIterator implements Iterator { private Scheduler scheduler; private int nextKeyIndex; private List objectsOfCurrentKey; private int objectsOfCurrentKeyIndex; private SchedulerIterator(Scheduler scheduler) { this.scheduler = scheduler; this.nextKeyIndex = 0; } public void remove() { if (objectsOfCurrentKey == null) throw new NoSuchElementException("iterator not yet placed on an element"); objectsOfCurrentKeyIndex--; objectsOfCurrentKey.remove(objectsOfCurrentKeyIndex); if (objectsOfCurrentKey.size() == 0) { // there are no more objects in the current position's list -> remove it nextKeyIndex--; Object key = scheduler.keys.get(nextKeyIndex); scheduler.keys.remove(nextKeyIndex); scheduler.objects.remove(key); objectsOfCurrentKey = null; } scheduler.size--; } public boolean hasNext() { if (objectsOfCurrentKey == null || objectsOfCurrentKeyIndex >= objectsOfCurrentKey.size()) { // we reached the end of the current position's list if (nextKeyIndex < scheduler.keys.size()) { // there is another position after this one Integer currentKey = (Integer) scheduler.keys.get(nextKeyIndex++); objectsOfCurrentKey = (List) scheduler.objects.get(currentKey); objectsOfCurrentKeyIndex = 0; return true; } else { // there is no other position after this one return false; } } // there are still objects in the current position's list return true; } public Object next() { if (!hasNext()) throw new NoSuchElementException("iterator bounds reached"); return objectsOfCurrentKey.get(objectsOfCurrentKeyIndex++); } } }