All Downloads are FREE. Search and download functionalities are using the official Maven repository.

bitronix.tm.utils.Scheduler Maven / Gradle / Ivy

The newest version!
/*
 * 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.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;

/**
 * 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.
 *
 * @author Ludovic Orban
 * @param  the type the scheduler handles
 */
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;


    public Scheduler() {
    }

    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++;
    }

    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);
    }

    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(Integer position) {
        return objects.get(position);
    }

    public synchronized List getByReverseOrderForPosition(Integer position) {
        List result = new ArrayList(getByNaturalOrderForPosition(position));
        Collections.reverse(result);
        return result;
    }

    public synchronized int size() {
        return size;
    }

    @Override
    public Iterator iterator() {
        return new SchedulerNaturalOrderIterator();
    }

    public Iterator reverseIterator() {
        return new SchedulerReverseOrderIterator();
    }

    @Override
    public String toString() {
        return "a Scheduler with " + size() + " object(s) in " + getNaturalOrderPositions().size() + " position(s)";
    }

    /**
     * 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;

        private SchedulerNaturalOrderIterator() {
            this.nextKeyIndex = 0;
        }

        @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--;
            }
        }

        @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;
            }
        }

        @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;

        private SchedulerReverseOrderIterator() {
            synchronized (Scheduler.this) {
                this.nextKeyIndex = Scheduler.this.keys.size() -1;
            }
        }

        @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--;
            }
        }

        @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;
            }
        }

        @Override
        public T next() {
            synchronized (Scheduler.this) {
                if (!hasNext())
                    throw new NoSuchElementException("iterator bounds reached");
                return objectsOfCurrentKey.get(objectsOfCurrentKeyIndex++);
            }
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy