View Javadoc

1   package org.mortbay.util;
2   
3   import java.util.Iterator;
4   import java.util.NoSuchElementException;
5   
6   import org.mortbay.util.ArrayQueue;
7   
8   public class ArrayIdQueue<E> extends ArrayQueue<E>
9   {
10      private long[] _ids;
11      private long _currentId;
12      private int _unacked;
13      private int _cursor;
14  
15      /* ------------------------------------------------------------ */
16      public ArrayIdQueue()
17      {
18          super();
19          _ids=new long[DEFAULT_CAPACITY];
20      }
21  
22      /* ------------------------------------------------------------ */
23      public ArrayIdQueue(int capacity)
24      {
25          super(capacity);
26          _ids=new long[capacity];
27      }
28  
29      /* ------------------------------------------------------------ */
30      public ArrayIdQueue(int initCapacity, int growBy)
31      {
32          super(initCapacity,growBy);
33          _ids=new long[initCapacity];
34      }
35  
36      /* ------------------------------------------------------------ */
37      public ArrayIdQueue(int initCapacity, int growBy, Object lock)
38      {
39          super(initCapacity,growBy,lock);
40          _ids=new long[initCapacity];
41      }
42  
43      /**
44       * @param unacked marks which messages have been sent, and are awaiting a
45       * response. The index is the first message that has not yet been sent
46       */
47      /* ------------------------------------------------------------ */
48      public int getUnackedIndex()
49      {
50          return _unacked;
51      }
52  
53      /* ------------------------------------------------------------ */
54      public void incrementUnackedIndex()
55      {
56          _unacked++;
57      }
58  
59      /* ------------------------------------------------------------ */
60      public void decrementUnackedIndex()
61      {
62          _unacked--;
63      }
64  
65      /* ------------------------------------------------------------ */
66      /**
67       * @return currentId the latest batch that has been sent to the client
68       */
69      public long getCurrentId()
70      {
71          return _currentId;
72      }
73      
74      public void setCurrentId(int currentId)
75      {
76          _currentId=currentId;
77      }
78  
79      public void incrementCurrentId()
80      {
81          _currentId++;
82      }
83  
84      /* ------------------------------------------------------------ */
85      public boolean add(E e)
86      {
87          synchronized (_lock)
88          {
89              int nextSlot=_nextSlot;
90              super.add(e);
91              _ids[nextSlot]=_currentId;
92          }
93          return true;
94      }
95  
96      /* ------------------------------------------------------------ */
97      public void addUnsafe(E e)
98      {
99          int nextSlot=_nextSlot;
100         super.addUnsafe(e);
101         _ids[nextSlot]=_currentId;
102 
103     }
104 
105     /* ------------------------------------------------------------ */
106     public boolean offer(E e)
107     {
108         int nextSlot = _nextSlot;
109         int nextE = _nextE;
110         
111         _ids[nextSlot]=_currentId;
112         
113         boolean offer = super.offer(e);
114         if(!offer) return false;
115         
116         long[] ids=new long[_elements.length];
117 
118         int split=_ids.length-nextE;
119         if (split>0)
120             System.arraycopy(_ids,nextE,ids,0,split);
121         if (nextE!=0)
122             System.arraycopy(_ids,0,ids,split,nextSlot);
123 
124         _ids=ids;
125 
126         return offer;
127 
128     }
129 
130     /* ------------------------------------------------------------ */
131     public long getAssociatedId(int index)
132     {
133         synchronized(_lock)
134         {
135             if (index<0 || index>=_size)
136                 throw new IndexOutOfBoundsException("!("+0+"<"+index+"<="+_size+")");
137             int i = _nextE+index;
138             if (i>=_ids.length)
139                 i-=_ids.length;
140             return _ids[i];
141         }
142     }
143 
144     /* ------------------------------------------------------------ */
145     public long getAssociatedIdUnsafe(int index)
146     {
147         int i = _nextE+index;
148         if (i>=_ids.length)
149             i-=_ids.length;
150         return _ids[i];
151     }
152 
153     /* ------------------------------------------------------------ */
154     public E remove(int index)
155     {
156         synchronized(_lock)
157         {
158             int nextSlot = _nextSlot;
159             E e = super.remove(index);
160 
161             int i = _nextE+index;
162             if (i>=_ids.length)
163                 i-=_ids.length;
164             
165             if (i<nextSlot)
166             {
167                 System.arraycopy(_ids,i+1,_ids,i,nextSlot-i);
168                 nextSlot--;
169             }
170             else
171             {
172                 System.arraycopy(_ids,i+1,_ids,i,_ids.length-1);
173                 if (nextSlot>0)
174                 {
175                     _ids[_ids.length]=_ids[0];
176                     System.arraycopy(_ids,1,_ids,0,nextSlot-1);
177                     nextSlot--;
178                 }
179                 else
180                     nextSlot=_ids.length-1;
181 
182             }
183             
184             return e;
185         }
186     }
187 
188     /* ------------------------------------------------------------ */
189     public E set(int index, E element)
190     {
191         synchronized(_lock)
192         {
193             E old = super.set(index, element);
194 
195             int i = _nextE+index;
196             if (i>=_ids.length)
197                 i-=_ids.length;
198             // TODO: what if the id is not meant to be the latest? 
199             _ids[i]=_currentId;
200             return old;
201         }
202     }
203     
204     /* ------------------------------------------------------------ */
205     public void add(int index, E element)
206     {
207         synchronized(_lock)
208         {
209             int nextSlot = _nextSlot;
210             super.add(index, element);
211             
212             if (index==_size)
213             {
214                 _ids[index] = _currentId;
215             }
216             else
217             {
218                 int i = _nextE+index;
219                 if (i>=_ids.length)
220                     i-=_ids.length;
221 
222                 if (i<nextSlot)
223                 {
224                     System.arraycopy(_ids,i,_ids,i+1,nextSlot-i);
225                     _ids[i]=_currentId;
226                 }
227                 else
228                 {
229                     if (nextSlot>0)
230                     {
231                         System.arraycopy(_ids,0,_ids,1,nextSlot);
232                         _ids[0]=_ids[_ids.length-1];
233                     }
234 
235                     System.arraycopy(_ids,i,_ids,i+1,_ids.length-i-1);
236                     _ids[i]=_currentId;
237                 }
238             }
239         }
240     }
241 
242     public E get(int index)
243     {
244         _cursor = index;
245         return super.get(index);
246     }
247     
248     protected void grow()
249     {
250         int nextE=_nextE;
251         int nextSlot=_nextSlot;
252 
253         super.grow();
254 
255         long[] Ids=new long[_elements.length];
256         int split=_ids.length - nextE;
257         if (split > 0)
258             System.arraycopy(_ids,nextE,Ids,0,split);
259         if (nextE != 0)
260             System.arraycopy(_ids,0,Ids,split,nextSlot);
261 
262         _ids=Ids;
263     }
264     
265     
266     /**
267      * @return idIterator an iterator over the associated ids
268      */
269     public ArrayIdIterator idIterator()
270     {
271         return new ArrayIdIterator(iterator());
272     }
273     
274     public class ArrayIdIterator implements Iterator<E> 
275     {
276         private Iterator<E> _iterator;
277         
278         public ArrayIdIterator(Iterator<E> iterator)
279         {
280             _iterator = iterator;
281         }
282 
283         /* ------------------------------------------------------------ */
284         /**
285          * @return the id associated with the current element in the iteration
286          */
287         public long associatedId()
288         {
289             try {
290                 long nextId = ArrayIdQueue.this.getAssociatedId(ArrayIdQueue.this._cursor);
291                 return nextId;
292             } catch(IndexOutOfBoundsException e) {
293                 throw new NoSuchElementException();
294             }            
295         }
296 
297         /* ------------------------------------------------------------ */
298         public long nextId() {
299             try {
300                 next();
301                 long nextId = ArrayIdQueue.this.getAssociatedId(ArrayIdQueue.this._cursor);
302                 return nextId;
303             } catch(IndexOutOfBoundsException e) {
304                 throw new NoSuchElementException();
305             }
306         }
307         
308         /* ------------------------------------------------------------ */        
309         public boolean hasNext()
310         {
311             return _iterator.hasNext();
312         }
313 
314         /* ------------------------------------------------------------ */
315         public E next()
316         {
317             return _iterator.next();
318         }
319 
320         /* ------------------------------------------------------------ */
321         public void remove()
322         {
323             _iterator.remove();
324         }
325     }
326 
327 }