1 package org.apache.jcs.auxiliary.remote;
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 import java.io.Serializable;
24 import java.util.Collections;
25 import java.util.Set;
26
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29 import org.apache.jcs.auxiliary.remote.behavior.IRemoteCacheService;
30 import org.apache.jcs.engine.ZombieCacheService;
31 import org.apache.jcs.engine.behavior.ICacheElement;
32 import org.apache.jcs.utils.struct.BoundedQueue;
33 import org.apache.jcs.utils.timing.ElapsedTimer;
34
35 /***
36 * Zombie adapter for the remote cache service. It just balks if there is no queue configured. If a
37 * queue is configured, then events will be added to the queue. The idea is that when proper
38 * operation is restored, the remote cache will walk the queue. The queue must be bounded so it does
39 * not eat memory.
40 * <p>
41 * Much of this is potentially reusable.
42 * <p>
43 * TODO figure out a way to get the propagate method into an interface for Zombies.
44 */
45 public class ZombieRemoteCacheService
46 extends ZombieCacheService
47 implements IRemoteCacheService
48 {
49 private final static Log log = LogFactory.getLog( ZombieRemoteCacheService.class );
50
51 private int maxQueueSize = 0;
52
53 private BoundedQueue queue;
54
55 /***
56 * Default.
57 */
58 public ZombieRemoteCacheService()
59 {
60 queue = new BoundedQueue( 0 );
61 }
62
63 /***
64 * Sets the maximum number of items that will be allowed on the queue.
65 * <p>
66 * @param maxQueueSize
67 */
68 public ZombieRemoteCacheService( int maxQueueSize )
69 {
70 this.maxQueueSize = maxQueueSize;
71 queue = new BoundedQueue( maxQueueSize );
72 }
73
74 /***
75 * Gets the number of items on the queue.
76 * <p>
77 * @return size of the queue.
78 */
79 public int getQueueSize()
80 {
81 return queue.size();
82 }
83
84 /***
85 * Adds an update event to the queue if the maxSize is greater than 0;
86 * <p>
87 * (non-Javadoc)
88 * @see org.apache.jcs.auxiliary.remote.behavior.IRemoteCacheService#update(org.apache.jcs.engine.behavior.ICacheElement,
89 * long)
90 */
91 public void update( ICacheElement item, long listenerId )
92 {
93 if ( maxQueueSize > 0 )
94 {
95 PutEvent event = new PutEvent( item, listenerId );
96 queue.add( event );
97 }
98
99 return;
100 }
101
102 /***
103 * Adds a removeAll event to the queue if the maxSize is greater than 0;
104 * <p>
105 * (non-Javadoc)
106 * @see org.apache.jcs.auxiliary.remote.behavior.IRemoteCacheService#remove(java.lang.String,
107 * java.io.Serializable, long)
108 */
109 public void remove( String cacheName, Serializable key, long listenerId )
110 {
111 if ( maxQueueSize > 0 )
112 {
113 RemoveEvent event = new RemoveEvent( cacheName, key, listenerId );
114 queue.add( event );
115 }
116
117 return;
118 }
119
120 /***
121 * Adds a removeAll event to the queue if the maxSize is greater than 0;
122 * <p>
123 * (non-Javadoc)
124 * @see org.apache.jcs.auxiliary.remote.behavior.IRemoteCacheService#removeAll(java.lang.String,
125 * long)
126 */
127 public void removeAll( String cacheName, long listenerId )
128 {
129 if ( maxQueueSize > 0 )
130 {
131 RemoveAllEvent event = new RemoveAllEvent( cacheName, listenerId );
132 queue.add( event );
133 }
134
135 return;
136 }
137
138 /***
139 * Does nothing. Gets are synchronous and cannot be added to a queue.
140 * <p>
141 * (non-Javadoc)
142 * @see org.apache.jcs.auxiliary.remote.behavior.IRemoteCacheService#get(java.lang.String,
143 * java.io.Serializable, long)
144 */
145 public ICacheElement get( String cacheName, Serializable key, long requesterId )
146 throws IOException
147 {
148
149 return null;
150 }
151
152 /***
153 * Does nothing.
154 * <p>
155 * (non-Javadoc)
156 * @see org.apache.jcs.auxiliary.remote.behavior.IRemoteCacheService#getGroupKeys(java.lang.String,
157 * java.lang.String)
158 */
159 public Set getGroupKeys( String cacheName, String groupName )
160 {
161 return Collections.EMPTY_SET;
162 }
163
164 /***
165 * Walk the queue, calling the service for each queue operation.
166 * <p>
167 * @param service
168 * @throws Exception
169 */
170 protected void propagateEvents( IRemoteCacheService service )
171 throws Exception
172 {
173 int cnt = 0;
174 if ( log.isInfoEnabled() )
175 {
176 log.info( "Propagating events to the new RemoteService." );
177 }
178 ElapsedTimer timer = new ElapsedTimer();
179 while ( !queue.isEmpty() )
180 {
181 cnt++;
182
183
184 ZombieEvent event = (ZombieEvent) queue.take();
185
186 if ( event instanceof PutEvent )
187 {
188 PutEvent putEvent = (PutEvent) event;
189 service.update( putEvent.element, event.requesterId );
190 }
191 else if ( event instanceof RemoveEvent )
192 {
193 RemoveEvent removeEvent = (RemoveEvent) event;
194 service.remove( event.cacheName, removeEvent.key, event.requesterId );
195 }
196 else if ( event instanceof RemoveAllEvent )
197 {
198 service.removeAll( event.cacheName, event.requesterId );
199 }
200 }
201 if ( log.isInfoEnabled() )
202 {
203 log.info( "Propagated " + cnt + " events to the new RemoteService in " + timer.getElapsedTimeString() );
204 }
205 }
206
207 /***
208 * Base of the other events.
209 */
210 private abstract class ZombieEvent
211 {
212 String cacheName;
213
214 long requesterId;
215 }
216
217 /***
218 * A basic put event.
219 */
220 private class PutEvent
221 extends ZombieEvent
222 {
223 ICacheElement element;
224
225 /***
226 * Set the element
227 * @param element
228 * @param requesterId
229 */
230 public PutEvent( ICacheElement element, long requesterId )
231 {
232 this.requesterId = requesterId;
233 this.element = element;
234 }
235 }
236
237 /***
238 * A basic Remove event.
239 */
240 private class RemoveEvent
241 extends ZombieEvent
242 {
243 Serializable key;
244
245 /***
246 * Set the element
247 * @param cacheName
248 * @param key
249 * @param requesterId
250 */
251 public RemoveEvent( String cacheName, Serializable key, long requesterId )
252 {
253 this.cacheName = cacheName;
254 this.requesterId = requesterId;
255 this.key = key;
256 }
257 }
258
259 /***
260 * A basic RemoveAll event.
261 */
262 private class RemoveAllEvent
263 extends ZombieEvent
264 {
265 /***
266 * @param cacheName
267 * @param requesterId
268 */
269 public RemoveAllEvent( String cacheName, long requesterId )
270 {
271 this.cacheName = cacheName;
272 this.requesterId = requesterId;
273 }
274 }
275 }