# FixedSizeQueue.java

    /*
     *  Licensed to the Apache Software Foundation (ASF) under one
     *  or more contributor license agreements.  See the NOTICE file
     *  distributed with this work for additional information
     *  regarding copyright ownership.  The ASF licenses this file
     *  to you 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 org.apache.synapse.commons.executors.queues;

    import org.apache.synapse.commons.executors.InternalQueue;

    import java.util.concurrent.locks.Condition;
    import java.util.*;

    /**
     * A bounded queue implementation for internal queues. This queue is backed by an
     * fixed size array.
     *
     * @param <E> Should implement the Importance interface
     */
    public class FixedSizeQueue<E> extends AbstractQueue<E> implements InternalQueue<E> {

        /**
         * Priority of this queue
         */
        private int priority;

        /**
         * A waiting queue when this queue is full
         */
        private Condition notFullCond;

        /**
         * Array holding the queues
         */
        private E[] array;

        /**
         * Capacity of the queue
         */
        private int capacity;

        /**
         * Number of elements in the queue
         */
        private int count = 0;

        /**
         * Head of the queue
         */
        private int head = 0;

        /**
         * Tail of the queue
         */
        private int tail = 0;

        /**
         * Create a queue with the given priority and capacity.
         * @param priority priority of the elements in the queue
         * @param capacity capacity of the queue
         */
        public FixedSizeQueue(int priority, int capacity) {
            this.priority = priority;
            this.capacity = capacity;

            array = (E[]) new Object[capacity];
        }

        public int getPriority() {
            return priority;
        }

        public void setPriority(int p) {
            this.priority = p;
        }

        public Condition getNotFullCond() {
            return notFullCond;
        }

        public void setNotFullCond(Condition notFullCond) {
            this.notFullCond = notFullCond;
        }

        public Iterator<E> iterator() {
            return new Itr<E>();
        }

        public int size() {
            return count;
        }

        public String toString() {
            return super.toString() + this.priority;
        }

        public boolean offer(E e) {
            if (count == array.length) {
                return false;
            } else {
                insert(e);
                return true;
            }
        }

        public E poll() {
            if (count == 0)
                return null;
            return get();
        }

        public E peek() {
            return (count == 0) ? null : array[head];
        }

        public int remainingCapacity() {
            return capacity - count;
        }

        public int drainTo(Collection<? super E> c) {
            final E[] items = this.array;
            int i = head;
            int n = 0;
            int max = count;
            while (n < max) {
                c.add(items[i]);
                items[i] = null;
                i = increment(i);
                n++;
            }
            if (n > 0) {
                count = 0;
                tail = 0;
                head = 0;

            }
            return n;
        }

        public int drainTo(Collection<? super E> c, int maxElements) {
            final E[] items = this.array;
            int i = head;
            int n = 0;
            int max = (maxElements < count) ? maxElements : count;
            while (n < max) {
                c.add(items[i]);
                items[i] = null;
                i = increment(i);
                n++;
            }
            if (n > 0) {
                count -= n;
                head = i;
            }
            return n;
        }

        public int getCapacity() {
            return capacity;
        }

        @Override
        public boolean contains(Object o) {
            for (E e : array) {
                if (e.equals(o)) return true;
            }
            return false;
        }

        @Override
        public boolean remove(Object o) {
            boolean found = false;
            int i = head;
            int iterations = 0;
            while (iterations++ < count) {
                if (!found && array[i].equals(o)) {
                    found = true;
                }

                if (found) {
                    int j = increment(i);
                    array[i] = array[j];
                }

                i = increment(i);
            }

            if (found) {
                count--;
                tail = decrement(tail);
            }

            return found;
        }

        private class Itr<E> implements Iterator<E> {
    	    int index = head;

            public boolean hasNext() {
                return index != tail;
            }

            public E next() {
                if (!hasNext()) {
                    throw new NoSuchElementException();
                }

                return (E) array[index++];

            }

            public void remove() {
                while (index != tail) {
                    int j = increment(index);

                    array[index] = array[j];
                    index = j;
                }
            }
        }

        private int decrement(int n) {
            return (n == 0) ? array.length - 1 : n;
        }

        private int increment(int n) {
            return (++n == array.length) ? 0 : n;
        }

        private void insert(E e) {
            array[tail] = e;
            tail = increment(tail);
            count++;
        }

        private E get() {
            E e = array[head];
            array[head] = null;
            head = increment(head);
            count--;
            return e;
        }
    }