bitronix.tm.utils.Scheduler Maven / Gradle / Ivy
/*
* Copyright (C) 2006-2013 Bitronix Software (http://www.bitronix.be)
*
* 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.
*
* @param
* the type the scheduler handles
*
* @author Ludovic Orban
*/
public class Scheduler
implements Iterable
{
public static final Integer DEFAULT_POSITION = 0;
public static final Integer ALWAYS_FIRST_POSITION = Integer.MIN_VALUE;
public static final Integer ALWAYS_LAST_POSITION = Integer.MAX_VALUE;
private final List keys = new ArrayList<>();
private final Map> objects = new TreeMap<>();
private int size = 0;
/**
* Constructor Scheduler creates a new Scheduler instance.
*/
public Scheduler()
{
//Nothing needed
}
/**
* Method add ...
*
* @param obj
* of type T
* @param position
* of type Integer
*/
public synchronized void add(T obj, Integer position)
{
List list = objects.get(position);
if (list == null)
{
if (!keys.contains(position))
{
keys.add(position);
Collections.sort(keys);
}
list = new ArrayList<>();
objects.put(position, list);
}
list.add(obj);
size++;
}
/**
* Method remove ...
*
* @param obj
* of type T
*/
public synchronized void remove(T obj)
{
Iterator it = iterator();
while (it.hasNext())
{
T o = it.next();
if (o == obj)
{
it.remove();
return;
}
}
throw new NoSuchElementException("no such element: " + obj);
}
/**
* Method iterator ...
*
* @return Iterator T
*/
@Override
public Iterator iterator()
{
return new SchedulerNaturalOrderIterator();
}
/**
* Method getReverseOrderPositions returns the reverseOrderPositions of this Scheduler object.
*
* @return the reverseOrderPositions (type SortedSet Integer ) of this Scheduler object.
*/
public synchronized SortedSet getReverseOrderPositions()
{
TreeSet result = new TreeSet<>(Collections.reverseOrder());
result.addAll(getNaturalOrderPositions());
return result;
}
/**
* Method getNaturalOrderPositions returns the naturalOrderPositions of this Scheduler object.
*
* @return the naturalOrderPositions (type SortedSet Integer ) of this Scheduler object.
*/
public synchronized SortedSet getNaturalOrderPositions()
{
return new TreeSet<>(objects.keySet());
}
/**
* Method getByReverseOrderForPosition ...
*
* @param position
* of type Integer
*
* @return List T
*/
public synchronized List getByReverseOrderForPosition(Integer position)
{
List result = new ArrayList<>(getByNaturalOrderForPosition(position));
Collections.reverse(result);
return result;
}
/**
* Method getByNaturalOrderForPosition ...
*
* @param position
* of type Integer
*
* @return List T
*/
public synchronized List getByNaturalOrderForPosition(Integer position)
{
return objects.get(position);
}
/**
* Method reverseIterator ...
*
* @return Iterator T
*/
public Iterator reverseIterator()
{
return new SchedulerReverseOrderIterator();
}
/**
* Method toString ...
*
* @return String
*/
@Override
public String toString()
{
return "a Scheduler with " + size() + " object(s) in " + getNaturalOrderPositions().size() + " position(s)";
}
/**
* Method size ...
*
* @return int
*/
public synchronized int size()
{
return size;
}
/**
* This iterator supports in-flight updates of the iterated object.
*/
private final class SchedulerNaturalOrderIterator
implements Iterator
{
private int nextKeyIndex;
private List objectsOfCurrentKey;
private int objectsOfCurrentKeyIndex;
/**
* Constructor SchedulerNaturalOrderIterator creates a new SchedulerNaturalOrderIterator instance.
*/
private SchedulerNaturalOrderIterator()
{
this.nextKeyIndex = 0;
}
/**
* Method remove ...
*/
@Override
public void remove()
{
synchronized (Scheduler.this)
{
if (objectsOfCurrentKey == null)
{
throw new NoSuchElementException("iterator not yet placed on an element");
}
objectsOfCurrentKeyIndex--;
objectsOfCurrentKey.remove(objectsOfCurrentKeyIndex);
if (objectsOfCurrentKey.isEmpty())
{
// there are no more objects in the current position's list -> remove it
nextKeyIndex--;
Integer key = Scheduler.this.keys.get(nextKeyIndex);
Scheduler.this.keys.remove(nextKeyIndex);
Scheduler.this.objects.remove(key);
objectsOfCurrentKey = null;
}
Scheduler.this.size--;
}
}
/**
* Method hasNext ...
*
* @return boolean
*/
@Override
public boolean hasNext()
{
synchronized (Scheduler.this)
{
if (objectsOfCurrentKey == null || objectsOfCurrentKeyIndex >= objectsOfCurrentKey.size())
{
// we reached the end of the current position's list
if (nextKeyIndex < Scheduler.this.keys.size())
{
// there is another position after this one
Integer currentKey = Scheduler.this.keys.get(nextKeyIndex++);
objectsOfCurrentKey = Scheduler.this.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;
}
}
/**
* Method next ...
*
* @return T
*/
@Override
public T next()
{
synchronized (Scheduler.this)
{
if (!hasNext())
{
throw new NoSuchElementException("iterator bounds reached");
}
return objectsOfCurrentKey.get(objectsOfCurrentKeyIndex++);
}
}
}
/**
* This iterator supports in-flight updates of the iterated object.
*/
private final class SchedulerReverseOrderIterator
implements Iterator
{
private int nextKeyIndex;
private List objectsOfCurrentKey;
private int objectsOfCurrentKeyIndex;
/**
* Constructor SchedulerReverseOrderIterator creates a new SchedulerReverseOrderIterator instance.
*/
private SchedulerReverseOrderIterator()
{
synchronized (Scheduler.this)
{
this.nextKeyIndex = Scheduler.this.keys.size() - 1;
}
}
/**
* Method remove ...
*/
@Override
public void remove()
{
synchronized (Scheduler.this)
{
if (objectsOfCurrentKey == null)
{
throw new NoSuchElementException("iterator not yet placed on an element");
}
objectsOfCurrentKeyIndex--;
objectsOfCurrentKey.remove(objectsOfCurrentKeyIndex);
if (objectsOfCurrentKey.isEmpty())
{
// there are no more objects in the current position's list -> remove it
Integer key = Scheduler.this.keys.get(nextKeyIndex + 1);
Scheduler.this.keys.remove(nextKeyIndex + 1);
Scheduler.this.objects.remove(key);
objectsOfCurrentKey = null;
}
Scheduler.this.size--;
}
}
/**
* Method hasNext ...
*
* @return boolean
*/
@Override
public boolean hasNext()
{
synchronized (Scheduler.this)
{
if (objectsOfCurrentKey == null || objectsOfCurrentKeyIndex >= objectsOfCurrentKey.size())
{
// we reached the end of the current position's list
if (nextKeyIndex >= 0)
{
// there is another position after this one
Integer currentKey = Scheduler.this.keys.get(nextKeyIndex--);
objectsOfCurrentKey = Scheduler.this.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;
}
}
/**
* Method next ...
*
* @return T
*/
@Override
public T next()
{
synchronized (Scheduler.this)
{
if (!hasNext())
{
throw new NoSuchElementException("iterator bounds reached");
}
return objectsOfCurrentKey.get(objectsOfCurrentKeyIndex++);
}
}
}
}