Package org.apache.excalibur.event.impl

Source Code of org.apache.excalibur.event.impl.DefaultQueue$DefaultPreparedEnqueue

/*
* 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.excalibur.event.impl;

import org.apache.commons.collections.Buffer;
import org.apache.commons.collections.UnboundedFifoBuffer;
import org.apache.excalibur.event.EnqueuePredicate;
import org.apache.excalibur.event.PreparedEnqueue;
import org.apache.excalibur.event.SinkException;
import org.apache.excalibur.event.SinkFullException;

import EDU.oswego.cs.dl.util.concurrent.ReentrantLock;

/**
* The default queue implementation is a variable size queue.  This queue is
* thread safe, however the overhead in synchronization costs a few extra
* milliseconds.
*
* @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
*/
public final class DefaultQueue extends AbstractQueue
{
    private final Buffer m_elements;
    private final ReentrantLock m_mutex;
    protected int m_reserve;
    private final int m_maxSize;

    /**
     * Construct a new DefaultQueue with the specified number of elements.
     * if the number of elements is greater than zero, then the
     * <code>Queue</code> is bounded by that number.  Otherwise, the
     * <code>Queue</code> is not bounded at all.
     *
     * @param  size  The maximum number of elements in the <code>Queue</code>.
     *               Any number less than 1 means there is no limit.
     */
    public DefaultQueue( int size )
    {
        this( new ThresholdEnqueuePredicate( size ) );
    }

    public DefaultQueue( EnqueuePredicate predicate )
    {
        setEnqueuePredicate( predicate );

        m_mutex = new ReentrantLock();
        m_elements = new UnboundedFifoBuffer();
        m_reserve = 0;
        m_maxSize = -1;
    }

    /**
     * Create an unbounded DefaultQueue.
     */
    public DefaultQueue()
    {
        this( new NullEnqueuePredicate() );
    }

    /**
     * Return the number of elements currently in the <code>Queue</code>.
     *
     * @return <code>int</code> representing the number of elements (including the reserved ones).
     */
    public int size()
    {
        return m_elements.size() + m_reserve;
    }

    /**
     * Return the maximum number of elements that will fit in the
     * <code>Queue</code>.  A number below 1 indecates an unbounded
     * <code>Queue</code>, which means there is no limit.
     *
     * @return <code>int</code> representing the maximum number of elements
     */
    public int maxSize()
    {
        return m_maxSize;
    }

    public PreparedEnqueue prepareEnqueue( final Object[] elements )
        throws SinkException
    {
        PreparedEnqueue enqueue = null;

        try
        {
            m_mutex.acquire();
            try
            {
                if( getEnqueuePredicate().accept(elements, this) )
                {
                    enqueue = new DefaultPreparedEnqueue( this, elements );
                }
                else
                {
                    throw new SinkFullException( "Not enough room to enqueue these elements." );
                }
            }
            finally
            {
                m_mutex.release();
            }
        }
        catch( InterruptedException ie )
        {
            if ( null == enqueue )
            {
                throw new SinkException("The mutex was interrupted before it could be released");
            }
        }

        return enqueue;
    }

    public boolean tryEnqueue( final Object element )
    {
        boolean success = false;

        try
        {
            m_mutex.acquire();
            try
            {
                success = getEnqueuePredicate().accept( element, this );

                if ( success )
                {
                    m_elements.add( element );
                }
            }
            finally
            {
                m_mutex.release();
            }
        }
        catch( InterruptedException ie )
        {
        }

        return success;
    }

    public void enqueue( final Object[] elements )
        throws SinkException
    {
        final int len = elements.length;

        try
        {
            m_mutex.acquire();
            try
            {
                if( ! getEnqueuePredicate().accept( elements, this ) )
                {
                    throw new SinkFullException( "Not enough room to enqueue these elements." );
                }

                for( int i = 0; i < len; i++ )
                {
                    m_elements.add( elements[ i ] );
                }
            }
            finally
            {
                m_mutex.release();
            }
        }
        catch( InterruptedException ie )
        {
        }
    }

