|
|||||||||||||||||||
Source file | Conditionals | Statements | Methods | TOTAL | |||||||||||||||
BlockingCircularQueue.java | 0% | 0% | 0% | 0% |
|
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 | 0 | public BlockingCircularQueue() { |
77 | 0 | 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 | 0 | public BlockingCircularQueue( final int capacity ) { |
88 | 0 | queue_ = new Object[capacity]; |
89 | 0 | capacity_ = capacity; |
90 | 0 | if( capacity < 2 ) { |
91 | 0 | throw new DetailedIllegalArgumentException( "capacity", capacity, "Must be larger than two" ); |
92 | } | |
93 | } | |
94 | ||
95 | ||
96 | /** | |
97 | * Remove all items from the queue | |
98 | */ | |
99 | 0 | public synchronized void clear() { |
100 | 0 | front_ = 0; |
101 | 0 | back_ = 0; |
102 | 0 | size_ = 0; |
103 | ||
104 | // Remove any current object references so that they can be | |
105 | // garbage collected. | |
106 | 0 | int i; |
107 | 0 | for( i = 0; i < capacity_; i++ ) { |
108 | 0 | 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 | 0 | public boolean add( final Object object ) { |
121 | 0 | assertNotNull( "object", object ); |
122 | 0 | while( true ) { |
123 | 0 | synchronized( this ) { |
124 | 0 | if( size_ != capacity_ ) { |
125 | 0 | if( size_ == 0 ) { |
126 | 0 | front_ = 0; |
127 | 0 | back_ = 0; |
128 | } | |
129 | else { | |
130 | 0 | front_ = incrementPosition( front_ ); |
131 | } | |
132 | 0 | queue_[front_] = object; |
133 | 0 | synchronized( getLock_ ) { |
134 | 0 | getLock_.notify(); |
135 | } | |
136 | 0 | size_++; |
137 | 0 | return true; |
138 | } | |
139 | } | |
140 | 0 | synchronized( addLock_ ) { |
141 | 0 | try { |
142 | 0 | 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 | 0 | public Object next() { |
160 | 0 | while( true ) { |
161 | // If there's something in the queue then return it now. | |
162 | 0 | synchronized( this ) { |
163 | 0 | if( isEmpty() == false ) { |
164 | 0 | final Object object = queue_[back_]; |
165 | 0 | queue_[back_] = null;// help the garbage collector |
166 | 0 | back_ = incrementPosition( back_ ); |
167 | 0 | synchronized( addLock_ ) { |
168 | 0 | addLock_.notify(); |
169 | } | |
170 | 0 | size_--; |
171 | 0 | return object; |
172 | } | |
173 | } | |
174 | // There wasn't anything in the queue. Block until something gets added. | |
175 | 0 | synchronized( getLock_ ) { |
176 | 0 | try { |
177 | 0 | 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 | 0 | private int incrementPosition( final int position ) { |
194 | 0 | if( ( position < 0 ) || ( position >= capacity_ ) ) { |
195 | 0 | throw new DetailedIllegalArgumentException( |
196 | "position", new Integer( position ), "Must be within 1 and " + capacity_ ); | |
197 | } | |
198 | 0 | int newPosition = position + 1; |
199 | 0 | if( newPosition == capacity_ ) { |
200 | 0 | newPosition = 0; |
201 | } | |
202 | 0 | return newPosition; |
203 | } | |
204 | ||
205 | ||
206 | /** | |
207 | * Return the number of objects currently in the collection. | |
208 | * @return The object count. | |
209 | */ | |
210 | 0 | public int size() { |
211 | 0 | return size_; |
212 | } | |
213 | ||
214 | ||
215 | /** | |
216 | * Return true if the collection is empty. | |
217 | * @return true if the collection is empty. | |
218 | */ | |
219 | 0 | public boolean isEmpty() { |
220 | 0 | 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 | 0 | public String toString() { |
229 | 0 | final StringBuffer buffer = new StringBuffer(); |
230 | 0 | buffer.append( getClass().getName() ); |
231 | 0 | buffer.append( ": capacity_=" ); |
232 | 0 | buffer.append( capacity_ ); |
233 | 0 | buffer.append( " size_=" ); |
234 | 0 | buffer.append( size_ ); |
235 | 0 | buffer.append( " front_=" ); |
236 | 0 | buffer.append( front_ ); |
237 | 0 | buffer.append( " back_=" ); |
238 | 0 | buffer.append( back_ ); |
239 | 0 | 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 | 0 | protected final void assertNotNull( final String fieldName, final Object fieldValue ) |
252 | throws DetailedNullPointerException { | |
253 | 0 | if( fieldValue == null ) { |
254 | 0 | throw new DetailedNullPointerException( fieldName ); |
255 | } | |
256 | } | |
257 | } | |
258 |
|