1 package org.apache.jcs.engine.control.event;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.IOException;
23
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26
27 import org.apache.jcs.engine.control.event.behavior.IElementEventQueue;
28 import org.apache.jcs.engine.control.event.behavior.IElementEventHandler;
29 import org.apache.jcs.engine.control.event.behavior.IElementEvent;
30
31 /***
32 * An event queue is used to propagate ordered cache events to one and only one
33 * target listener.
34 */
35 public class ElementEventQueue
36 implements IElementEventQueue
37 {
38 private final static Log log = LogFactory.getLog( ElementEventQueue.class );
39
40 private static int processorInstanceCount = 0;
41
42 private String cacheName;
43
44 private boolean destroyed = false;
45
46 private Thread t;
47
48
49
50 private Object queueLock = new Object();
51
52
53
54 private Node head = new Node();
55
56 private Node tail = head;
57
58 /***
59 * Constructor for the ElementEventQueue object
60 *
61 * @param cacheName
62 */
63 public ElementEventQueue( String cacheName )
64 {
65
66 this.cacheName = cacheName;
67
68 t = new QProcessor();
69 t.start();
70
71 if ( log.isDebugEnabled() )
72 {
73 log.debug( "Constructed: " + this );
74 }
75 }
76
77 /***
78 * Event Q is emtpy.
79 */
80 public synchronized void destroy()
81 {
82 if ( !destroyed )
83 {
84 destroyed = true;
85
86
87
88
89 synchronized ( queueLock )
90 {
91 t.interrupt();
92 }
93
94 t = null;
95
96 log.info( "Element event queue destroyed: " + this );
97 }
98 }
99
100 /***
101 * @return the region name for the event queue
102 */
103 public String toString()
104 {
105 return "cacheName=" + cacheName;
106 }
107
108 /***
109 * @return The destroyed value
110 */
111 public boolean isAlive()
112 {
113 return ( !destroyed );
114 }
115
116 /***
117 * Adds an ElementEvent to be handled
118 *
119 * @param hand
120 * The IElementEventHandler
121 * @param event
122 * The IElementEventHandler IElementEvent event
123 * @throws IOException
124 */
125 public void addElementEvent( IElementEventHandler hand, IElementEvent event )
126 throws IOException
127 {
128
129 if ( log.isDebugEnabled() )
130 {
131 log.debug( "Adding Event Handler to QUEUE, !destroyed = " + !destroyed );
132 }
133
134 if ( !destroyed )
135 {
136 ElementEventRunner runner = new ElementEventRunner( hand, event );
137
138 if ( log.isDebugEnabled() )
139 {
140 log.debug( "runner = " + runner );
141 }
142
143 put( runner );
144 }
145 }
146
147 /***
148 * Adds an event to the queue.
149 *
150 * @param event
151 */
152 private void put( AbstractElementEventRunner event )
153 {
154 Node newNode = new Node();
155
156 newNode.event = event;
157
158 synchronized ( queueLock )
159 {
160 tail.next = newNode;
161 tail = newNode;
162
163 queueLock.notify();
164 }
165 }
166
167 private AbstractElementEventRunner take()
168 throws InterruptedException
169 {
170 synchronized ( queueLock )
171 {
172
173
174 while ( head == tail )
175 {
176 if ( log.isDebugEnabled() )
177 {
178 log.debug( "Waiting for something to come into the Q" );
179 }
180
181 queueLock.wait();
182
183 if ( log.isDebugEnabled() )
184 {
185 log.debug( "Something came into the Q" );
186 }
187 }
188
189
190
191 Node node = head.next;
192
193 AbstractElementEventRunner value = node.event;
194
195 if ( log.isDebugEnabled() )
196 {
197 log.debug( "head.event = " + head.event );
198 log.debug( "node.event = " + node.event );
199 }
200
201
202
203 node.event = null;
204 head = node;
205
206 return value;
207 }
208 }
209
210
211
212 private static class Node
213 {
214 Node next = null;
215
216 ElementEventQueue.AbstractElementEventRunner event = null;
217 }
218
219 /***
220 */
221 private class QProcessor
222 extends Thread
223 {
224 /***
225 * Constructor for the QProcessor object
226 */
227 QProcessor()
228 {
229 super( "ElementEventQueue.QProcessor-" + ( ++processorInstanceCount ) );
230
231 setDaemon( true );
232 }
233
234 /***
235 * Main processing method for the QProcessor object
236 */
237 public void run()
238 {
239 AbstractElementEventRunner r = null;
240
241 while ( !destroyed )
242 {
243 try
244 {
245 r = take();
246
247 if ( log.isDebugEnabled() )
248 {
249 log.debug( "r from take() = " + r );
250 }
251
252 }
253 catch ( InterruptedException e )
254 {
255
256
257 this.destroy();
258 }
259
260 if ( !destroyed && r != null )
261 {
262 r.run();
263 }
264 }
265
266 log.info( "QProcessor exiting for " + ElementEventQueue.this );
267 }
268 }
269
270 /***
271 * Retries before declaring failure.
272 *
273 */
274 private abstract class AbstractElementEventRunner
275 implements Runnable
276 {
277 /***
278 * Main processing method for the AbstractElementEvent object
279 */
280 public void run()
281 {
282 IOException ex = null;
283
284 try
285 {
286 ex = null;
287 doRun();
288 return;
289
290 }
291 catch ( IOException e )
292 {
293 ex = e;
294 }
295
296
297 if ( ex != null )
298 {
299 log.warn( "Giving up element event handling " + ElementEventQueue.this, ex );
300
301 }
302 return;
303 }
304
305 /***
306 * Description of the Method
307 *
308 * @exception IOException
309 */
310 protected abstract void doRun()
311 throws IOException;
312 }
313
314 /***
315 */
316 private class ElementEventRunner
317 extends AbstractElementEventRunner
318 {
319
320 private IElementEventHandler hand;
321
322 private IElementEvent event;
323
324 /***
325 * Constructor for the PutEvent object
326 * @param hand
327 * @param event
328 * @exception IOException
329 */
330 ElementEventRunner( IElementEventHandler hand, IElementEvent event )
331 throws IOException
332 {
333 if ( log.isDebugEnabled() )
334 {
335 log.debug( "Constructing " + this );
336 }
337 this.hand = hand;
338 this.event = event;
339 }
340
341 /***
342 * Description of the Method
343 *
344 * @exception IOException
345 */
346 protected void doRun()
347 throws IOException
348 {
349 hand.handleElementEvent( event );
350 }
351 }
352 }