ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/experimental/server/Queue/Queue.java
Revision: 1.3
Committed: Tue Jan 2 01:50:17 2001 UTC (23 years, 11 months ago) by tdb
Branch: MAIN
Changes since 1.2: +71 -79 lines
Log Message:
Added support for the dynamic creation of queues upon request. Makes the
whole system more flexible, and hopefully will allow for the starting and stopping
of components within the system.

File Contents

# User Rev Content
1 tdb 1.2 //---PACKAGE DECLARATION---
2    
3     //---IMPORTS---
4 tdb 1.1 import java.util.LinkedList;
5     import java.util.NoSuchElementException;
6 tdb 1.2 //import uk.ac.ukc.iscream.util.*;
7 tdb 1.1
8 tdb 1.2 /**
9     * A Queue class designed to operate in a multi-threaded environment, with
10     * added support for multiple "consumer" threads. Also offers blocking on
11     * the get() methods, which ensures the consumer waits until the queue
12     * actually contains some elements.
13     *
14 tdb 1.3 * @author $Author: tdb1 $
15     * @version $Id: Queue.java,v 1.2 2000/12/28 03:49:15 tdb1 Exp $
16 tdb 1.2 */
17 tdb 1.1 class Queue {
18 tdb 1.2
19     //---FINAL ATTRIBUTES---
20    
21     /**
22     * The current CVS revision of this class
23     */
24 tdb 1.3 public static final String REVISION = "$Revision: 1.2 $";
25 tdb 1.2
26     //---STATIC METHODS---
27    
28 tdb 1.3 //---CONSTRUCTORS---
29    
30 tdb 1.2 //---PUBLIC METHODS---
31    
32     /**
33     * This method adds a given object to every queue. It will notify
34     * any waiting consumers (on an empty queue) during this process.
35     *
36     * @param o An Object to be added to the queues.
37     */
38     public void add(Object o) {
39 tdb 1.3 for(int i=0; i < _lists.size(); i++) {
40     // skip over any gaps left in the list
41     if(_lists.get(i) != null) {
42     int s = ((LinkedList) _lists.get(i)).size();
43     synchronized(this) {
44     // add() does the same thing, but this ensures behaviour
45     ((LinkedList) _lists.get(i)).addLast(o);
46     }
47     // if the queue was empty before the add it is possible
48     // that a consumer is waiting... so we notify them
49     if (s == 0) {
50     synchronized(((LinkedList) _lists.get(i))) {
51     ((LinkedList) _lists.get(i)).notifyAll();
52     }
53 tdb 1.2 }
54     }
55 tdb 1.1 }
56 tdb 1.2 // we keep track of the total additions for the status() method
57 tdb 1.1 _count++;
58     }
59    
60 tdb 1.2 /**
61     * This method returns an object from the front of a given queue.
62     * It will block until data exists in the queue if required.
63     *
64     * @return The object from the front of the queue.
65 tdb 1.3 * @throws InvalidQueueException if the queue does not exist.
66 tdb 1.2 */
67 tdb 1.3 public Object get(int queue) throws InvalidQueueException {
68     // make sure queue exists
69     if (queue >= _lists.size() || _lists.get(queue) == null) {
70     throw new InvalidQueueException("Requested queue "+queue+" does not exist");
71     }
72 tdb 1.2 // block if the queue is empty
73 tdb 1.3 if (((LinkedList) _lists.get(queue)).size() == 0) {
74     synchronized(((LinkedList) _lists.get(queue))) {
75     try { ((LinkedList) _lists.get(queue)).wait(); } catch(Exception e) {}
76 tdb 1.2 }
77 tdb 1.1 }
78 tdb 1.2 // get an item, it should never be null due to the blocking above
79 tdb 1.1 Object o = null;
80 tdb 1.2 synchronized(this) {
81     try {
82 tdb 1.3 o = ((LinkedList) _lists.get(queue)).removeFirst();
83 tdb 1.2 }
84     catch (NoSuchElementException e) {
85     // This should never happen !
86     }
87 tdb 1.1 }
88     return o;
89     }
90 tdb 1.3
91 tdb 1.2 /**
92     * This method returns a textual status of the queues. It
93     * is merely for observation, and would most likely be used
94     * by a larger "monitoring" component. Information returned
95     * includes the current size of each queue, and the total
96     * items passed through.
97     *
98     * @return A String message containing status information.
99     */
100 tdb 1.1 public String status() {
101     String status = "";
102 tdb 1.3 for(int i=0; i < _lists.size(); i++) {
103     // check for null entries
104     if(_lists.get(i) != null) {
105     status += "Queue number "+i+" contains "+((LinkedList) _lists.get(i)).size()+" elements";
106     status += "\n";
107     }
108     else {
109     status += "Slot number "+i+" is currently empty";
110     status += "\n";
111     }
112 tdb 1.2 }
113     status += "A total of "+_count+" elements have been added to the queues";
114 tdb 1.1 return status;
115     }
116    
117 tdb 1.2 /**
118     * This method assigns a queue to a consumer. The idea behind
119     * this is to ensure that only 1 consumer can be associated with
120     * a given queue, otherwise the whole "blocking" thing fails
121 tdb 1.3 * miserably. Queues are created upon requested.
122     *
123     * It is IMPORTANT that removeQueue() is used when the queue is
124     * no longer required.
125 tdb 1.2 *
126     * @return An integer to be passed to the get() method.
127     */
128 tdb 1.3 public int getQueue() {
129     int pos = -1;
130     for(int i=0; i < _lists.size(); i++) {
131     if(_lists.get(i) == null) {
132     // found a gap, re-use it
133     pos = i;
134     _lists.set(i, new LinkedList());
135     }
136 tdb 1.2 }
137 tdb 1.3 if(pos == -1) {
138     //we didn't find a gap, add at end
139     pos = _lists.size();
140     _lists.add(pos, new LinkedList());
141 tdb 1.2 }
142 tdb 1.3 return pos;
143 tdb 1.2 }
144 tdb 1.3
145     /**
146     * This method sets a entry to null in the list. This ensures
147     * that it will no longer be added to after it is no longer
148     * required be a consumer.
149     *
150     * @param queue The integer identifier for the queue, given by getQueue().
151     */
152     public void removeQueue(int queue) {
153     _lists.set(queue, null);
154     }
155    
156 tdb 1.2 /**
157     * Overrides the {@link java.lang.Object#toString() Object.toString()}
158     * method to provide clean logging (every class should have this).
159     *
160     * This uses the uk.ac.ukc.iscream.util.FormatName class
161     * to format the toString()
162     *
163     * @return the name of this class and its CVS revision
164     */
165     /*public String toString() {
166     return FormatName.getName(
167     _name,
168     getClass().getName(),
169     REVISION);
170     }*/
171    
172     //---PRIVATE METHODS---
173    
174     //---ACCESSOR/MUTATOR METHODS---
175    
176     //---ATTRIBUTES---
177    
178     /**
179 tdb 1.3 * The LinkedLists of queues.
180 tdb 1.2 */
181 tdb 1.3 private LinkedList _lists = new LinkedList();
182 tdb 1.2
183     /**
184     * A counter so we know how many data items have been
185     * passed through, for statistical purposes.
186     */
187     private int _count = 0;
188    
189     /**
190     * This is the friendly identifier of the
191     * component this class is running in.
192     * eg, a Filter may be called "filter1",
193     * If this class does not have an owning
194     * component, a name from the configuration
195     * can be placed here. This name could also
196     * be changed to null for utility classes.
197     */
198     //private String _name = <!THIS SHOULD CALL A STATIC NAME IN THE COMPONENT CLASS FOR THIS OBJECT!>;
199    
200     /**
201     * This holds a reference to the
202     * system logger that is being used.
203     */
204     //private Logger _logger = ReferenceManager.getInstance().getLogger();
205    
206     //---STATIC ATTRIBUTES---
207    
208     }