View Javadoc
1   /*
2    * Copyright (c) 2002-2022, City of Paris
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    *  1. Redistributions of source code must retain the above copyright notice
10   *     and the following disclaimer.
11   *
12   *  2. Redistributions in binary form must reproduce the above copyright notice
13   *     and the following disclaimer in the documentation and/or other materials
14   *     provided with the distribution.
15   *
16   *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17   *     contributors may be used to endorse or promote products derived from
18   *     this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   *
32   * License 1.0
33   */
34  package fr.paris.lutece.portal.service.cache;
35  
36  import fr.paris.lutece.portal.service.util.AppLogService;
37  
38  import net.sf.ehcache.Cache;
39  import net.sf.ehcache.CacheException;
40  import net.sf.ehcache.Ehcache;
41  import net.sf.ehcache.Element;
42  import net.sf.ehcache.Statistics;
43  import net.sf.ehcache.event.CacheEventListener;
44  
45  import java.util.ArrayList;
46  import java.util.List;
47  
48  import org.apache.logging.log4j.LogManager;
49  import org.apache.logging.log4j.Logger;
50  
51  /**
52   * Base implementation for a cacheable service
53   */
54  public abstract class AbstractCacheableService implements CacheableService, CacheEventListener
55  {
56      private Cache _cache;
57      private boolean _bEnable;
58      private Logger _logger = LogManager.getLogger( "lutece.cache" );
59  
60      /**
61       * Init the cache. Should be called by the service at its initialization.
62       */
63      public void initCache( )
64      {
65          initCache( getName( ) );
66      }
67  
68      /**
69       * Init the cache. Should be called by the service at its initialization.
70       * 
71       * @param strCacheName
72       *            The cache name
73       */
74      public void initCache( String strCacheName )
75      {
76          createCache( strCacheName );
77          _bEnable = true;
78          CacheService.registerCacheableService( this );
79      }
80  
81      /**
82       * Create a cache
83       * 
84       * @param strCacheName
85       *            The cache name
86       */
87      private void createCache( String strCacheName )
88      {
89          _cache = CacheService.getInstance( ).createCache( strCacheName );
90          _cache.getCacheEventNotificationService( ).registerListener( this );
91      }
92  
93      /**
94       * Put an object into the cache
95       * 
96       * @param strKey
97       *            The key of the object to put into the cache
98       * @param object
99       *            The object to put into the cache
100      */
101     public void putInCache( String strKey, Object object )
102     {
103         if ( ( _cache != null ) && isCacheEnable( ) )
104         {
105             Element element = new Element( strKey, object );
106             _cache.put( element );
107         }
108     }
109 
110     /**
111      * Gets an object from the cache
112      * 
113      * @param strKey
114      *            The key of the object to retrieve from the cache
115      * @return The object from the cache
116      */
117     public Object getFromCache( String strKey )
118     {
119         Object object = null;
120 
121         if ( ( _cache != null ) && isCacheEnable( ) )
122         {
123             Element element = _cache.get( strKey );
124 
125             if ( element != null )
126             {
127                 object = element.getObjectValue( );
128             }
129         }
130 
131         return object;
132     }
133 
134     /**
135      * Gets the current cache status.
136      *
137      * @return true if enable, otherwise false
138      */
139     @Override
140     public boolean isCacheEnable( )
141     {
142         return _bEnable;
143     }
144 
145     /**
146      * {@inheritDoc }
147      */
148     @Override
149     public void enableCache( boolean bEnable )
150     {
151         _bEnable = bEnable;
152 
153         if ( ( !_bEnable ) && ( _cache != null ) )
154         {
155             _cache.removeAll( );
156         }
157 
158         if ( ( _bEnable ) && ( _cache == null ) )
159         {
160             createCache( getName( ) );
161         }
162 
163         CacheService.updateCacheStatus( this );
164     }
165 
166     /**
167      * Reset the cache.
168      */
169     @Override
170     public void resetCache( )
171     {
172         try
173         {
174             if ( _cache != null )
175             {
176                 _cache.removeAll( );
177             }
178         }
179         catch( CacheException | IllegalStateException e )
180         {
181             AppLogService.error( e.getMessage( ), e );
182         }
183     }
184 
185     /**
186      * Gets the number of item currently in the cache.
187      *
188      * @return the number of item currently in the cache.
189      */
190     @Override
191     public int getCacheSize( )
192     {
193         return ( _cache != null ) ? _cache.getSize( ) : 0;
194     }
195 
196     /**
197      * Return a cache object
198      * 
199      * @return cache object
200      */
201     public Cache getCache( )
202     {
203         return _cache;
204     }
205 
206     /**
207      * {@inheritDoc }
208      */
209     @Override
210     public List<String> getKeys( )
211     {
212         if ( _cache != null )
213         {
214             return _cache.getKeys( );
215         }
216 
217         return new ArrayList<>( );
218     }
219 
220     /**
221      * {@inheritDoc }
222      */
223     @Override
224     public int getMaxElements( )
225     {
226         return _cache.getCacheConfiguration( ).getMaxElementsInMemory( );
227     }
228 
229     /**
230      * {@inheritDoc }
231      */
232     @Override
233     public long getTimeToLive( )
234     {
235         return _cache.getCacheConfiguration( ).getTimeToLiveSeconds( );
236     }
237 
238     /**
239      * {@inheritDoc }
240      */
241     @Override
242     public long getMemorySize( )
243     {
244         return _cache.calculateInMemorySize( );
245     }
246 
247     /**
248      * {@inheritDoc }
249      */
250     @Override
251     public String getInfos( )
252     {
253         return CacheService.getInfos( _cache );
254     }
255 
256     /**
257      * Get cache statistics.
258      * 
259      * The string representation is susceptible to change
260      * 
261      * @return a string representation of cache statistics
262      * 
263      * @since 7.0.10
264      */
265     public String getStatistics( )
266     {
267         if ( !( isCacheEnable( ) && _cache.getCacheConfiguration( ).getStatistics( ) ) )
268         {
269             return null;
270         }
271         Statistics stats = _cache.getStatistics( );
272         StringBuilder buidler = new StringBuilder( );
273         buidler.append( "name = " ).append( stats.getAssociatedCacheName( ) ).append( "\ncacheHits = " )
274                 .append( stats.getCacheHits( ) ).append( "\nonDiskHits = " ).append( stats.getOnDiskHits( ) )
275                 .append( "\noffHeapHits = " ).append( stats.getOffHeapHits( ) ).append( "\ninMemoryHits = " )
276                 .append( stats.getInMemoryHits( ) ).append( "\nmisses = " ).append( stats.getCacheMisses( ) )
277                 .append( "\nonDiskMisses = " ).append( stats.getOnDiskMisses( ) ).append( "\noffHeapMisses = " )
278                 .append( stats.getOffHeapMisses( ) ).append( "\ninMemoryMisses = " )
279                 .append( stats.getInMemoryMisses( ) ).append( "\nsize = " ).append( stats.getObjectCount( ) )
280                 .append( "\naverageGetTime = " ).append( stats.getAverageGetTime( ) ).append( "\nevictionCount = " )
281                 .append( stats.getEvictionCount( ) );
282         return buidler.toString( );
283     }
284 
285     // CacheEventListener implementation
286 
287     /**
288      * @see java.lang.Object#clone()
289      * @return the instance
290      */
291     @Override
292     public Object clone( )
293     {
294         throw new UnsupportedOperationException( "This class shouldn't be cloned" );
295     }
296 
297     /**
298      * {@inheritDoc }
299      */
300     @Override
301     public void notifyElementExpired( Ehcache cache, Element element )
302     {
303         // Remove the element from the cache
304         _cache.remove( element.getKey( ) );
305         _logger.debug( "Object removed from the cache : {}  - key : {}", cache.getName( ), element.getKey( ) );
306     }
307 
308     /**
309      * {@inheritDoc }
310      */
311     @Override
312     public void notifyElementRemoved( Ehcache ehch, Element elmnt )
313     {
314         // Do nothing
315     }
316 
317     /**
318      * {@inheritDoc }
319      */
320     @Override
321     public void notifyElementEvicted( Ehcache ehch, Element elmnt )
322     {
323         // Do nothing
324     }
325 
326     /**
327      * {@inheritDoc }
328      */
329     @Override
330     public void notifyRemoveAll( Ehcache ehch )
331     {
332         // Do nothing
333     }
334 
335     /**
336      * {@inheritDoc }
337      */
338     @Override
339     public void notifyElementPut( Ehcache ehch, Element elmnt )
340     {
341         // Do nothing
342     }
343 
344     /**
345      * {@inheritDoc }
346      */
347     @Override
348     public void notifyElementUpdated( Ehcache ehch, Element elmnt )
349     {
350         // Do nothing
351     }
352 
353     /**
354      * {@inheritDoc }
355      */
356     @Override
357     public void dispose( )
358     {
359         // Do nothing
360     }
361 
362     /**
363      * Remove a key from the cache
364      * 
365      * @param strKey
366      *            The key to remove
367      */
368     public void removeKey( String strKey )
369     {
370         getCache( ).remove( strKey );
371     }
372 }