001    /*
002     * Copyright 2003-2004 The Apache Software Foundation
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *     http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.apache.commons.events.observable;
017    
018    import org.apache.commons.collections.Buffer;
019    
020    /**
021     * Decorates a <code>Buffer</code> implementation to observe modifications.
022     * <p>
023     * Each modifying method call made on this <code>Buffer</code> is forwarded to a
024     * {@link ModificationHandler}.
025     * The handler manages the event, notifying listeners and optionally vetoing changes.
026     * The default handler is
027     * {@link org.apache.commons.events.observable.standard.StandardModificationHandler StandardModificationHandler}.
028     * See this class for details of configuration available.
029     *
030     * @since Commons Events 1.0
031     * @version $Revision: 155443 $ $Date: 2005-02-26 13:19:51 +0000 (Sat, 26 Feb 2005) $
032     * 
033     * @author Stephen Colebourne
034     */
035    public class ObservableBuffer extends ObservableCollection implements Buffer {
036        
037        // Factories
038        //-----------------------------------------------------------------------
039        /**
040         * Factory method to create an observable buffer.
041         * <p>
042         * A {@link org.apache.commons.events.observable.standard.StandardModificationHandler} will be created.
043         * This can be accessed by {@link #getHandler()} to add listeners.
044         *
045         * @param buffer  the buffer to decorate, must not be null
046         * @return the observed Buffer
047         * @throws IllegalArgumentException if the buffer is null
048         */
049        public static ObservableBuffer decorate(final Buffer buffer) {
050            return new ObservableBuffer(buffer, null);
051        }
052    
053        /**
054         * Factory method to create an observable buffer using a listener or a handler.
055         * <p>
056         * A lot of functionality is available through this method.
057         * If you don't need the extra functionality, simply implement the
058         * {@link org.apache.commons.events.observable.standard.StandardModificationListener}
059         * interface and pass it in as the second parameter.
060         * <p>
061         * Internally, an <code>ObservableBuffer</code> relies on a {@link ModificationHandler}.
062         * The handler receives all the events and processes them, typically by
063         * calling listeners. Different handler implementations can be plugged in
064         * to provide a flexible event system.
065         * <p>
066         * The handler implementation is determined by the listener parameter via
067         * the registered factories. The listener may be a manually configured 
068         * <code>ModificationHandler</code> instance.
069         * <p>
070         * The listener is defined as an Object for maximum flexibility.
071         * It does not have to be a listener in the classic JavaBean sense.
072         * It is entirely up to the factory and handler as to how the parameter
073         * is interpretted. An IllegalArgumentException is thrown if no suitable
074         * handler can be found for this listener.
075         * <p>
076         * A <code>null</code> listener will create a
077         * {@link org.apache.commons.events.observable.standard.StandardModificationHandler}.
078         *
079         * @param buffer  the buffer to decorate, must not be null
080         * @param listener  buffer listener, may be null
081         * @return the observed buffer
082         * @throws IllegalArgumentException if the buffer is null
083         * @throws IllegalArgumentException if there is no valid handler for the listener
084         */
085        public static ObservableBuffer decorate(
086                final Buffer buffer,
087                final Object listener) {
088            
089            if (buffer == null) {
090                throw new IllegalArgumentException("Buffer must not be null");
091            }
092            return new ObservableBuffer(buffer, listener);
093        }
094    
095        // Constructors
096        //-----------------------------------------------------------------------
097        /**
098         * Constructor that wraps (not copies).
099         * <p>
100         * The handler implementation is determined by the listener parameter via
101         * the registered factories. The listener may be a manually configured 
102         * <code>ModificationHandler</code> instance.
103         * 
104         * @param buffer  the buffer to decorate, must not be null
105         * @param listener  the listener, may be null
106         * @throws IllegalArgumentException if the buffer is null
107         */
108        protected ObservableBuffer(
109                final Buffer buffer,
110                final Object listener) {
111            super(buffer, listener);
112        }
113        
114        /**
115         * Typecast the collection to a Buffer.
116         * 
117         * @return the wrapped collection as a Buffer
118         */
119        private Buffer getBuffer() {
120            return (Buffer) getCollection();
121        }
122    
123        // Buffer API
124        //-----------------------------------------------------------------------
125        public Object get() {
126            return getBuffer().get();
127        }
128    
129        //-----------------------------------------------------------------------
130        public Object remove() {
131            Object result = null;
132            if (handler.preRemoveNext()) {
133                result = getBuffer().remove();
134                handler.postRemoveNext(result);
135            }
136            return result;
137        }
138    
139    }