View Javadoc
1   package org.apache.commons.jcs3.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.jcs3.engine.behavior.ICacheElement;
28  import org.apache.commons.jcs3.engine.behavior.ICacheServiceNonLocal;
29  import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
30  import org.apache.commons.jcs3.engine.control.CompositeCache;
31  import org.apache.commons.jcs3.engine.logging.CacheEvent;
32  import org.apache.commons.jcs3.engine.logging.behavior.ICacheEvent;
33  import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
34  import org.apache.commons.jcs3.log.Log;
35  import org.apache.commons.jcs3.log.LogManager;
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;
55  
56      /** The interval at which we will log updates. */
57      private final static int logInterval = 100;
58  
59      /** log instance */
60      private static final Log log = LogManager.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( final ICompositeCacheManager cacheManager, final 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( final 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( final ICacheElement<K, V> item, final long requesterId )
94          throws IOException
95      {
96          final 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( final 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 = {0}", puts );
133             }
134         }
135 
136         log.debug( "In update, put [{0}] in [{1}]", item::getKey,
137                 item::getCacheName);
138     }
139 
140     /**
141      * Returns a cache value from the specified remote cache; or null if the cache or key does not
142      * exist.
143      * <p>
144      * @param cacheName
145      * @param key
146      * @return ICacheElement
147      * @throws IOException
148      */
149     @Override
150     public ICacheElement<K, V> get( final String cacheName, final 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     @Override
170     public ICacheElement<K, V> get( final String cacheName, final K key, final long requesterId )
171         throws IOException
172     {
173         ICacheElement<K, V> element = null;
174         final ICacheEvent<K> cacheEvent = createICacheEvent( cacheName, key, requesterId, ICacheEventLogger.GET_EVENT );
175         try
176         {
177             element = processGet( cacheName, key, requesterId );
178         }
179         finally
180         {
181             logICacheEvent( cacheEvent );
182         }
183         return element;
184     }
185 
186     /**
187      * Returns a cache bean from the specified cache; or null if the key does not exist.
188      * <p>
189      * Adding the requestor id, allows the cache to determine the source of the get.
190      * <p>
191      * @param cacheName
192      * @param key
193      * @param requesterId
194      * @return ICacheElement
195      * @throws IOException
196      */
197     abstract ICacheElement<K, V> processGet( String cacheName, K key, long requesterId )
198         throws IOException;
199 
200     /**
201      * Gets all matching items.
202      * <p>
203      * @param cacheName
204      * @param pattern
205      * @return Map of keys and wrapped objects
206      * @throws IOException
207      */
208     @Override
209     public Map<K, ICacheElement<K, V>> getMatching( final String cacheName, final String pattern )
210         throws IOException
211     {
212         return getMatching( cacheName, pattern, 0 );
213     }
214 
215     /**
216      * Retrieves all matching keys.
217      * <p>
218      * @param cacheName
219      * @param pattern
220      * @param requesterId
221      * @return Map of keys and wrapped objects
222      * @throws IOException
223      */
224     @Override
225     public Map<K, ICacheElement<K, V>> getMatching( final String cacheName, final String pattern, final long requesterId )
226         throws IOException
227     {
228         final ICacheEvent<String> 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<K, ICacheElement<K, V>> 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 K key to ICacheElement&lt;K, V&gt; element, or an empty map if there is no
258      *         data in cache for any of these keys
259      * @throws IOException
260      */
261     @Override
262     public Map<K, ICacheElement<K, V>> getMultiple( final String cacheName, final Set<K> keys )
263         throws IOException
264     {
265         return this.getMultiple( cacheName, keys, 0 );
266     }
267 
268     /**
269      * Gets multiple items from the cache based on the given set of keys.
270      * <p>
271      * The internal processing is wrapped in event logging calls.
272      * <p>
273      * @param cacheName
274      * @param keys
275      * @param requesterId
276      * @return a map of K key to ICacheElement&lt;K, V&gt; element, or an empty map if there is no
277      *         data in cache for any of these keys
278      * @throws IOException
279      */
280     @Override
281     public Map<K, ICacheElement<K, V>> getMultiple( final String cacheName, final Set<K> keys, final long requesterId )
282         throws IOException
283     {
284         final ICacheEvent<Serializable> cacheEvent = createICacheEvent( cacheName, (Serializable) keys, requesterId,
285                                                     ICacheEventLogger.GETMULTIPLE_EVENT );
286         try
287         {
288             return processGetMultiple( cacheName, keys, requesterId );
289         }
290         finally
291         {
292             logICacheEvent( cacheEvent );
293         }
294     }
295 
296     /**
297      * Gets multiple items from the cache based on the given set of keys.
298      * <p>
299      * @param cacheName
300      * @param keys
301      * @param requesterId
302      * @return a map of K key to ICacheElement&lt;K, V&gt; element, or an empty map if there is no
303      *         data in cache for any of these keys
304      * @throws IOException
305      */
306     abstract Map<K, ICacheElement<K, V>> processGetMultiple( String cacheName, Set<K> keys, long requesterId )
307         throws IOException;
308 
309     /**
310      * Return the keys in this cache.
311      * <p>
312      * @see org.apache.commons.jcs3.auxiliary.AuxiliaryCache#getKeySet()
313      */
314     @Override
315     public Set<K> getKeySet( final String cacheName )
316     {
317         return processGetKeySet( cacheName );
318     }
319 
320     /**
321      * Gets the set of keys of objects currently in the cache.
322      * <p>
323      * @param cacheName
324      * @return Set
325      */
326     public Set<K> processGetKeySet( final String cacheName )
327     {
328         final CompositeCache<K, V> cache = getCacheManager().getCache( cacheName );
329 
330         return cache.getKeySet();
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     @Override
341     public void remove( final String cacheName, final K key )
342         throws IOException
343     {
344         remove( cacheName, key, 0 );
345     }
346 
347     /**
348      * Remove the key from the cache region and don't tell the source listener about it.
349      * <p>
350      * The internal processing is wrapped in event logging calls.
351      * <p>
352      * @param cacheName
353      * @param key
354      * @param requesterId
355      * @throws IOException
356      */
357     @Override
358     public void remove( final String cacheName, final K key, final long requesterId )
359         throws IOException
360     {
361         final ICacheEvent<K> cacheEvent = createICacheEvent( cacheName, key, requesterId, ICacheEventLogger.REMOVE_EVENT );
362         try
363         {
364             processRemove( cacheName, key, requesterId );
365         }
366         finally
367         {
368             logICacheEvent( cacheEvent );
369         }
370     }
371 
372     /**
373      * Remove the key from the cache region and don't tell the source listener about it.
374      * <p>
375      * @param cacheName
376      * @param key
377      * @param requesterId
378      * @throws IOException
379      */
380     abstract void processRemove( String cacheName, K key, long requesterId )
381         throws IOException;
382 
383     /**
384      * Remove all keys from the specified remote cache.
385      * <p>
386      * @param cacheName
387      * @throws IOException
388      */
389     @Override
390     public void removeAll( final String cacheName )
391         throws IOException
392     {
393         removeAll( cacheName, 0 );
394     }
395 
396     /**
397      * Remove all keys from the specified remote cache.
398      * <p>
399      * The internal processing is wrapped in event logging calls.
400      * <p>
401      * @param cacheName
402      * @param requesterId
403      * @throws IOException
404      */
405     @Override
406     public void removeAll( final String cacheName, final long requesterId )
407         throws IOException
408     {
409         final ICacheEvent<String> cacheEvent = createICacheEvent( cacheName, "all", requesterId, ICacheEventLogger.REMOVEALL_EVENT );
410         try
411         {
412             processRemoveAll( cacheName, requesterId );
413         }
414         finally
415         {
416             logICacheEvent( cacheEvent );
417         }
418     }
419 
420     /**
421      * Remove all keys from the specified remote cache.
422      * <p>
423      * @param cacheName
424      * @param requesterId
425      * @throws IOException
426      */
427     abstract void processRemoveAll( String cacheName, long requesterId )
428         throws IOException;
429 
430     /**
431      * Frees the specified remote cache.
432      * <p>
433      * @param cacheName
434      * @throws IOException
435      */
436     @Override
437     public void dispose( final String cacheName )
438         throws IOException
439     {
440         dispose( cacheName, 0 );
441     }
442 
443     /**
444      * Frees the specified remote cache.
445      * <p>
446      * @param cacheName
447      * @param requesterId
448      * @throws IOException
449      */
450     public void dispose( final String cacheName, final long requesterId )
451         throws IOException
452     {
453         final ICacheEvent<String> cacheEvent = createICacheEvent( cacheName, "none", requesterId, ICacheEventLogger.DISPOSE_EVENT );
454         try
455         {
456             processDispose( cacheName, requesterId );
457         }
458         finally
459         {
460             logICacheEvent( cacheEvent );
461         }
462     }
463 
464     /**
465      * @param cacheName
466      * @param requesterId
467      * @throws IOException
468      */
469     abstract void processDispose( String cacheName, long requesterId )
470         throws IOException;
471 
472     /**
473      * Gets the stats attribute of the RemoteCacheServer object.
474      * <p>
475      * @return The stats value
476      * @throws IOException
477      */
478     public String getStats()
479         throws IOException
480     {
481         return cacheManager.getStats();
482     }
483 
484     /**
485      * Logs an event if an event logger is configured.
486      * <p>
487      * @param item
488      * @param requesterId
489      * @param eventName
490      * @return ICacheEvent
491      */
492     protected ICacheEvent<ICacheElement<K, V>> createICacheEvent( final ICacheElement<K, V> item, final long requesterId, final String eventName )
493     {
494         if ( cacheEventLogger == null )
495         {
496             return new CacheEvent<>();
497         }
498         final String ipAddress = getExtraInfoForRequesterId( requesterId );
499         return cacheEventLogger.createICacheEvent( getEventLogSourceName(), item.getCacheName(), eventName, ipAddress,
500                                                    item );
501     }
502 
503     /**
504      * Logs an event if an event logger is configured.
505      * <p>
506      * @param cacheName
507      * @param key
508      * @param requesterId
509      * @param eventName
510      * @return ICacheEvent
511      */
512     protected <T> ICacheEvent<T> createICacheEvent( final String cacheName, final T key, final long requesterId, final String eventName )
513     {
514         if ( cacheEventLogger == null )
515         {
516             return new CacheEvent<>();
517         }
518         final String ipAddress = getExtraInfoForRequesterId( requesterId );
519         return cacheEventLogger.createICacheEvent( getEventLogSourceName(), cacheName, eventName, ipAddress, key );
520     }
521 
522     /**
523      * Logs an event if an event logger is configured.
524      * <p>
525      * @param source
526      * @param eventName
527      * @param optionalDetails
528      */
529     protected void logApplicationEvent( final String source, final String eventName, final String optionalDetails )
530     {
531         if ( cacheEventLogger != null )
532         {
533             cacheEventLogger.logApplicationEvent( source, eventName, optionalDetails );
534         }
535     }
536 
537     /**
538      * Logs an event if an event logger is configured.
539      * <p>
540      * @param cacheEvent
541      */
542     protected <T> void logICacheEvent( final ICacheEvent<T> cacheEvent )
543     {
544         if ( cacheEventLogger != null )
545         {
546             cacheEventLogger.logICacheEvent( cacheEvent );
547         }
548     }
549 
550     /**
551      * Ip address for the client, if one is stored.
552      * <p>
553      * Protected for testing.
554      * <p>
555      * @param requesterId
556      * @return String
557      */
558     protected abstract String getExtraInfoForRequesterId( long requesterId );
559 
560     /**
561      * Allows it to be injected.
562      * <p>
563      * @param cacheEventLogger
564      */
565     public void setCacheEventLogger( final ICacheEventLogger cacheEventLogger )
566     {
567         this.cacheEventLogger = cacheEventLogger;
568     }
569 
570     /**
571      * @param cacheManager the cacheManager to set
572      */
573     protected void setCacheManager( final ICompositeCacheManager cacheManager )
574     {
575         this.cacheManager = cacheManager;
576     }
577 
578     /**
579      * @return the cacheManager
580      */
581     protected ICompositeCacheManager getCacheManager()
582     {
583         return cacheManager;
584     }
585 
586     /**
587      * @param eventLogSourceName the eventLogSourceName to set
588      */
589     protected void setEventLogSourceName( final String eventLogSourceName )
590     {
591         this.eventLogSourceName = eventLogSourceName;
592     }
593 
594     /**
595      * @return the eventLogSourceName
596      */
597     protected String getEventLogSourceName()
598     {
599         return eventLogSourceName;
600     }
601 }