    public void enqueue( final Object element )
        throws SinkException
    {
        try
        {
            m_mutex.acquire();
            try
            {
                if( ! getEnqueuePredicate().accept(element, this) )
                {
                    throw new SinkFullException( "Not enough room to enqueue these elements." );
                }

                m_elements.add( element );
            }
            finally
            {
                m_mutex.release();
            }
        }
        catch( InterruptedException ie )
        {
        }
    }

    public Object[] dequeue( final int numElements )
    {
        getDequeueInterceptor().before(this);
        Object[] elements = EMPTY_ARRAY;

        try
        {
            if( m_mutex.attempt( m_timeout ) )
            {
                try
                {
                    elements = retrieveElements( m_elements,
                                                 Math.min( size(),
                                                           numElements ) );
                }
                finally
                {
                    m_mutex.release();
                }
            }
        }
        catch( InterruptedException ie )
        {
            //TODO: exception handling
        }

        getDequeueInterceptor().after(this);
        return elements;
    }

    public Object[] dequeueAll()
    {
        getDequeueInterceptor().before(this);
        Object[] elements = EMPTY_ARRAY;

        try
        {
            if( m_mutex.attempt( m_timeout ) )
            {
                try
                {
                    elements = retrieveElements( m_elements, size() );
                }
                finally
                {
                    m_mutex.release();
                }
            }
        }
        catch( InterruptedException ie )
        {
            // TODO: exception hanlding
        }

        getDequeueInterceptor().after(this);
        return elements;
    }

    /**
     * Removes the given number of elements from the given <code>buf</code>
     * and returns them in an array. Trusts the caller to pass in a buffer
     * full of <code>Object</code>s and with at least
     * <code>count</code> elements available.
     * <p>
     * @param buf to remove elements from, the caller is responsible
     *            for synchronizing access
     * @param count number of elements to remove/return
     * @return requested number of elements
     */
    private static Object[] retrieveElements( Buffer buf, int count )
    {
        Object[] elements = new Object[ count ];

        for( int i = 0; i < count; i++ )
        {
            elements[ i ] = buf.remove();
        }

        return elements;
    }

    public Object dequeue()
    {
        getDequeueInterceptor().before(this);
        Object element = null;

        try
        {
            if( m_mutex.attempt( m_timeout ) )
            {
                try
                {
                    if( size() > 0 )
                    {
                        element = m_elements.remove();
                    }
                }
                finally
                {
                    m_mutex.release();
                }
            }
        }
        catch( InterruptedException ie )
        {
            // TODO: exception handling
        }

        getDequeueInterceptor().after(this);
        return element;
    }

    private static final class DefaultPreparedEnqueue implements PreparedEnqueue
    {
        private final DefaultQueue m_parent;
        private Object[] m_elements;

        private DefaultPreparedEnqueue( DefaultQueue parent, Object[] elements )
        {
            m_parent = parent;
            m_elements = elements;
            m_parent.m_reserve += elements.length;
        }

        public void commit()
        {
            if( null == m_elements )
            {
                throw new IllegalStateException( "This PreparedEnqueue has already been processed!" );
            }

            try
            {
                m_parent.m_reserve -= m_elements.length;
                m_parent.enqueue( m_elements );
                m_elements = null;
            }
            catch( Exception e )
            {
                throw new IllegalStateException( "Default enqueue did not happen--should be impossible" );
                // will never happen
            }
        }

        public void abort()
        {
            if( null == m_elements )
            {
                throw new IllegalStateException( "This PreparedEnqueue has already been processed!" );
            }

            m_parent.m_reserve -= m_elements.length;
            m_elements = null;
        }
    }
}
TOP

Related Classes of org.apache.excalibur.event.impl.DefaultQueue$DefaultPreparedEnqueue

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.