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