View Javadoc

1   /*
2    * Copyright (c) 1998, 2005 Gargoyle Software Inc. All rights reserved.
3    *
4    * Redistribution and use in source and binary forms, with or without
5    * modification, are permitted provided that the following conditions are met:
6    *
7    * 1. Redistributions of source code must retain the above copyright notice,
8    *    this list of conditions and the following disclaimer.
9    * 2. Redistributions in binary form must reproduce the above copyright notice,
10   *    this list of conditions and the following disclaimer in the documentation
11   *    and/or other materials provided with the distribution.
12   * 3. The end-user documentation included with the redistribution, if any, must
13   *    include the following acknowledgment:
14   *
15   *       "This product includes software developed by Gargoyle Software Inc.
16   *        (http://www.GargoyleSoftware.com/)."
17   *
18   *    Alternately, this acknowledgment may appear in the software itself, if
19   *    and wherever such third-party acknowledgments normally appear.
20   * 4. The name "Gargoyle Software" must not be used to endorse or promote
21   *    products derived from this software without prior written permission.
22   *    For written permission, please contact info@GargoyleSoftware.com.
23   * 5. Products derived from this software may not be called "GSBase", nor may
24   *    "GSBase" appear in their name, without prior written permission of
25   *    Gargoyle Software Inc.
26   *
27   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
28   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
29   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARGOYLE
30   * SOFTWARE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
31   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
33   * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
36   * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37   */
38  package com.gargoylesoftware.base.trace;
39  
40  import com.gargoylesoftware.base.util.DetailedIllegalArgumentException;
41  import com.gargoylesoftware.base.util.DetailedNullPointerException;
42  import java.io.Serializable;
43  
44  /***
45   * <p style="color: orange">Internal use only.</p>.
46   * <p>A circular queue with blocking semantics.</p>
47   *
48   * @version  $Revision: 1.8 $
49   * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
50   */
51  public class BlockingCircularQueue
52           implements
53          Serializable {
54  
55      // Required for serialization - do not remove or modify
56      private static final long serialVersionUID = 2206052328240171051L;
57  
58      // Locks for blocking on add/next
59      private final Object getLock_ = new Object();
60      private final Object addLock_ = new Object();
61  
62      // The actual storage
63      private final Object queue_[];
64  
65      private final int capacity_;
66      private int size_;
67  
68      // Objects get added to the front and removed from the back
69      private int front_;
70      private int back_;
71  
72  
73      /***
74       *  Create the queue with a capacity of 20
75       */
76      public BlockingCircularQueue() {
77          this( 20 );
78      }
79  
80  
81  
82      /***
83       *  Create the queue with the specified capacity
84       *
85       *@param  capacity The size of the queue
86       */
87      public BlockingCircularQueue( final int capacity ) {
88          queue_ = new Object[capacity];
89          capacity_ = capacity;
90          if( capacity < 2 ) {
91              throw new DetailedIllegalArgumentException( "capacity", capacity, "Must be larger than two" );
92          }
93      }
94  
95  
96      /***
97       *  Remove all items from the queue
98       */
99      public synchronized void clear() {
100         front_ = 0;
101         back_ = 0;
102         size_ = 0;
103 
104         // Remove any current object references so that they can be
105         // garbage collected.
106         int i;
107         for( i = 0; i < capacity_; i++ ) {
108             queue_[i] = null;
109         }
110     }
111 
112 
113     /***
114      *  Add an object to the queue. If the collection is currently full then
115      *  block until an object is removed.
116      *
117      * @param object The object to add.
118      * @return true if the object was successfully added.
119      */
120     public boolean add( final Object object ) {
121         assertNotNull( "object", object );
122         while( true ) {
123             synchronized( this ) {
124                 if( size_ != capacity_ ) {
125                     if( size_ == 0 ) {
126                         front_ = 0;
127                         back_ = 0;
128                     }
129                     else {
130                         front_ = incrementPosition( front_ );
131                     }
132                     queue_[front_] = object;
133                     synchronized( getLock_ ) {
134                         getLock_.notify();
135                     }
136                     size_++;
137                     return true;
138                 }
139             }
140             synchronized( addLock_ ) {
141                 try {
142                     addLock_.wait();
143                 }
144                 catch( final InterruptedException e ) {
145                     //TODO: We should be doing something here
146                 }
147             }
148         }
149     }
150 
151 
152     /***
153      *  Return the next item in the queue. The returned item is removed from the
154      *  collection. If no objects are present then block until an object has
155      *  been added.
156      *
157      * @return The next item.
158      */
159     public Object next() {
160         while( true ) {
161             // If there's something in the queue then return it now.
162             synchronized( this ) {
163                 if( isEmpty() == false ) {
164                     final Object object = queue_[back_];
165                     queue_[back_] = null;// help the garbage collector
166                     back_ = incrementPosition( back_ );
167                     synchronized( addLock_ ) {
168                         addLock_.notify();
169                     }
170                     size_--;
171                     return object;
172                 }
173             }
174             // There wasn't anything in the queue.  Block until something gets added.
175             synchronized( getLock_ ) {
176                 try {
177                     getLock_.wait();
178                 }
179                 catch( InterruptedException e ) {
180                     //TODO: Do something here
181                 }
182             }
183         }
184     }
185 
186 
187     /***
188      *  Utility method to increment the position and roll back to zero once we
189      *  hit the end. Return the new position after the adjustment.
190      * @param position The position to increment
191      * @return the new position
192      */
193     private int incrementPosition( final int position ) {
194         if( ( position < 0 ) || ( position >= capacity_ ) ) {
195             throw new DetailedIllegalArgumentException(
196                     "position", new Integer( position ), "Must be within 1 and " + capacity_ );
197         }
198         int newPosition = position + 1;
199         if( newPosition == capacity_ ) {
200             newPosition = 0;
201         }
202         return newPosition;
203     }
204 
205 
206     /***
207      *  Return the number of objects currently in the collection.
208      * @return The object count.
209      */
210     public int size() {
211         return size_;
212     }
213 
214 
215     /***
216      *  Return true if the collection is empty.
217      * @return true if the collection is empty.
218      */
219     public boolean isEmpty() {
220         return size_ == 0;
221     }
222 
223 
224     /***
225      *  Return a string representation of this object.
226      * @return a string representation of this object.
227      */
228     public String toString() {
229         final StringBuffer buffer = new StringBuffer();
230         buffer.append( getClass().getName() );
231         buffer.append( ": capacity_=" );
232         buffer.append( capacity_ );
233         buffer.append( " size_=" );
234         buffer.append( size_ );
235         buffer.append( " front_=" );
236         buffer.append( front_ );
237         buffer.append( " back_=" );
238         buffer.append( back_ );
239         return buffer.toString();
240     }
241 
242 
243     /***
244      *  Verify that the specified value is not null. If it is then throw an
245      *  exception
246      *
247      *@param  fieldName                         The name of the field to check
248      *@param  fieldValue                        The value of the field to check
249      *@exception  DetailedNullPointerException  If fieldValue is null
250      */
251     protected final void assertNotNull( final String fieldName, final Object fieldValue )
252              throws DetailedNullPointerException {
253         if( fieldValue == null ) {
254             throw new DetailedNullPointerException( fieldName );
255         }
256     }
257 }
258