001 package org.apache.jcs.auxiliary.remote.http.server;
002
003 /*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements. See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership. The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License. You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied. See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022 import java.io.IOException;
023 import java.io.Serializable;
024 import java.util.Map;
025 import java.util.Set;
026
027 import org.apache.commons.logging.Log;
028 import org.apache.commons.logging.LogFactory;
029 import org.apache.jcs.engine.behavior.ICacheElement;
030 import org.apache.jcs.engine.behavior.ICacheServiceNonLocal;
031 import org.apache.jcs.engine.behavior.ICompositeCacheManager;
032 import org.apache.jcs.engine.control.CompositeCache;
033 import org.apache.jcs.engine.control.CompositeCacheManager;
034 import org.apache.jcs.engine.logging.CacheEvent;
035 import org.apache.jcs.engine.logging.behavior.ICacheEvent;
036 import org.apache.jcs.engine.logging.behavior.ICacheEventLogger;
037
038 /**
039 * This class contains common methods for remote cache services. Eventually I hope to extract out
040 * much of the RMI server to use this as well. I'm starting with the Http service.
041 */
042 public abstract class AbstractRemoteCacheService<K extends Serializable, V extends Serializable>
043 implements ICacheServiceNonLocal<K, V>
044 {
045 /** An optional event logger */
046 private transient ICacheEventLogger cacheEventLogger;
047
048 /** The central hub */
049 private ICompositeCacheManager cacheManager;
050
051 /** Name of the event log source. */
052 private String eventLogSourceName = "AbstractRemoteCacheService";
053
054 /** Number of puts into the cache. */
055 private int puts = 0;
056
057 /** The interval at which we will log updates. */
058 private final int logInterval = 100;
059
060 /** log instance */
061 private final static Log log = LogFactory.getLog( AbstractRemoteCacheService.class );
062
063 /**
064 * Creates the super with the needed items.
065 * <p>
066 * @param cacheManager
067 * @param cacheEventLogger
068 */
069 public AbstractRemoteCacheService( ICompositeCacheManager cacheManager, ICacheEventLogger cacheEventLogger )
070 {
071 this.cacheManager = cacheManager;
072 this.cacheEventLogger = cacheEventLogger;
073 }
074
075 /**
076 * @param item
077 * @throws IOException
078 */
079 public void update( ICacheElement<K, V> item )
080 throws IOException
081 {
082 update( item, 0 );
083 }
084
085 /**
086 * The internal processing is wrapped in event logging calls.
087 * <p>
088 * @param item
089 * @param requesterId
090 * @throws IOException
091 */
092 public void update( ICacheElement<K, V> item, long requesterId )
093 throws IOException
094 {
095 ICacheEvent<ICacheElement<K, V>> cacheEvent = createICacheEvent( item, requesterId, ICacheEventLogger.UPDATE_EVENT );
096 try
097 {
098 logUpdateInfo( item );
099
100 processUpdate( item, requesterId );
101 }
102 finally
103 {
104 logICacheEvent( cacheEvent );
105 }
106 }
107
108 /**
109 * The internal processing is wrapped in event logging calls.
110 * <p>
111 * @param item
112 * @param requesterId
113 * @throws IOException
114 */
115 abstract void processUpdate( ICacheElement<K, V> item, long requesterId )
116 throws IOException;
117
118 /**
119 * Log some details.
120 * <p>
121 * @param item
122 */
123 private void logUpdateInfo( ICacheElement<K, V> item )
124 {
125 if ( log.isInfoEnabled() )
126 {
127 // not thread safe, but it doesn't have to be accurate
128 puts++;
129 if ( puts % logInterval == 0 )
130 {
131 log.info( "puts = " + puts );
132 }
133 }
134
135 if ( log.isDebugEnabled() )
136 {
137 log.debug( "In update, put [" + item.getKey() + "] in [" + item.getCacheName() + "]" );
138 }
139 }
140
141 /**
142 * Returns a cache value from the specified remote cache; or null if the cache or key does not
143 * exist.
144 * <p>
145 * @param cacheName
146 * @param key
147 * @return ICacheElement
148 * @throws IOException
149 */
150 public ICacheElement<K, V> get( String cacheName, K key )
151 throws IOException
152 {
153 return this.get( cacheName, key, 0 );
154 }
155
156 /**
157 * Returns a cache bean from the specified cache; or null if the key does not exist.
158 * <p>
159 * Adding the requestor id, allows the cache to determine the source of the get.
160 * <p>
161 * The internal processing is wrapped in event logging calls.
162 * <p>
163 * @param cacheName
164 * @param key
165 * @param requesterId
166 * @return ICacheElement
167 * @throws IOException
168 */
169 public ICacheElement<K, V> get( String cacheName, K key, long requesterId )
170 throws IOException
171 {
172 ICacheElement<K, V> element = null;
173 ICacheEvent<K> cacheEvent = createICacheEvent( cacheName, key, requesterId, ICacheEventLogger.GET_EVENT );
174 try
175 {
176 element = processGet( cacheName, key, requesterId );
177 }
178 finally
179 {
180 logICacheEvent( cacheEvent );
181 }
182 return element;
183 }
184
185 /**
186 * Returns a cache bean from the specified cache; or null if the key does not exist.
187 * <p>
188 * Adding the requestor id, allows the cache to determine the source of the get.
189 * <p>
190 * @param cacheName
191 * @param key
192 * @param requesterId
193 * @return ICacheElement
194 * @throws IOException
195 */
196 abstract ICacheElement<K, V> processGet( String cacheName, K key, long requesterId )
197 throws IOException;
198
199 /**
200 * Gets all matching items.
201 * <p>
202 * @param cacheName
203 * @param pattern
204 * @return Map of keys and wrapped objects
205 * @throws IOException
206 */
207 public Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern )
208 throws IOException
209 {
210 return getMatching( cacheName, pattern, 0 );
211 }
212
213 /**
214 * Retrieves all matching keys.
215 * <p>
216 * @param cacheName
217 * @param pattern
218 * @param requesterId
219 * @return Map of keys and wrapped objects
220 * @throws IOException
221 */
222 public Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern, long requesterId )
223 throws IOException
224 {
225 ICacheEvent<String> cacheEvent = createICacheEvent( cacheName, pattern, requesterId,
226 ICacheEventLogger.GETMATCHING_EVENT );
227 try
228 {
229 return processGetMatching( cacheName, pattern, requesterId );
230 }
231 finally
232 {
233 logICacheEvent( cacheEvent );
234 }
235 }
236
237 /**
238 * Retrieves all matching keys.
239 * <p>
240 * @param cacheName
241 * @param pattern
242 * @param requesterId
243 * @return Map of keys and wrapped objects
244 * @throws IOException
245 */
246 abstract Map<K, ICacheElement<K, V>> processGetMatching( String cacheName, String pattern, long requesterId )
247 throws IOException;
248
249 /**
250 * Gets multiple items from the cache based on the given set of keys.
251 * <p>
252 * @param cacheName
253 * @param keys
254 * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
255 * data in cache for any of these keys
256 * @throws IOException
257 */
258 public Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys )
259 throws IOException
260 {
261 return this.getMultiple( cacheName, keys, 0 );
262 }
263
264 /**
265 * Gets multiple items from the cache based on the given set of keys.
266 * <p>
267 * The internal processing is wrapped in event logging calls.
268 * <p>
269 * @param cacheName
270 * @param keys
271 * @param requesterId
272 * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
273 * data in cache for any of these keys
274 * @throws IOException
275 */
276 public Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys, long requesterId )
277 throws IOException
278 {
279 ICacheEvent<Serializable> cacheEvent = createICacheEvent( cacheName, (Serializable) keys, requesterId,
280 ICacheEventLogger.GETMULTIPLE_EVENT );
281 try
282 {
283 return processGetMultiple( cacheName, keys, requesterId );
284 }
285 finally
286 {
287 logICacheEvent( cacheEvent );
288 }
289 }
290
291 /**
292 * Gets multiple items from the cache based on the given set of keys.
293 * <p>
294 * @param cacheName
295 * @param keys
296 * @param requesterId
297 * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
298 * data in cache for any of these keys
299 * @throws IOException
300 */
301 abstract Map<K, ICacheElement<K, V>> processGetMultiple( String cacheName, Set<K> keys, long requesterId )
302 throws IOException;
303
304 /**
305 * Gets the set of keys of objects currently in the group.
306 * <p>
307 * @param cacheName
308 * @param group
309 * @return A Set of group keys
310 */
311 public Set<K> getGroupKeys( String cacheName, String group )
312 {
313 return processGetGroupKeys( cacheName, group );
314 }
315
316 /**
317 * Gets the set of keys of objects currently in the group.
318 * <p>
319 * @param cacheName
320 * @param groupName
321 * @return Set
322 */
323 public Set<K> processGetGroupKeys( String cacheName, String groupName )
324 {
325 CompositeCache<K, V> cache = getCacheManager().getCache( cacheName );
326
327 return cache.getGroupKeys( groupName );
328 }
329
330 /**
331 * Gets the set of group names currently in the cache.
332 * <p>
333 * @param cacheName
334 * @param group
335 * @return A Set of group names
336 */
337 public Set<String> getGroupNames( String cacheName )
338 {
339 return processGetGroupNames( cacheName );
340 }
341
342 /**
343 * Gets the set of keys of objects currently in the group.
344 * <p>
345 * @param cacheName
346 * @param groupName
347 * @return Set
348 */
349 public Set<String> processGetGroupNames( String cacheName )
350 {
351 CompositeCache<?, ?> cache = getCacheManager().getCache( cacheName );
352 return cache.getGroupNames();
353 }
354
355 /**
356 * Removes the given key from the specified remote cache. Defaults the listener id to 0.
357 * <p>
358 * @param cacheName
359 * @param key
360 * @throws IOException
361 */
362 public void remove( String cacheName, K key )
363 throws IOException
364 {
365 remove( cacheName, key, 0 );
366 }
367
368 /**
369 * Remove the key from the cache region and don't tell the source listener about it.
370 * <p>
371 * The internal processing is wrapped in event logging calls.
372 * <p>
373 * @param cacheName
374 * @param key
375 * @param requesterId
376 * @throws IOException
377 */
378 public void remove( String cacheName, K key, long requesterId )
379 throws IOException
380 {
381 ICacheEvent<K> cacheEvent = createICacheEvent( cacheName, key, requesterId, ICacheEventLogger.REMOVE_EVENT );
382 try
383 {
384 processRemove( cacheName, key, requesterId );
385 }
386 finally
387 {
388 logICacheEvent( cacheEvent );
389 }
390 }
391
392 /**
393 * Remove the key from the cache region and don't tell the source listener about it.
394 * <p>
395 * @param cacheName
396 * @param key
397 * @param requesterId
398 * @throws IOException
399 */
400 abstract void processRemove( String cacheName, K key, long requesterId )
401 throws IOException;
402
403 /**
404 * Remove all keys from the specified remote cache.
405 * <p>
406 * @param cacheName
407 * @throws IOException
408 */
409 public void removeAll( String cacheName )
410 throws IOException
411 {
412 removeAll( cacheName, 0 );
413 }
414
415 /**
416 * Remove all keys from the specified remote cache.
417 * <p>
418 * The internal processing is wrapped in event logging calls.
419 * <p>
420 * @param cacheName
421 * @param requesterId
422 * @throws IOException
423 */
424 public void removeAll( String cacheName, long requesterId )
425 throws IOException
426 {
427 ICacheEvent<String> cacheEvent = createICacheEvent( cacheName, "all", requesterId, ICacheEventLogger.REMOVEALL_EVENT );
428 try
429 {
430 processRemoveAll( cacheName, requesterId );
431 }
432 finally
433 {
434 logICacheEvent( cacheEvent );
435 }
436 }
437
438 /**
439 * Remove all keys from the specified remote cache.
440 * <p>
441 * @param cacheName
442 * @param requesterId
443 * @throws IOException
444 */
445 abstract void processRemoveAll( String cacheName, long requesterId )
446 throws IOException;
447
448 /**
449 * Frees the specified remote cache.
450 * <p>
451 * @param cacheName
452 * @throws IOException
453 */
454 public void dispose( String cacheName )
455 throws IOException
456 {
457 dispose( cacheName, 0 );
458 }
459
460 /**
461 * Frees the specified remote cache.
462 * <p>
463 * @param cacheName
464 * @param requesterId
465 * @throws IOException
466 */
467 public void dispose( String cacheName, long requesterId )
468 throws IOException
469 {
470 ICacheEvent<String> cacheEvent = createICacheEvent( cacheName, "none", requesterId, ICacheEventLogger.DISPOSE_EVENT );
471 try
472 {
473 processDispose( cacheName, requesterId );
474 }
475 finally
476 {
477 logICacheEvent( cacheEvent );
478 }
479 }
480
481 /**
482 * @param cacheName
483 * @param requesterId
484 * @throws IOException
485 */
486 abstract void processDispose( String cacheName, long requesterId )
487 throws IOException;
488
489 /**
490 * Gets the stats attribute of the RemoteCacheServer object.
491 * <p>
492 * @return The stats value
493 * @throws IOException
494 */
495 public String getStats()
496 throws IOException
497 {
498 return cacheManager.getStats();
499 }
500
501 /**
502 * Logs an event if an event logger is configured.
503 * <p>
504 * @param item
505 * @param requesterId
506 * @param eventName
507 * @return ICacheEvent
508 */
509 protected ICacheEvent<ICacheElement<K, V>> createICacheEvent( ICacheElement<K, V> item, long requesterId, String eventName )
510 {
511 if ( cacheEventLogger == null )
512 {
513 return new CacheEvent<ICacheElement<K, V>>();
514 }
515 String ipAddress = getExtraInfoForRequesterId( requesterId );
516 return cacheEventLogger.createICacheEvent( getEventLogSourceName(), item.getCacheName(), eventName, ipAddress,
517 item );
518 }
519
520 /**
521 * Logs an event if an event logger is configured.
522 * <p>
523 * @param cacheName
524 * @param key
525 * @param requesterId
526 * @param eventName
527 * @return ICacheEvent
528 */
529 protected <T extends Serializable> ICacheEvent<T> createICacheEvent( String cacheName, T key, long requesterId, String eventName )
530 {
531 if ( cacheEventLogger == null )
532 {
533 return new CacheEvent<T>();
534 }
535 String ipAddress = getExtraInfoForRequesterId( requesterId );
536 return cacheEventLogger.createICacheEvent( getEventLogSourceName(), cacheName, eventName, ipAddress, key );
537 }
538
539 /**
540 * Logs an event if an event logger is configured.
541 * <p>
542 * @param source
543 * @param eventName
544 * @param optionalDetails
545 */
546 protected void logApplicationEvent( String source, String eventName, String optionalDetails )
547 {
548 if ( cacheEventLogger != null )
549 {
550 cacheEventLogger.logApplicationEvent( source, eventName, optionalDetails );
551 }
552 }
553
554 /**
555 * Logs an event if an event logger is configured.
556 * <p>
557 * @param cacheEvent
558 */
559 protected <T extends Serializable> void logICacheEvent( ICacheEvent<T> cacheEvent )
560 {
561 if ( cacheEventLogger != null )
562 {
563 cacheEventLogger.logICacheEvent( cacheEvent );
564 }
565 }
566
567 /**
568 * Ip address for the client, if one is stored.
569 * <p>
570 * Protected for testing.
571 * <p>
572 * @param requesterId
573 * @return String
574 */
575 protected abstract String getExtraInfoForRequesterId( long requesterId );
576
577 /**
578 * Allows it to be injected.
579 * <p>
580 * @param cacheEventLogger
581 */
582 public void setCacheEventLogger( ICacheEventLogger cacheEventLogger )
583 {
584 this.cacheEventLogger = cacheEventLogger;
585 }
586
587 /**
588 * @param cacheManager the cacheManager to set
589 */
590 protected void setCacheManager( CompositeCacheManager cacheManager )
591 {
592 this.cacheManager = cacheManager;
593 }
594
595 /**
596 * @return the cacheManager
597 */
598 protected ICompositeCacheManager getCacheManager()
599 {
600 return cacheManager;
601 }
602
603 /**
604 * @param eventLogSourceName the eventLogSourceName to set
605 */
606 protected void setEventLogSourceName( String eventLogSourceName )
607 {
608 this.eventLogSourceName = eventLogSourceName;
609 }
610
611 /**
612 * @return the eventLogSourceName
613 */
614 protected String getEventLogSourceName()
615 {
616 return eventLogSourceName;
617 }
618 }