1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package fr.paris.lutece.portal.service.cache;
35
36 import fr.paris.lutece.portal.service.datastore.DatastoreService;
37 import fr.paris.lutece.portal.service.util.AppLogService;
38 import fr.paris.lutece.portal.service.util.AppPathService;
39 import fr.paris.lutece.portal.service.util.AppPropertiesService;
40
41 import net.sf.ehcache.Cache;
42 import net.sf.ehcache.CacheManager;
43 import net.sf.ehcache.config.CacheConfiguration;
44 import net.sf.ehcache.management.ManagementService;
45
46 import java.io.File;
47 import java.io.FileInputStream;
48 import java.io.FileNotFoundException;
49 import java.io.IOException;
50
51 import java.lang.management.ManagementFactory;
52
53 import java.util.ArrayList;
54 import java.util.List;
55 import java.util.Properties;
56
57 import javax.management.MBeanServer;
58
59
60
61
62
63 public final class CacheService
64 {
65 private static final String PROPERTY_PATH_CONF = "path.conf";
66 private static final String PROPERTY_IS_ENABLED = ".enabled";
67 private static final String FILE_CACHES_STATUS = "caches.dat";
68
69
70 private static final String PROPERTY_MAX_ELEMENTS = ".maxElementsInMemory";
71 private static final String PROPERTY_ETERNAL = ".eternal";
72 private static final String PROPERTY_TIME_TO_IDLE = ".timeToIdleSeconds";
73 private static final String PROPERTY_TIME_TO_LIVE = ".timeToLiveSeconds";
74 private static final String PROPERTY_OVERFLOW_TO_DISK = ".overflowToDisk";
75 private static final String PROPERTY_DISK_PERSISTENT = ".diskPersistent";
76 private static final String PROPERTY_DISK_EXPIRY = ".diskExpiryThreadIntervalSeconds";
77 private static final String PROPERTY_MAX_ELEMENTS_DISK = ".maxElementsOnDisk";
78 private static final String PROPERTY_STATISTICS = ".statistics";
79
80
81 private static final String KEY_PREFIX = "core.cache.status.";
82
83
84 private static final String PROPERTY_JMX_MONITORING = "lutece.cache.jmx.monitoring.enabled";
85 private static final String PROPERTY_MONITOR_CACHE_MANAGER = "lutece.cache.jmx.monitorCacheManager";
86 private static final String PROPERTY_MONITOR_CACHES = "lutece.cache.jmx.monitorCaches";
87 private static final String PROPERTY_MONITOR_CACHE_CONFIGURATIONS = "lutece.cache.jmx.monitorCacheConfiguration";
88 private static final String PROPERTY_MONITOR_CACHE_STATISTICS = "lutece.cache.jmx.monitorCacheStatistics";
89 private static final String FALSE = "false";
90 private static final String TRUE = "true";
91 private static final String ENABLED = "1";
92 private static final String DISABLED = "0";
93 private static final String NOT_FOUND = "NOT FOUND";
94 private static final String PREFIX_DEFAULT = "lutece.cache.default";
95 private static CacheService _singleton;
96 private static CacheManager _manager;
97
98
99
100 private static List<CacheableService> _listCacheableServicesRegistry = new ArrayList<CacheableService>( );
101 private int _nDefaultMaxElementsInMemory;
102 private boolean _bDefaultEternal;
103 private long _lDefaultTimeToIdle;
104 private long _lDefaultTimeToLive;
105 private boolean _bDefaultOverflowToDisk;
106 private boolean _bDefaultDiskPersistent;
107 private long _lDefaultDiskExpiry;
108 private int _nDefaultMaxElementsOnDisk;
109 private boolean _bDefaultStatistics;
110
111
112
113
114 private CacheService( )
115 {
116 }
117
118
119
120
121
122
123 public static synchronized CacheService getInstance( )
124 {
125 if ( _singleton == null )
126 {
127 _singleton = new CacheService( );
128 _singleton.init( );
129 }
130
131 return _singleton;
132 }
133
134
135
136
137
138 private void init( )
139 {
140 _manager = CacheManager.create( );
141 loadDefaults( );
142 loadCachesConfig( );
143
144 boolean bJmxMonitoring = AppPropertiesService.getProperty( PROPERTY_JMX_MONITORING, FALSE ).equals( TRUE );
145
146 if ( bJmxMonitoring )
147 {
148 initJmxMonitoring( );
149 }
150 }
151
152
153
154
155 private void initJmxMonitoring( )
156 {
157 MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer( );
158
159 boolean bRegisterCacheManager = AppPropertiesService.getProperty( PROPERTY_MONITOR_CACHE_MANAGER, FALSE )
160 .equals( TRUE );
161 boolean bRegisterCaches = AppPropertiesService.getProperty( PROPERTY_MONITOR_CACHES, FALSE ).equals( TRUE );
162 boolean bRegisterCacheConfigurations = AppPropertiesService.getProperty( PROPERTY_MONITOR_CACHE_CONFIGURATIONS,
163 FALSE ).equals( TRUE );
164 boolean bRegisterCacheStatistics = AppPropertiesService.getProperty( PROPERTY_MONITOR_CACHE_STATISTICS, FALSE )
165 .equals( TRUE );
166 ManagementService.registerMBeans( _manager, mBeanServer, bRegisterCacheManager, bRegisterCaches,
167 bRegisterCacheConfigurations, bRegisterCacheStatistics );
168 }
169
170
171
172
173
174
175
176 public Cache createCache( String strCacheName )
177 {
178 Cache cache = new Cache( getCacheConfiguration( strCacheName ) );
179 _manager.addCache( cache );
180
181 return _manager.getCache( strCacheName );
182 }
183
184
185
186
187 public static void resetCaches( )
188 {
189
190 for ( CacheableService cs : _listCacheableServicesRegistry )
191 {
192 cs.resetCache( );
193 }
194 }
195
196
197
198
199
200 public void shutdown( )
201 {
202 CacheService.storeCachesStatus( );
203 _manager.shutdown( );
204 }
205
206
207
208
209
210
211
212
213 @Deprecated
214 public static void registerCacheableService( String strName, CacheableService cs )
215 {
216 registerCacheableService( cs );
217 }
218
219
220
221
222
223
224 public static void registerCacheableService( CacheableService cs )
225 {
226 _listCacheableServicesRegistry.add( cs );
227
228
229 cs.enableCache( getStatus( cs ) );
230 }
231
232
233
234
235
236
237 public static List<CacheableService> getCacheableServicesList( )
238 {
239 return _listCacheableServicesRegistry;
240 }
241
242
243
244
245 public static void storeCachesStatus( )
246 {
247 for ( CacheableService cs : _listCacheableServicesRegistry )
248 {
249 String strKey = getDSKey( cs.getName( ), PROPERTY_IS_ENABLED );
250 DatastoreService.setInstanceDataValue( strKey, cs.isCacheEnable( ) ? ENABLED : DISABLED );
251 }
252 }
253
254
255
256
257
258
259
260 static String getInfos( Cache cache )
261 {
262 StringBuilder sbInfos = new StringBuilder( );
263 sbInfos.append( PROPERTY_MAX_ELEMENTS ).append( "=" )
264 .append( cache.getCacheConfiguration( ).getMaxElementsInMemory( ) ).append( "\n" );
265 sbInfos.append( PROPERTY_ETERNAL ).append( "=" ).append( cache.getCacheConfiguration( ).isEternal( ) )
266 .append( "\n" );
267 sbInfos.append( PROPERTY_TIME_TO_IDLE ).append( "=" )
268 .append( cache.getCacheConfiguration( ).getTimeToIdleSeconds( ) ).append( "\n" );
269 sbInfos.append( PROPERTY_TIME_TO_LIVE ).append( "=" )
270 .append( cache.getCacheConfiguration( ).getTimeToLiveSeconds( ) ).append( "\n" );
271 sbInfos.append( PROPERTY_OVERFLOW_TO_DISK ).append( "=" )
272 .append( cache.getCacheConfiguration( ).isOverflowToDisk( ) ).append( "\n" );
273 sbInfos.append( PROPERTY_DISK_PERSISTENT ).append( "=" )
274 .append( cache.getCacheConfiguration( ).isDiskPersistent( ) ).append( "\n" );
275 sbInfos.append( PROPERTY_DISK_EXPIRY ).append( "=" )
276 .append( cache.getCacheConfiguration( ).getDiskExpiryThreadIntervalSeconds( ) ).append( "\n" );
277 sbInfos.append( PROPERTY_MAX_ELEMENTS_DISK ).append( "=" )
278 .append( cache.getCacheConfiguration( ).getMaxElementsOnDisk( ) ).append( "\n" );
279 sbInfos.append( PROPERTY_STATISTICS ).append( '=' ).append( cache.getCacheConfiguration( ).getStatistics( ) )
280 .append( "\n" );
281
282 return sbInfos.toString( );
283 }
284
285
286
287
288 private void loadDefaults( )
289 {
290 _nDefaultMaxElementsInMemory = AppPropertiesService.getPropertyInt( PREFIX_DEFAULT + PROPERTY_MAX_ELEMENTS,
291 10000 );
292 _bDefaultEternal = AppPropertiesService.getPropertyBoolean( PREFIX_DEFAULT + PROPERTY_ETERNAL, false );
293 _lDefaultTimeToIdle = AppPropertiesService.getPropertyLong( PREFIX_DEFAULT + PROPERTY_TIME_TO_IDLE, 10000L );
294 _lDefaultTimeToLive = AppPropertiesService.getPropertyLong( PREFIX_DEFAULT + PROPERTY_TIME_TO_LIVE, 10000L );
295 _bDefaultOverflowToDisk = AppPropertiesService.getPropertyBoolean( PREFIX_DEFAULT + PROPERTY_OVERFLOW_TO_DISK,
296 true );
297 _bDefaultDiskPersistent = AppPropertiesService.getPropertyBoolean( PREFIX_DEFAULT + PROPERTY_DISK_PERSISTENT,
298 true );
299 _lDefaultDiskExpiry = AppPropertiesService.getPropertyLong( PREFIX_DEFAULT + PROPERTY_DISK_EXPIRY, 120L );
300 _nDefaultMaxElementsOnDisk = AppPropertiesService.getPropertyInt( PREFIX_DEFAULT + PROPERTY_MAX_ELEMENTS_DISK,
301 10000 );
302 _bDefaultStatistics = AppPropertiesService.getPropertyBoolean( PREFIX_DEFAULT + PROPERTY_STATISTICS, false );
303 }
304
305
306
307
308 private void loadCachesConfig( )
309 {
310 String strCachesStatusFile = AppPathService.getPath( PROPERTY_PATH_CONF, FILE_CACHES_STATUS );
311 File file = new File( strCachesStatusFile );
312
313 FileInputStream fis = null;
314
315 try
316 {
317 Properties properties = new Properties( );
318 fis = new FileInputStream( file );
319 properties.load( fis );
320
321
322 for ( String strKey : properties.stringPropertyNames( ) )
323 {
324 String strDSKey = KEY_PREFIX + strKey;
325
326 if ( !DatastoreService.existsInstanceKey( strDSKey ) )
327 {
328 String strValue = properties.getProperty( strKey );
329 DatastoreService.setInstanceDataValue( strDSKey, strValue );
330 }
331 }
332 }
333 catch ( FileNotFoundException e )
334 {
335 AppLogService.error( "No cache.dat file. Should be created at shutdown." );
336 }
337 catch ( Exception e )
338 {
339 AppLogService.error( "Error loading caches status defined in file : " + file.getAbsolutePath( ), e );
340 }
341 finally
342 {
343 if ( fis != null )
344 {
345 try
346 {
347 fis.close( );
348 }
349 catch ( IOException e )
350 {
351 AppLogService.error( e.getMessage( ), e );
352 }
353 }
354 }
355 }
356
357
358
359
360
361 public static void updateCacheStatus( CacheableService cs )
362 {
363 String strKey = getDSKey( cs.getName( ), PROPERTY_IS_ENABLED );
364 DatastoreService.setInstanceDataValue( strKey, ( cs.isCacheEnable( ) ? ENABLED : DISABLED ) );
365 }
366
367
368
369
370
371
372
373 private static boolean getStatus( CacheableService cs )
374 {
375 String strEnabled = DatastoreService.getInstanceDataValue( getDSKey( cs.getName( ), PROPERTY_IS_ENABLED ),
376 DISABLED );
377
378 return strEnabled.equals( ENABLED );
379 }
380
381
382
383
384
385
386
387 private static String getDSKey( String strCacheName, String strProperty )
388 {
389 return KEY_PREFIX + normalizeName( strCacheName ) + strProperty;
390 }
391
392
393
394
395
396
397
398 private static String normalizeName( String strName )
399 {
400 return strName.replace( " ", "" );
401 }
402
403
404
405
406
407
408
409 private CacheConfiguration getCacheConfiguration( String strCacheName )
410 {
411 CacheConfiguration config = new CacheConfiguration( );
412 config.setName( strCacheName );
413 config.setMaxElementsInMemory( getIntProperty( strCacheName, PROPERTY_MAX_ELEMENTS, _nDefaultMaxElementsInMemory ) );
414 config.setEternal( getBooleanProperty( strCacheName, PROPERTY_ETERNAL, _bDefaultEternal ) );
415 config.setTimeToIdleSeconds( getLongProperty( strCacheName, PROPERTY_TIME_TO_IDLE, _lDefaultTimeToIdle ) );
416 config.setTimeToLiveSeconds( getLongProperty( strCacheName, PROPERTY_TIME_TO_LIVE, _lDefaultTimeToLive ) );
417 config.setOverflowToDisk( getBooleanProperty( strCacheName, PROPERTY_OVERFLOW_TO_DISK, _bDefaultOverflowToDisk ) );
418 config.setDiskPersistent( getBooleanProperty( strCacheName, PROPERTY_DISK_PERSISTENT, _bDefaultDiskPersistent ) );
419 config.setDiskExpiryThreadIntervalSeconds( getLongProperty( strCacheName, PROPERTY_DISK_EXPIRY,
420 _lDefaultDiskExpiry ) );
421 config.setMaxElementsOnDisk( getIntProperty( strCacheName, PROPERTY_MAX_ELEMENTS_DISK,
422 _nDefaultMaxElementsOnDisk ) );
423 config.setStatistics( getBooleanProperty( strCacheName, PROPERTY_STATISTICS, _bDefaultStatistics ) );
424
425 return config;
426 }
427
428
429
430
431
432
433
434
435
436 private int getIntProperty( String strCacheName, String strProperty, int nDefault )
437 {
438 String strKey = getDSKey( strCacheName, strProperty );
439
440 if ( DatastoreService.existsInstanceKey( strKey ) )
441 {
442 String strValue = NOT_FOUND;
443
444 try
445 {
446 strValue = DatastoreService.getInstanceDataValue( strKey, strValue );
447
448 int nValue = Integer.parseInt( strValue );
449
450 return nValue;
451 }
452 catch ( NumberFormatException e )
453 {
454 AppLogService.error( "Invalid numeric property : " + strCacheName + strProperty + "=" + strValue, e );
455 }
456 }
457
458 return nDefault;
459 }
460
461
462
463
464
465
466
467
468
469 private long getLongProperty( String strCacheName, String strProperty, long lDefault )
470 {
471 String strKey = getDSKey( strCacheName, strProperty );
472
473 if ( DatastoreService.existsInstanceKey( strKey ) )
474 {
475 String strValue = NOT_FOUND;
476
477 try
478 {
479 strValue = DatastoreService.getInstanceDataValue( strKey, strValue );
480
481 long lValue = Integer.parseInt( strValue );
482
483 return lValue;
484 }
485 catch ( NumberFormatException e )
486 {
487 AppLogService.error( "Invalid numeric property : " + strCacheName + strProperty + "=" + strValue, e );
488 }
489 }
490
491 return lDefault;
492 }
493
494
495
496
497
498
499
500
501
502 private boolean getBooleanProperty( String strCacheName, String strProperty, boolean bDefault )
503 {
504 String strKey = getDSKey( strCacheName, strProperty );
505
506 if ( DatastoreService.existsInstanceKey( strKey ) )
507 {
508 String strValue = DatastoreService.getInstanceDataValue( strKey, NOT_FOUND );
509
510 return ( strValue.equalsIgnoreCase( TRUE ) );
511 }
512
513 return bDefault;
514 }
515 }