1 package org.apache.jcs.auxiliary.remote.http.server;
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.util.Map;
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.behavior.ICacheElement;
31 import org.apache.jcs.engine.behavior.ICompositeCacheManager;
32 import org.apache.jcs.engine.control.CompositeCache;
33 import org.apache.jcs.engine.control.CompositeCacheManager;
34 import org.apache.jcs.engine.logging.CacheEvent;
35 import org.apache.jcs.engine.logging.behavior.ICacheEvent;
36 import org.apache.jcs.engine.logging.behavior.ICacheEventLogger;
37
38 /**
39 * This class contains common methods for remote cache services. Eventually I hope to extract out
40 * much of the RMI server to use this as well. I'm starting with the Http service.
41 */
42 public abstract class AbstractRemoteCacheService
43 implements IRemoteCacheService
44 {
45 /** An optional event logger */
46 private transient ICacheEventLogger cacheEventLogger;
47
48 /** If there is no event logger, we will return this event for all create calls. */
49 private static final ICacheEvent EMPTY_ICACHE_EVENT = new CacheEvent();
50
51 /** The central hub */
52 private ICompositeCacheManager cacheManager;
53
54 /** Name of the event log source. */
55 private String eventLogSourceName = "AbstractRemoteCacheService";
56
57 /** Number of puts into the cache. */
58 private int puts = 0;
59
60 /** The interval at which we will log updates. */
61 private final int logInterval = 100;
62
63 /** log instance */
64 private final static Log log = LogFactory.getLog( AbstractRemoteCacheService.class );
65
66 /**
67 * Creates the super with the needed items.
68 * <p>
69 * @param cacheManager
70 * @param cacheEventLogger
71 */
72 public AbstractRemoteCacheService( ICompositeCacheManager cacheManager, ICacheEventLogger cacheEventLogger )
73 {
74 this.cacheManager = cacheManager;
75 this.cacheEventLogger = cacheEventLogger;
76 }
77
78 /**
79 * @param item
80 * @throws IOException
81 */
82 public void update( ICacheElement item )
83 throws IOException
84 {
85 update( item, 0 );
86 }
87
88 /**
89 * The internal processing is wrapped in event logging calls.
90 * <p>
91 * @param item
92 * @param requesterId
93 * @throws IOException
94 */
95 public void update( ICacheElement item, long requesterId )
96 throws IOException
97 {
98 ICacheEvent cacheEvent = createICacheEvent( item, requesterId, ICacheEventLogger.UPDATE_EVENT );
99 try
100 {
101 logUpdateInfo( item );
102
103 processUpdate( item, requesterId );
104 }
105 finally
106 {
107 logICacheEvent( cacheEvent );
108 }
109 }
110
111 /**
112 * The internal processing is wrapped in event logging calls.
113 * <p>
114 * @param item
115 * @param requesterId
116 * @throws IOException
117 */
118 abstract void processUpdate( ICacheElement item, long requesterId )
119 throws IOException;
120
121 /**
122 * Log some details.
123 * <p>
124 * @param item
125 */
126 private void logUpdateInfo( ICacheElement item )
127 {
128 if ( log.isInfoEnabled() )
129 {
130 // not thread safe, but it doesn't have to be accurate
131 puts++;
132 if ( puts % logInterval == 0 )
133 {
134 log.info( "puts = " + puts );
135 }
136 }
137
138 if ( log.isDebugEnabled() )
139 {
140 log.debug( "In update, put [" + item.getKey() + "] in [" + item.getCacheName() + "]" );
141 }
142 }
143
144 /**
145 * Returns a cache value from the specified remote cache; or null if the cache or key does not
146 * exist.
147 * <p>
148 * @param cacheName
149 * @param key
150 * @return ICacheElement
151 * @throws IOException
152 */
153 public ICacheElement get( String cacheName, Serializable key )
154 throws IOException
155 {
156 return this.get( cacheName, key, 0 );
157 }
158
159 /**
160 * Returns a cache bean from the specified cache; or null if the key does not exist.
161 * <p>
162 * Adding the requestor id, allows the cache to determine the source of the get.
163 * <p>
164 * The internal processing is wrapped in event logging calls.
165 * <p>
166 * @param cacheName
167 * @param key
168 * @param requesterId
169 * @return ICacheElement
170 * @throws IOException
171 */
172 public ICacheElement get( String cacheName, Serializable key, long requesterId )
173 throws IOException
174 {
175 ICacheElement element = null;
176 ICacheEvent cacheEvent = createICacheEvent( cacheName, key, requesterId, ICacheEventLogger.GET_EVENT );
177 try
178 {
179 element = processGet( cacheName, key, requesterId );
180 }
181 finally
182 {
183 logICacheEvent( cacheEvent );
184 }
185 return element;
186 }
187
188 /**
189 * Returns a cache bean from the specified cache; or null if the key does not exist.
190 * <p>
191 * Adding the requestor id, allows the cache to determine the source of the get.
192 * <p>
193 * @param cacheName
194 * @param key
195 * @param requesterId
196 * @return ICacheElement
197 * @throws IOException
198 */
199 abstract ICacheElement processGet( String cacheName, Serializable key, long requesterId )
200 throws IOException;
201
202 /**
203 * Gets all matching items.
204 * <p>
205 * @param cacheName
206 * @param pattern
207 * @return Map of keys and wrapped objects
208 * @throws IOException
209 */
210 public Map<Serializable, ICacheElement> getMatching( String cacheName, String pattern )
211 throws IOException
212 {
213 return getMatching( cacheName, pattern, 0 );
214 }
215
216 /**
217 * Retrieves all matching keys.
218 * <p>
219 * @param cacheName
220 * @param pattern
221 * @param requesterId
222 * @return Map of keys and wrapped objects
223 * @throws IOException
224 */
225 public Map<Serializable, ICacheElement> getMatching( String cacheName, String pattern, long requesterId )
226 throws IOException
227 {
228 ICacheEvent cacheEvent = createICacheEvent( cacheName, pattern, requesterId,
229 ICacheEventLogger.GETMATCHING_EVENT );
230 try
231 {
232 return processGetMatching( cacheName, pattern, requesterId );
233 }
234 finally
235 {
236 logICacheEvent( cacheEvent );
237 }
238 }
239
240 /**
241 * Retrieves all matching keys.
242 * <p>
243 * @param cacheName
244 * @param pattern
245 * @param requesterId
246 * @return Map of keys and wrapped objects
247 * @throws IOException
248 */
249 abstract Map<Serializable, ICacheElement> processGetMatching( String cacheName, String pattern, long requesterId )
250 throws IOException;
251
252 /**
253 * Gets multiple items from the cache based on the given set of keys.
254 * <p>
255 * @param cacheName
256 * @param keys
257 * @return a map of Serializable key to ICacheElement element, or an empty map if there is no
258 * data in cache for any of these keys
259 * @throws IOException
260 */
261 public Map<Serializable, ICacheElement> getMultiple( String cacheName, Set<Serializable> keys )
262 throws IOException
263 {
264 return this.getMultiple( cacheName, keys, 0 );
265 }
266
267 /**
268 * Gets multiple items from the cache based on the given set of keys.
269 * <p>
270 * The internal processing is wrapped in event logging calls.
271 * <p>
272 * @param cacheName
273 * @param keys
274 * @param requesterId
275 * @return a map of Serializable key to ICacheElement element, or an empty map if there is no
276 * data in cache for any of these keys
277 * @throws IOException
278 */
279 public Map<Serializable, ICacheElement> getMultiple( String cacheName, Set<Serializable> keys, long requesterId )
280 throws IOException
281 {
282 ICacheEvent cacheEvent = createICacheEvent( cacheName, (Serializable) keys, requesterId,
283 ICacheEventLogger.GETMULTIPLE_EVENT );
284 try
285 {
286 return processGetMultiple( cacheName, keys, requesterId );
287 }
288 finally
289 {
290 logICacheEvent( cacheEvent );
291 }
292 }
293
294 /**
295 * Gets multiple items from the cache based on the given set of keys.
296 * <p>
297 * @param cacheName
298 * @param keys
299 * @param requesterId
300 * @return a map of Serializable key to ICacheElement element, or an empty map if there is no
301 * data in cache for any of these keys
302 * @throws IOException
303 */
304 abstract Map<Serializable, ICacheElement> processGetMultiple( String cacheName, Set<Serializable> keys, long requesterId )
305 throws IOException;
306
307 /**
308 * Gets the set of keys of objects currently in the group.
309 * <p>
310 * @param cacheName
311 * @param group
312 * @return A Set of group keys
313 */
314 public Set<Serializable> getGroupKeys( String cacheName, String group )
315 {
316 return processGetGroupKeys( cacheName, group );
317 }
318
319 /**
320 * Gets the set of keys of objects currently in the group.
321 * <p>
322 * @param cacheName
323 * @param groupName
324 * @return Set
325 */
326 public Set<Serializable> processGetGroupKeys( String cacheName, String groupName )
327 {
328 CompositeCache cache = getCacheManager().getCache( cacheName );
329
330 return cache.getGroupKeys( groupName );
331 }
332
333 /**
334 * Removes the given key from the specified remote cache. Defaults the listener id to 0.
335 * <p>
336 * @param cacheName
337 * @param key
338 * @throws IOException
339 */
340 public void remove( String cacheName, Serializable key )
341 throws IOException
342 {
343 remove( cacheName, key, 0 );
344 }
345
346 /**
347 * Remove the key from the cache region and don't tell the source listener about it.
348 * <p>
349 * The internal processing is wrapped in event logging calls.
350 * <p>
351 * @param cacheName
352 * @param key
353 * @param requesterId
354 * @throws IOException
355 */
356 public void remove( String cacheName, Serializable key, long requesterId )
357 throws IOException
358 {
359 ICacheEvent cacheEvent = createICacheEvent( cacheName, key, requesterId, ICacheEventLogger.REMOVE_EVENT );
360 try
361 {
362 processRemove( cacheName, key, requesterId );
363 }
364 finally
365 {
366 logICacheEvent( cacheEvent );
367 }
368 }
369
370 /**
371 * Remove the key from the cache region and don't tell the source listener about it.
372 * <p>
373 * @param cacheName
374 * @param key
375 * @param requesterId
376 * @throws IOException
377 */
378 abstract void processRemove( String cacheName, Serializable key, long requesterId )
379 throws IOException;
380
381 /**
382 * Remove all keys from the specified remote cache.
383 * <p>
384 * @param cacheName
385 * @throws IOException
386 */
387 public void removeAll( String cacheName )
388 throws IOException
389 {
390 removeAll( cacheName, 0 );
391 }
392
393 /**
394 * Remove all keys from the specified remote cache.
395 * <p>
396 * The internal processing is wrapped in event logging calls.
397 * <p>
398 * @param cacheName
399 * @param requesterId
400 * @throws IOException
401 */
402 public void removeAll( String cacheName, long requesterId )
403 throws IOException
404 {
405 ICacheEvent cacheEvent = createICacheEvent( cacheName, "all", requesterId, ICacheEventLogger.REMOVEALL_EVENT );
406 try
407 {
408 processRemoveAll( cacheName, requesterId );
409 }
410 finally
411 {
412 logICacheEvent( cacheEvent );
413 }
414 }
415
416 /**
417 * Remove all keys from the specified remote cache.
418 * <p>
419 * @param cacheName
420 * @param requesterId
421 * @throws IOException
422 */
423 abstract void processRemoveAll( String cacheName, long requesterId )
424 throws IOException;
425
426 /**
427 * Frees the specified remote cache.
428 * <p>
429 * @param cacheName
430 * @throws IOException
431 */
432 public void dispose( String cacheName )
433 throws IOException
434 {
435 dispose( cacheName, 0 );
436 }
437
438 /**
439 * Frees the specified remote cache.
440 * <p>
441 * @param cacheName
442 * @param requesterId
443 * @throws IOException
444 */
445 public void dispose( String cacheName, long requesterId )
446 throws IOException
447 {
448 ICacheEvent cacheEvent = createICacheEvent( cacheName, "none", requesterId, ICacheEventLogger.DISPOSE_EVENT );
449 try
450 {
451 processDispose( cacheName, requesterId );
452 }
453 finally
454 {
455 logICacheEvent( cacheEvent );
456 }
457 }
458
459 /**
460 * @param cacheName
461 * @param requesterId
462 * @throws IOException
463 */
464 abstract void processDispose( String cacheName, long requesterId )
465 throws IOException;
466
467 /**
468 * Gets the stats attribute of the RemoteCacheServer object.
469 * <p>
470 * @return The stats value
471 * @throws IOException
472 */
473 public String getStats()
474 throws IOException
475 {
476 return cacheManager.getStats();
477 }
478
479 /**
480 * Logs an event if an event logger is configured.
481 * <p>
482 * @param item
483 * @param requesterId
484 * @param eventName
485 * @return ICacheEvent
486 */
487 protected ICacheEvent createICacheEvent( ICacheElement item, long requesterId, String eventName )
488 {
489 if ( cacheEventLogger == null )
490 {
491 return EMPTY_ICACHE_EVENT;
492 }
493 String ipAddress = getExtraInfoForRequesterId( requesterId );
494 return cacheEventLogger.createICacheEvent( getEventLogSourceName(), item.getCacheName(), eventName, ipAddress,
495 item );
496 }
497
498 /**
499 * Logs an event if an event logger is configured.
500 * <p>
501 * @param cacheName
502 * @param key
503 * @param requesterId
504 * @param eventName
505 * @return ICacheEvent
506 */
507 protected ICacheEvent createICacheEvent( String cacheName, Serializable key, long requesterId, String eventName )
508 {
509 if ( cacheEventLogger == null )
510 {
511 return EMPTY_ICACHE_EVENT;
512 }
513 String ipAddress = getExtraInfoForRequesterId( requesterId );
514 return cacheEventLogger.createICacheEvent( getEventLogSourceName(), cacheName, eventName, ipAddress, key );
515 }
516
517 /**
518 * Logs an event if an event logger is configured.
519 * <p>
520 * @param source
521 * @param eventName
522 * @param optionalDetails
523 */
524 protected void logApplicationEvent( String source, String eventName, String optionalDetails )
525 {
526 if ( cacheEventLogger != null )
527 {
528 cacheEventLogger.logApplicationEvent( source, eventName, optionalDetails );
529 }
530 }
531
532 /**
533 * Logs an event if an event logger is configured.
534 * <p>
535 * @param cacheEvent
536 */
537 protected void logICacheEvent( ICacheEvent cacheEvent )
538 {
539 if ( cacheEventLogger != null )
540 {
541 cacheEventLogger.logICacheEvent( cacheEvent );
542 }
543 }
544
545 /**
546 * Ip address for the client, if one is stored.
547 * <p>
548 * Protected for testing.
549 * <p>
550 * @param requesterId
551 * @return String
552 */
553 protected abstract String getExtraInfoForRequesterId( long requesterId );
554
555 /**
556 * Allows it to be injected.
557 * <p>
558 * @param cacheEventLogger
559 */
560 public void setCacheEventLogger( ICacheEventLogger cacheEventLogger )
561 {
562 this.cacheEventLogger = cacheEventLogger;
563 }
564
565 /**
566 * @param cacheManager the cacheManager to set
567 */
568 protected void setCacheManager( CompositeCacheManager cacheManager )
569 {
570 this.cacheManager = cacheManager;
571 }
572
573 /**
574 * @return the cacheManager
575 */
576 protected ICompositeCacheManager getCacheManager()
577 {
578 return cacheManager;
579 }
580
581 /**
582 * @param eventLogSourceName the eventLogSourceName to set
583 */
584 protected void setEventLogSourceName( String eventLogSourceName )
585 {
586 this.eventLogSourceName = eventLogSourceName;
587 }
588
589 /**
590 * @return the eventLogSourceName
591 */
592 protected String getEventLogSourceName()
593 {
594 return eventLogSourceName;
595 }
596 }