1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
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
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
151
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
164
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
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
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
198 if (actIndex == 0) { return null; }
199
200
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
217 if (endPoint == -1) { return null; }
218
219
220 if (actIndex == endPoint) { return null; }
221
222
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
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 }