View Javadoc

1   /*
2    * $Revision: 1.3 $
3    * $Date: 2006/02/28 18:33:34 $
4    *
5    * ====================================================================
6    * Struts back mechanism
7    * Copyright (C) 2006 - Manfred Wolff
8    * 
9    * Licensed under the Apache License, Version 2.0 (the "License");
10   * you may not use this file except in compliance with the License.
11   * You may obtain a copy of the License at
12   * 
13   *      http://www.apache.org/licenses/LICENSE-2.0
14   * 
15   * Unless required by applicable law or agreed to in writing, software
16   * distributed under the License is distributed on an "AS IS" BASIS,
17   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18   * See the License for the specific language governing permissions and
19   * limitations under the License.
20   *
21   * created: 21-01-2006 Manfred Wolff (wolff@mwolff.org)
22   */
23  package org.mwolff.struts.back;
24  
25  import java.util.ArrayList;
26  import java.util.Iterator;
27  
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  
31  /***
32   * A Ringbuffer is a buffer to store something (in this case ArrayEntries). 
33   * This buffer is made for the stuts back mechanism. Its supports also a 
34   * wizzard manner to go back and forward more steps. This implementation 
35   * simulates a ringbuffer. The Buffer has the following invariants:
36   * <ul>
37   * <li>The actIndex pointer shows to the act index to be shown.</li>
38   * <li>All Entries from startPoint to endPoint are valid entries if both 
39   *     pointers are >= 0.</li>
40   * <li>If maxindex is reached the first index will be overide and the overflow 
41   *     flag is set.</li>
42   * </ul>
43   * Example: startPoint = 0; endPoint = 5; actIndex = 4;
44   * <ol>
45   * <li>There are 6 valid entries from 0 to 5.</li>
46   * <li>The actal index ist 4. So you can go forward 1 entry and you can go 
47   *     backword 4 entries.</li>
48   * <li>A New Entry will be inserted on index 6, the endpoint will be increased
49   * </ol>
50   * 
51   * @since 1.0
52   * @author <a href="mailto:wolff@mwolff.org">Manfred Wolff </a>
53   */
54  public class RingBuffer {
55  
56      /*** The maximum length of the ringbuffer */
57      private int maxEntries = 40;
58      /*** The ringbuffer itselfs */
59      private final ArrayList ringBuffer;
60      /*** The Startpoint of the ringbuffer */
61      // private int startPoint = -1;
62      /*** The Endpoint of the ringbuffer */
63      private int endPoint = -1;
64      /*** The pointer of the act index */
65      private int actIndex = -1;
66      /*** Sign that ringbuffer is overflowed */
67      private boolean overflow;
68      /*** Sign that back or forward is set */
69      private boolean noPush;
70      /*** Sign that back or forwardaction were involved */
71      private boolean wereInvolved;
72  
73      /***
74       * <p>
75       * Commons Logging instance.
76       * </p>
77       */
78      protected static Log log = LogFactory.getLog(RingBuffer.class);
79  
80      /***
81       * Constructor with default entries (40).
82       */
83      public RingBuffer() {
84          super();
85          ringBuffer = new ArrayList();
86      }
87  
88      /***
89       * Constructor with an amount of entries.
90       * 
91       * @param maxEntries Entries of the ringbuffer.
92       */
93      public RingBuffer(int maxEntries) {
94          super();
95          this.maxEntries = maxEntries;
96          ringBuffer = new ArrayList();
97      }
98  
99      public boolean isForwardPossible() {
100         return (actIndex < endPoint);
101     }
102     
103     public boolean isBackPossible() {
104         return (actIndex > 0);
105     }
106     
107     public void print() {
108 
109         if (log.isInfoEnabled()) {
110             log.info("========= printing queue status ====================");
111             int index = 0;
112             for (Iterator it = ringBuffer.iterator(); it.hasNext();) {
113                 ArrayEntry entry = (ArrayEntry) it.next();
114                 if (log.isInfoEnabled()) {
115                     log.info("Index " + index++ + " = " + entry.getValue());
116                 }
117             }
118             log.info("The actual index is : " + actIndex);
119             log.info("The end index is    : " + endPoint);
120             log.info("========= END printing queue status ================");
121         }
122 
123     }
124 
125     /***
126      * Clears the buffer
127      */
128     public void clear() {
129         ringBuffer.clear();
130         // startPoint = -1;
131         endPoint = -1;
132         actIndex = -1;
133     }
134 
135     /***
136      * @return The maximal entries of the buffer.
137      */
138     public int size() {
139         return ringBuffer.size();
140     }
141 
142     /***
143      * Pushes an entry into the ringbuffer.
144      * 
145      * @param entry The entry to be pushed
146      * @return The actual index of the ringbuffer
147      */
148     public int push(ArrayEntry entry) {
149 
150         // Removes the first entry if necessary (overflow). If the actindex is 
151         // the last entry, correct it.
152         if (ringBuffer.size() == this.maxEntries) {
153             if (log.isInfoEnabled()) {
154                 log.info("Overflow, removing last entry.");
155             }
156             ringBuffer.remove(0);
157             if (actIndex == (ringBuffer.size())) {
158                 actIndex = (ringBuffer.size() - 1);
159             }
160             overflow = true;
161         }
162 
163         // If the index pointer is not the last entry, delete all
164         // entries above the index pointer !
165         if ((ringBuffer.size() > 0) && (actIndex != (ringBuffer.size() - 1))) {
166             if (log.isInfoEnabled()) {
167                 log.info("Correcting entries between index and end of buffer.");
168             }
169             while (actIndex != ringBuffer.size() - 1) {
170                 ringBuffer.remove(ringBuffer.size() - 1);
171             }
172         }
173 
174         // Adds the entry at the end of the buffer
175         ringBuffer.add(entry);
176         if (log.isInfoEnabled()) {
177             log.info("Pushed one entry " + entry.getValue() + ".");
178         }
179         if (actIndex == -1) {
180             actIndex = 0;
181             // startPoint = 0;
182         } else {
183             actIndex = ringBuffer.size() - 1;
184         }
185 
186         endPoint = actIndex;
187         return actIndex;
188     }
189 
190     /***
191      * Goes one entry back into the ringbuffer.
192      * 
193      * @return The entry back
194      */
195     public ArrayEntry back() {
196 
197         // There must be entries in the buffer
198         if (actIndex == 0) { return null; }
199 
200         // the index might not be 0
201         if (actIndex > 0) {
202             actIndex--;
203             setNoPush(true);
204         }
205 
206         return (ArrayEntry) ringBuffer.get(actIndex);
207     }
208 
209     /***
210      * Goes one entry forward in the ringbuffer.
211      * 
212      * @return The entry forward
213      */
214     public ArrayEntry forward() {
215 
216         // There must exists an endpoint
217         if (endPoint == -1) { return null; }
218 
219         // Forward only to the endpoint
220         if (actIndex == endPoint) { return null; }
221 
222         // the index might not be 0
223         if (actIndex < endPoint) {
224             actIndex++;
225             setNoPush(true);
226         }
227 
228         return (ArrayEntry) ringBuffer.get(actIndex);
229     }
230 
231     /***
232      * Returns the last pushed entry.
233      * 
234      * @return The last pushed entry
235      */
236     public ArrayEntry getLastPushed() {
237         // size > 0
238         if (ringBuffer.size() > 0) { return (ArrayEntry) ringBuffer
239             .get(ringBuffer.size() - 1); }
240         return null;
241     }
242     
243     public ArrayEntry getActIndex() {
244         if (ringBuffer.size() > 0) { return (ArrayEntry) ringBuffer
245             .get(actIndex); }
246         return null;
247     }
248 
249     /***
250      * Returns the overflow bit.
251      * 
252      * @return the overflow bit.
253      */
254     public boolean isOverflow() {
255         return overflow;
256     }
257 
258     /***
259      * Returns the NoPush Flag.
260      * 
261      * @return The NoPush Flag.
262      */
263     public boolean isNoPush() {
264         return noPush;
265     }
266 
267     /***
268      * Sets the NoPush Flag.
269      * 
270      * @param noPush The NoPush Flag.
271      */
272     public void setNoPush(boolean noPush) {
273         this.noPush = noPush;
274     }
275 
276     /***
277      * Returns the WereInvolved Flag.
278      * 
279      * @return The WereInvolved Flag.
280      */
281     public boolean isWereInvolved() {
282         return wereInvolved;
283     }
284 
285     /***
286      * Sets the WereInvolved Flag.
287      * 
288      * @param wereInvolved The WereInvolved Flag.
289      */
290     public void setWereInvolved(boolean wereInvolved) {
291         this.wereInvolved = wereInvolved;
292     }
293 }