%line | %branch | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
org.apache.jcs.auxiliary.remote.RemoteCacheNoWait |
|
|
1 | package org.apache.jcs.auxiliary.remote; |
|
2 | ||
3 | /* |
|
4 | * Licensed to the Apache Software Foundation (ASF) under one |
|
5 | * or more contributor license agreements. See the NOTICE file |
|
6 | * distributed with this work for additional information |
|
7 | * regarding copyright ownership. The ASF licenses this file |
|
8 | * to you under the Apache License, Version 2.0 (the |
|
9 | * "License"); you may not use this file except in compliance |
|
10 | * with the License. You may obtain a copy of the License at |
|
11 | * |
|
12 | * http://www.apache.org/licenses/LICENSE-2.0 |
|
13 | * |
|
14 | * Unless required by applicable law or agreed to in writing, |
|
15 | * software distributed under the License is distributed on an |
|
16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
|
17 | * KIND, either express or implied. See the License for the |
|
18 | * specific language governing permissions and limitations |
|
19 | * under the License. |
|
20 | */ |
|
21 | ||
22 | import java.io.IOException; |
|
23 | import java.io.Serializable; |
|
24 | import java.rmi.UnmarshalException; |
|
25 | import java.util.ArrayList; |
|
26 | import java.util.Arrays; |
|
27 | import java.util.List; |
|
28 | import java.util.Set; |
|
29 | ||
30 | import org.apache.commons.logging.Log; |
|
31 | import org.apache.commons.logging.LogFactory; |
|
32 | import org.apache.jcs.auxiliary.AuxiliaryCache; |
|
33 | import org.apache.jcs.auxiliary.AuxiliaryCacheAttributes; |
|
34 | import org.apache.jcs.auxiliary.remote.behavior.IRemoteCacheClient; |
|
35 | import org.apache.jcs.auxiliary.remote.behavior.IRemoteCacheService; |
|
36 | import org.apache.jcs.engine.CacheAdaptor; |
|
37 | import org.apache.jcs.engine.CacheConstants; |
|
38 | import org.apache.jcs.engine.CacheEventQueueFactory; |
|
39 | import org.apache.jcs.engine.behavior.ICacheElement; |
|
40 | import org.apache.jcs.engine.behavior.ICacheEventQueue; |
|
41 | import org.apache.jcs.engine.behavior.ICacheType; |
|
42 | import org.apache.jcs.engine.stats.StatElement; |
|
43 | import org.apache.jcs.engine.stats.Stats; |
|
44 | import org.apache.jcs.engine.stats.behavior.IStatElement; |
|
45 | import org.apache.jcs.engine.stats.behavior.IStats; |
|
46 | ||
47 | /** |
|
48 | * Used to queue up update requests to the underlying cache. These requests will be processed in |
|
49 | * their order of arrival via the cache event queue processor. |
|
50 | * <p> |
|
51 | * Typically errors will be handled down stream. We only need to kill the queue if an error makes it |
|
52 | * to this level from the queue. That can only happen if the queue is damaged, since the events are |
|
53 | * procesed asynchronously. |
|
54 | * <p> |
|
55 | * There is no reason to create a queue on startup if the remote is not healthy. |
|
56 | * <p> |
|
57 | * If the remote cache encounters an error it will zombie--create a blaking facade for the service. |
|
58 | * The Zombie will queue up items until the conenction is restored. An alternative way to accomplish |
|
59 | * the same thing would be to stop, not destroy the queue at this level. That way items would be |
|
60 | * added to the queue and then when the connection is restored, we could start the worker threads |
|
61 | * again. This is a better long term solution, but it requires some significnat changes to the |
|
62 | * complicated worker queues. |
|
63 | */ |
|
64 | public class RemoteCacheNoWait |
|
65 | implements AuxiliaryCache |
|
66 | { |
|
67 | private static final long serialVersionUID = -3104089136003714717L; |
|
68 | ||
69 | 28 | private final static Log log = LogFactory.getLog( RemoteCacheNoWait.class ); |
70 | ||
71 | private final IRemoteCacheClient cache; |
|
72 | ||
73 | private ICacheEventQueue cacheEventQueue; |
|
74 | ||
75 | 63 | private int getCount = 0; |
76 | ||
77 | 63 | private int removeCount = 0; |
78 | ||
79 | 63 | private int putCount = 0; |
80 | ||
81 | /** |
|
82 | * Constructs with the given remote cache, and fires up an event queue for aysnchronous |
|
83 | * processing. |
|
84 | * <p> |
|
85 | * @param cache |
|
86 | */ |
|
87 | public RemoteCacheNoWait( IRemoteCacheClient cache ) |
|
88 | 63 | { |
89 | 63 | this.cache = cache; |
90 | 63 | CacheEventQueueFactory fact = new CacheEventQueueFactory(); |
91 | 63 | this.cacheEventQueue = fact.createCacheEventQueue( new CacheAdaptor( cache ), cache.getListenerId(), cache.getCacheName(), |
92 | cache.getAuxiliaryCacheAttributes().getEventQueuePoolName(), cache |
|
93 | .getAuxiliaryCacheAttributes().getEventQueueTypeFactoryCode() ); |
|
94 | ||
95 | 63 | if ( cache.getStatus() == CacheConstants.STATUS_ERROR ) |
96 | { |
|
97 | 7 | cacheEventQueue.destroy(); |
98 | } |
|
99 | 63 | } |
100 | ||
101 | /** |
|
102 | * Adds a put event to the queue. |
|
103 | * <p> |
|
104 | * (non-Javadoc) |
|
105 | * @see org.apache.jcs.engine.behavior.ICache#update(org.apache.jcs.engine.behavior.ICacheElement) |
|
106 | */ |
|
107 | public void update( ICacheElement ce ) |
|
108 | throws IOException |
|
109 | { |
|
110 | 742 | putCount++; |
111 | try |
|
112 | { |
|
113 | 742 | cacheEventQueue.addPutEvent( ce ); |
114 | } |
|
115 | 0 | catch ( IOException ex ) |
116 | { |
|
117 | 0 | log.error( "Problem adding putEvent to queue.", ex ); |
118 | 0 | cacheEventQueue.destroy(); |
119 | 0 | throw ex; |
120 | 742 | } |
121 | 742 | } |
122 | ||
123 | /** |
|
124 | * Synchronously reads from the remote cache. |
|
125 | * <p> |
|
126 | * @param key |
|
127 | * @return |
|
128 | * @throws IOException |
|
129 | */ |
|
130 | public ICacheElement get( Serializable key ) |
|
131 | throws IOException |
|
132 | { |
|
133 | 28 | getCount++; |
134 | try |
|
135 | { |
|
136 | 28 | return cache.get( key ); |
137 | } |
|
138 | 0 | catch ( UnmarshalException ue ) |
139 | { |
|
140 | 0 | if ( log.isDebugEnabled() ) |
141 | { |
|
142 | 0 | log.debug( "Retrying the get owing to UnmarshalException..." ); |
143 | } |
|
144 | try |
|
145 | { |
|
146 | 0 | return cache.get( key ); |
147 | } |
|
148 | 0 | catch ( IOException ex ) |
149 | { |
|
150 | 0 | if ( log.isInfoEnabled() ) |
151 | { |
|
152 | 0 | log.info( "Failed in retrying the get for the second time. " + ex.getMessage() ); |
153 | } |
|
154 | } |
|
155 | } |
|
156 | 0 | catch ( IOException ex ) |
157 | { |
|
158 | // We don't want to destroy the queue on a get failure. |
|
159 | // The RemoteCache will Zombie and queue. |
|
160 | // Since get does not use the queue, I dont want to killing the queue. |
|
161 | 0 | throw ex; |
162 | 0 | } |
163 | 0 | return null; |
164 | } |
|
165 | ||
166 | public Set getGroupKeys( String groupName ) |
|
167 | throws IOException |
|
168 | { |
|
169 | 0 | return cache.getGroupKeys( groupName ); |
170 | } |
|
171 | ||
172 | /** |
|
173 | * Adds a remove request to the remote cache. |
|
174 | * <p> |
|
175 | * @param key |
|
176 | * @return |
|
177 | * @throws IOException |
|
178 | */ |
|
179 | public boolean remove( Serializable key ) |
|
180 | throws IOException |
|
181 | { |
|
182 | 14 | removeCount++; |
183 | try |
|
184 | { |
|
185 | 14 | cacheEventQueue.addRemoveEvent( key ); |
186 | } |
|
187 | 0 | catch ( IOException ex ) |
188 | { |
|
189 | 0 | log.error( "Problem adding RemoveEvent to queue.", ex ); |
190 | 0 | cacheEventQueue.destroy(); |
191 | 0 | throw ex; |
192 | 14 | } |
193 | 14 | return false; |
194 | } |
|
195 | ||
196 | /** |
|
197 | * Adds a removeAll request to the remote cache. |
|
198 | * <p> |
|
199 | * @throws IOException |
|
200 | */ |
|
201 | public void removeAll() |
|
202 | throws IOException |
|
203 | { |
|
204 | try |
|
205 | { |
|
206 | 0 | cacheEventQueue.addRemoveAllEvent(); |
207 | } |
|
208 | 0 | catch ( IOException ex ) |
209 | { |
|
210 | 0 | log.error( "Problem adding RemoveAllEvent to queue.", ex ); |
211 | 0 | cacheEventQueue.destroy(); |
212 | 0 | throw ex; |
213 | 0 | } |
214 | 0 | } |
215 | ||
216 | /** Adds a dispose request to the remote cache. */ |
|
217 | public void dispose() |
|
218 | { |
|
219 | try |
|
220 | { |
|
221 | 0 | cacheEventQueue.addDisposeEvent(); |
222 | } |
|
223 | 0 | catch ( IOException ex ) |
224 | { |
|
225 | 0 | log.error( "Problem adding DisposeEvent to queue.", ex ); |
226 | 0 | cacheEventQueue.destroy(); |
227 | 0 | } |
228 | 0 | } |
229 | ||
230 | /** |
|
231 | * No remote invocation. |
|
232 | * <p> |
|
233 | * @return The size value |
|
234 | */ |
|
235 | public int getSize() |
|
236 | { |
|
237 | 0 | return cache.getSize(); |
238 | } |
|
239 | ||
240 | /** |
|
241 | * No remote invokation. |
|
242 | * <p> |
|
243 | * @return The cacheType value |
|
244 | */ |
|
245 | public int getCacheType() |
|
246 | { |
|
247 | 0 | return ICacheType.REMOTE_CACHE; |
248 | } |
|
249 | ||
250 | /** |
|
251 | * Returns the asyn cache status. An error status indicates either the remote connection is not |
|
252 | * available, or the asyn queue has been unexpectedly destroyed. No remote invocation. |
|
253 | * <p> |
|
254 | * @return The status value |
|
255 | */ |
|
256 | public int getStatus() |
|
257 | { |
|
258 | 14 | return cacheEventQueue.isWorking() ? cache.getStatus() : CacheConstants.STATUS_ERROR; |
259 | } |
|
260 | ||
261 | /** |
|
262 | * Gets the cacheName attribute of the RemoteCacheNoWait object |
|
263 | * <p> |
|
264 | * @return The cacheName value |
|
265 | */ |
|
266 | public String getCacheName() |
|
267 | { |
|
268 | 0 | return cache.getCacheName(); |
269 | } |
|
270 | ||
271 | /** |
|
272 | * Replaces the remote cache service handle with the given handle and reset the event queue by |
|
273 | * starting up a new instance. |
|
274 | * <p> |
|
275 | * @param remote |
|
276 | */ |
|
277 | public void fixCache( IRemoteCacheService remote ) |
|
278 | { |
|
279 | 7 | cache.fixCache( remote ); |
280 | 7 | resetEventQ(); |
281 | 7 | return; |
282 | } |
|
283 | ||
284 | /** |
|
285 | * Resets the event q by first destroying the existing one and starting up new one. |
|
286 | * <p> |
|
287 | * There may be no good reason to kill the existing queue. We will sometimes need to set a new |
|
288 | * listener id, so we should create a new queue. We should let the old queue drain. If we were |
|
289 | * conencted to the failover, it would be best to finish sending items. |
|
290 | */ |
|
291 | public void resetEventQ() |
|
292 | { |
|
293 | 7 | ICacheEventQueue previousQueue = cacheEventQueue; |
294 | ||
295 | 7 | CacheEventQueueFactory fact = new CacheEventQueueFactory(); |
296 | 7 | this.cacheEventQueue = fact.createCacheEventQueue( new CacheAdaptor( cache ), cache.getListenerId(), cache.getCacheName(), |
297 | cache.getAuxiliaryCacheAttributes().getEventQueuePoolName(), cache |
|
298 | .getAuxiliaryCacheAttributes().getEventQueueTypeFactoryCode() ); |
|
299 | ||
300 | 7 | if ( previousQueue.isWorking() ) |
301 | { |
|
302 | // we don't expect anything, it would have all gone to the zombie |
|
303 | 7 | if ( log.isInfoEnabled() ) |
304 | { |
|
305 | 7 | log.info( "resetEventQ, previous queue has [" + previousQueue.size() + "] items queued up." ); |
306 | } |
|
307 | 7 | previousQueue.destroy(); |
308 | } |
|
309 | 7 | } |
310 | ||
311 | /** |
|
312 | * This is temporary. It allows the manager to get the lister. |
|
313 | * <p> |
|
314 | * @return |
|
315 | */ |
|
316 | protected IRemoteCacheClient getRemoteCache() |
|
317 | { |
|
318 | 0 | return cache; |
319 | } |
|
320 | ||
321 | /** |
|
322 | * @return Returns the AuxiliaryCacheAttributes. |
|
323 | */ |
|
324 | public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes() |
|
325 | { |
|
326 | 0 | return cache.getAuxiliaryCacheAttributes(); |
327 | } |
|
328 | ||
329 | /** |
|
330 | * This is for testing only. It allows you to take a look at the event queue. |
|
331 | * <p> |
|
332 | * @return ICacheEventQueue |
|
333 | */ |
|
334 | protected ICacheEventQueue getCacheEventQueue() |
|
335 | { |
|
336 | 14 | return this.cacheEventQueue; |
337 | } |
|
338 | ||
339 | /** |
|
340 | * Returns the stats and the cache.toString(). |
|
341 | * <p> |
|
342 | * (non-Javadoc) |
|
343 | * @see java.lang.Object#toString() |
|
344 | */ |
|
345 | public String toString() |
|
346 | { |
|
347 | 0 | return getStats() + "\n" + cache.toString(); |
348 | } |
|
349 | ||
350 | /** |
|
351 | * Returns the statistics in String form. |
|
352 | * <p> |
|
353 | * @return String |
|
354 | */ |
|
355 | public String getStats() |
|
356 | { |
|
357 | 7 | return getStatistics().toString(); |
358 | } |
|
359 | ||
360 | /* |
|
361 | * (non-Javadoc) |
|
362 | * @see org.apache.jcs.auxiliary.AuxiliaryCache#getStatistics() |
|
363 | */ |
|
364 | public IStats getStatistics() |
|
365 | { |
|
366 | 7 | IStats stats = new Stats(); |
367 | 7 | stats.setTypeName( "Remote Cache No Wait" ); |
368 | ||
369 | 7 | ArrayList elems = new ArrayList(); |
370 | ||
371 | 7 | IStatElement se = null; |
372 | ||
373 | 7 | se = new StatElement(); |
374 | 7 | se.setName( "Status" ); |
375 | 7 | int status = this.getStatus(); |
376 | 7 | if ( status == CacheConstants.STATUS_ERROR ) |
377 | { |
|
378 | 0 | se.setData( "ERROR" ); |
379 | 0 | } |
380 | 7 | else if ( status == CacheConstants.STATUS_ALIVE ) |
381 | { |
|
382 | 7 | se.setData( "ALIVE" ); |
383 | 7 | } |
384 | 0 | else if ( status == CacheConstants.STATUS_DISPOSED ) |
385 | { |
|
386 | 0 | se.setData( "DISPOSED" ); |
387 | 0 | } |
388 | else |
|
389 | { |
|
390 | 0 | se.setData( "" + status ); |
391 | } |
|
392 | 7 | elems.add( se ); |
393 | ||
394 | // no data gathered here |
|
395 | ||
396 | // get the stats from the cache queue too |
|
397 | // get as array, convert to list, add list to our outer list |
|
398 | 7 | IStats cStats = this.cache.getStatistics(); |
399 | 7 | if ( cStats != null ) |
400 | { |
|
401 | 0 | IStatElement[] cSEs = cStats.getStatElements(); |
402 | 0 | List cL = Arrays.asList( cSEs ); |
403 | 0 | elems.addAll( cL ); |
404 | } |
|
405 | ||
406 | // get the stats from the event queue too |
|
407 | // get as array, convert to list, add list to our outer list |
|
408 | 7 | IStats eqStats = this.cacheEventQueue.getStatistics(); |
409 | 7 | IStatElement[] eqSEs = eqStats.getStatElements(); |
410 | 7 | List eqL = Arrays.asList( eqSEs ); |
411 | 7 | elems.addAll( eqL ); |
412 | ||
413 | 7 | se = new StatElement(); |
414 | 7 | se.setName( "Get Count" ); |
415 | 7 | se.setData( "" + this.getCount ); |
416 | 7 | elems.add( se ); |
417 | ||
418 | 7 | se = new StatElement(); |
419 | 7 | se.setName( "Remove Count" ); |
420 | 7 | se.setData( "" + this.removeCount ); |
421 | 7 | elems.add( se ); |
422 | ||
423 | 7 | se = new StatElement(); |
424 | 7 | se.setName( "Put Count" ); |
425 | 7 | se.setData( "" + this.putCount ); |
426 | 7 | elems.add( se ); |
427 | ||
428 | // get an array and put them in the Stats object |
|
429 | 7 | IStatElement[] ses = (IStatElement[]) elems.toArray( new StatElement[elems.size()] ); |
430 | 7 | stats.setStatElements( ses ); |
431 | ||
432 | 7 | return stats; |
433 | } |
|
434 | ||
435 | } |
This report is generated by jcoverage, Maven and Maven JCoverage Plugin. |