1 package org.apache.jcs.engine.control;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.Serializable;
25 import java.security.AccessControlException;
26 import java.util.ArrayList;
27 import java.util.HashSet;
28 import java.util.Hashtable;
29 import java.util.Iterator;
30 import java.util.Properties;
31 import java.util.Set;
32
33 import org.apache.commons.logging.Log;
34 import org.apache.commons.logging.LogFactory;
35 import org.apache.jcs.access.exception.CacheException;
36 import org.apache.jcs.auxiliary.AuxiliaryCacheAttributes;
37 import org.apache.jcs.auxiliary.AuxiliaryCacheFactory;
38 import org.apache.jcs.auxiliary.remote.behavior.IRemoteCacheConstants;
39 import org.apache.jcs.engine.CacheConstants;
40 import org.apache.jcs.engine.CompositeCacheAttributes;
41 import org.apache.jcs.engine.ElementAttributes;
42 import org.apache.jcs.engine.behavior.ICache;
43 import org.apache.jcs.engine.behavior.ICacheType;
44 import org.apache.jcs.engine.behavior.ICompositeCacheAttributes;
45 import org.apache.jcs.engine.behavior.ICompositeCacheManager;
46 import org.apache.jcs.engine.behavior.IElementAttributes;
47 import org.apache.jcs.engine.behavior.IShutdownObservable;
48 import org.apache.jcs.engine.behavior.IShutdownObserver;
49 import org.apache.jcs.engine.stats.CacheStats;
50 import org.apache.jcs.engine.stats.behavior.ICacheStats;
51 import org.apache.jcs.utils.threadpool.ThreadPoolManager;
52
53
54
55
56
57
58
59
60
61
62
63 public class CompositeCacheManager
64 implements IRemoteCacheConstants, Serializable, ICompositeCacheManager, IShutdownObservable
65 {
66
67 private static final long serialVersionUID = 7598584393134401756L;
68
69
70 protected final static Log log = LogFactory.getLog( CompositeCacheManager.class );
71
72
73 protected Hashtable<String, ICache> caches = new Hashtable<String, ICache>();
74
75
76 protected Hashtable<String, ICache> systemCaches = new Hashtable<String, ICache>();
77
78
79 private int clients;
80
81
82 protected ICompositeCacheAttributes defaultCacheAttr = new CompositeCacheAttributes();
83
84
85 protected IElementAttributes defaultElementAttr = new ElementAttributes();
86
87
88 protected Hashtable<String, AuxiliaryCacheFactory> auxiliaryFactoryRegistry =
89 new Hashtable<String, AuxiliaryCacheFactory>( 11 );
90
91
92 protected Hashtable<String, AuxiliaryCacheAttributes> auxiliaryAttributeRegistry =
93 new Hashtable<String, AuxiliaryCacheAttributes>( 11 );
94
95
96 private Properties configurationProperties;
97
98
99 protected String defaultAuxValues;
100
101
102 protected static CompositeCacheManager instance;
103
104
105 private static final String SYSTEM_PROPERTY_KEY_PREFIX = "jcs";
106
107
108 private static final boolean DEFAULT_USE_SYSTEM_PROPERTIES = true;
109
110
111 private static final boolean DEFAULT_FORCE_RECONFIGURATION = false;
112
113
114 private final Set<IShutdownObserver> shutdownObservers = new HashSet<IShutdownObserver>();
115
116
117 private boolean isShutdown = false;
118
119
120 private boolean isConfigured = false;
121
122
123
124
125
126
127
128
129
130 public static synchronized CompositeCacheManager getInstance() throws CacheException
131 {
132 if ( instance == null )
133 {
134 log.debug( "Instance is null, creating with default config" );
135
136 instance = createInstance();
137
138 instance.configure();
139 }
140
141 instance.incrementClients();
142
143 return instance;
144 }
145
146
147
148
149
150
151
152
153 public static synchronized CompositeCacheManager getInstance( String propsFilename ) throws CacheException
154 {
155 if ( instance == null )
156 {
157 if ( log.isInfoEnabled() )
158 {
159 log.info( "Instance is null, creating with default config [" + propsFilename + "]" );
160 }
161
162 instance = createInstance();
163
164 instance.configure( propsFilename );
165 }
166
167 instance.incrementClients();
168
169 return instance;
170 }
171
172
173
174
175
176
177
178 public static synchronized CompositeCacheManager getUnconfiguredInstance()
179 {
180 if ( instance == null )
181 {
182 if ( log.isInfoEnabled() )
183 {
184 log.info( "Instance is null, returning unconfigured instance" );
185 }
186
187 instance = createInstance();
188 }
189
190 instance.incrementClients();
191
192 return instance;
193 }
194
195
196
197
198
199
200
201 protected static CompositeCacheManager createInstance()
202 {
203 return new CompositeCacheManager();
204 }
205
206
207 protected CompositeCacheManager()
208 {
209 ShutdownHook shutdownHook = new ShutdownHook();
210 try
211 {
212 Runtime.getRuntime().addShutdownHook( shutdownHook );
213 }
214 catch ( AccessControlException e )
215 {
216 log.error( "Could not register shutdown hook.", e );
217 }
218 }
219
220
221
222
223
224 public void configure() throws CacheException
225 {
226 configure( CacheConstants.DEFAULT_CONFIG );
227 }
228
229
230
231
232
233
234
235 public void configure( String propFile ) throws CacheException
236 {
237 log.info( "Creating cache manager from config file: " + propFile );
238
239 Properties props = new Properties();
240
241 InputStream is = getClass().getResourceAsStream( propFile );
242
243 if ( is != null )
244 {
245 try
246 {
247 props.load( is );
248
249 if ( log.isDebugEnabled() )
250 {
251 log.debug( "File [" + propFile + "] contained " + props.size() + " properties" );
252 }
253 }
254 catch ( IOException ex )
255 {
256 throw new CacheException("Failed to load properties for name [" + propFile + "]", ex);
257 }
258 finally
259 {
260 try
261 {
262 is.close();
263 }
264 catch ( IOException ignore )
265 {
266
267 }
268 }
269 }
270 else
271 {
272 throw new CacheException( "Failed to read configuration file [" + propFile + "]" );
273 }
274
275 configure( props );
276 }
277
278
279
280
281
282
283
284 public void configure( Properties props )
285 {
286 configure( props, DEFAULT_USE_SYSTEM_PROPERTIES );
287 }
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302 public void configure( Properties props, boolean useSystemProperties )
303 {
304 configure( props, useSystemProperties, DEFAULT_FORCE_RECONFIGURATION );
305 }
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322 public synchronized void configure( Properties props, boolean useSystemProperties, boolean forceReconfiguration )
323 {
324 if ( props == null )
325 {
326 log.error( "No properties found. Please configure the cache correctly." );
327 return;
328 }
329
330 if ( isConfigured )
331 {
332 if ( !forceReconfiguration )
333 {
334 if ( log.isDebugEnabled() )
335 {
336 log.debug( "Configure called after the manager has been configured. "
337 + "Force reconfiguration is false. Doing nothing" );
338 }
339 return;
340 }
341 else
342 {
343 if ( log.isInfoEnabled() )
344 {
345 log.info( "Configure called after the manager has been configured. "
346 + "Force reconfiguration is true. Reconfiguring as best we can." );
347 }
348 }
349 }
350 if ( useSystemProperties )
351 {
352 overrideWithSystemProperties( props );
353 }
354 doConfigure( props );
355 }
356
357
358
359
360
361
362
363
364 private static void overrideWithSystemProperties( Properties props )
365 {
366
367 Properties sysProps = System.getProperties();
368 Set<Object> keys = sysProps.keySet();
369 Iterator<Object> keyIt = keys.iterator();
370 while ( keyIt.hasNext() )
371 {
372 String key = (String) keyIt.next();
373 if ( key.startsWith( SYSTEM_PROPERTY_KEY_PREFIX ) )
374 {
375 if ( log.isInfoEnabled() )
376 {
377 log.info( "Using system property [[" + key + "] [" + sysProps.getProperty( key ) + "]]" );
378 }
379 props.put( key, sysProps.getProperty( key ) );
380 }
381 }
382 }
383
384
385
386
387
388
389 private void doConfigure( Properties props )
390 {
391
392 this.configurationProperties = props;
393
394
395 ThreadPoolManager.setProps( props );
396 ThreadPoolManager poolMgr = ThreadPoolManager.getInstance();
397 if ( log.isDebugEnabled() )
398 {
399 log.debug( "ThreadPoolManager = " + poolMgr );
400 }
401
402
403 CompositeCacheConfigurator configurator = new CompositeCacheConfigurator( this );
404
405 configurator.doConfigure( props );
406
407 isConfigured = true;
408 }
409
410
411
412
413
414
415 public ICompositeCacheAttributes getDefaultCacheAttributes()
416 {
417 return this.defaultCacheAttr.copy();
418 }
419
420
421
422
423
424
425 public void setDefaultCacheAttributes( ICompositeCacheAttributes icca )
426 {
427 this.defaultCacheAttr = icca;
428 }
429
430
431
432
433
434
435 public void setDefaultElementAttributes( IElementAttributes iea )
436 {
437 this.defaultElementAttr = iea;
438 }
439
440
441
442
443
444
445 public IElementAttributes getDefaultElementAttributes()
446 {
447 return this.defaultElementAttr.copy();
448 }
449
450
451
452
453
454
455
456 public CompositeCache getCache( String cacheName )
457 {
458 return getCache( cacheName, this.defaultCacheAttr.copy() );
459 }
460
461
462
463
464
465
466
467
468 public CompositeCache getCache( String cacheName, ICompositeCacheAttributes cattr )
469 {
470 cattr.setCacheName( cacheName );
471 return getCache( cattr, this.defaultElementAttr );
472 }
473
474
475
476
477
478
479
480
481
482 public CompositeCache getCache( String cacheName, ICompositeCacheAttributes cattr, IElementAttributes attr )
483 {
484 cattr.setCacheName( cacheName );
485 return getCache( cattr, attr );
486 }
487
488
489
490
491
492
493
494 public CompositeCache getCache( ICompositeCacheAttributes cattr )
495 {
496 return getCache( cattr, this.defaultElementAttr );
497 }
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512 public CompositeCache getCache( ICompositeCacheAttributes cattr, IElementAttributes attr )
513 {
514 CompositeCache cache;
515
516 if ( log.isDebugEnabled() )
517 {
518 log.debug( "attr = " + attr );
519 }
520
521 synchronized ( caches )
522 {
523 cache = (CompositeCache) caches.get( cattr.getCacheName() );
524 if ( cache == null )
525 {
526 cattr.setCacheName( cattr.getCacheName() );
527
528 CompositeCacheConfigurator configurator = new CompositeCacheConfigurator( this );
529
530 cache = configurator.parseRegion( this.getConfigurationProperties(), cattr.getCacheName(),
531 this.defaultAuxValues, cattr );
532
533 caches.put( cattr.getCacheName(), cache );
534 }
535 }
536
537 return cache;
538 }
539
540
541
542
543 public void freeCache( String name )
544 {
545 freeCache( name, false );
546 }
547
548
549
550
551
552 public void freeCache( String name, boolean fromRemote )
553 {
554 CompositeCache cache = (CompositeCache) caches.remove( name );
555
556 if ( cache != null )
557 {
558 cache.dispose( fromRemote );
559 }
560 }
561
562
563
564
565 public void shutDown()
566 {
567 isShutdown = true;
568
569
570 synchronized ( shutdownObservers )
571 {
572
573
574
575 for (IShutdownObserver observer : shutdownObservers)
576 {
577 observer.shutdown();
578 }
579 }
580
581
582 String[] names = getCacheNames();
583 int len = names.length;
584 for ( int i = 0; i < len; i++ )
585 {
586 String name = names[i];
587 freeCache( name );
588 }
589 }
590
591
592 protected void incrementClients()
593 {
594 clients++;
595 }
596
597
598 public void release()
599 {
600 release( false );
601 }
602
603
604
605
606 private void release( boolean fromRemote )
607 {
608 synchronized ( CompositeCacheManager.class )
609 {
610
611 if ( --clients > 0 )
612 {
613 if ( log.isDebugEnabled() )
614 {
615 log.debug( "Release called, but " + clients + " remain" );
616 return;
617 }
618 }
619
620 if ( log.isDebugEnabled() )
621 {
622 log.debug( "Last client called release. There are " + caches.size() + " caches which will be disposed" );
623 }
624
625 for (ICache c : caches.values() )
626 {
627 CompositeCache cache = (CompositeCache) c;
628
629 if ( cache != null )
630 {
631 cache.dispose( fromRemote );
632 }
633 }
634 }
635 }
636
637
638
639
640
641 public String[] getCacheNames()
642 {
643 String[] list = new String[caches.size()];
644 int i = 0;
645 for (String key : caches.keySet())
646 {
647 list[i++] = key;
648 }
649 return list;
650 }
651
652
653
654
655 public int getCacheType()
656 {
657 return ICacheType.CACHE_HUB;
658 }
659
660
661
662
663 public ICompositeCacheAttributes getDefaultCattr()
664 {
665 return this.defaultCacheAttr;
666 }
667
668
669
670
671 void registryFacPut( AuxiliaryCacheFactory auxFac )
672 {
673 auxiliaryFactoryRegistry.put( auxFac.getName(), auxFac );
674 }
675
676
677
678
679
680 AuxiliaryCacheFactory registryFacGet( String name )
681 {
682 return auxiliaryFactoryRegistry.get( name );
683 }
684
685
686
687
688 void registryAttrPut( AuxiliaryCacheAttributes auxAttr )
689 {
690 auxiliaryAttributeRegistry.put( auxAttr.getName(), auxAttr );
691 }
692
693
694
695
696
697 AuxiliaryCacheAttributes registryAttrGet( String name )
698 {
699 return auxiliaryAttributeRegistry.get( name );
700 }
701
702
703
704
705
706
707
708 public String getStats()
709 {
710 ICacheStats[] stats = getStatistics();
711 if ( stats == null )
712 {
713 return "NONE";
714 }
715
716
717 StringBuffer buf = new StringBuffer();
718 int statsLen = stats.length;
719 for ( int i = 0; i < statsLen; i++ )
720 {
721 buf.append( "\n---------------------------\n" );
722 buf.append( stats[i] );
723 }
724 return buf.toString();
725 }
726
727
728
729
730
731
732 public ICacheStats[] getStatistics()
733 {
734 ArrayList<ICacheStats> cacheStats = new ArrayList<ICacheStats>();
735 for (ICache c : caches.values())
736 {
737 CompositeCache cache = (CompositeCache) c;
738 if ( cache != null )
739 {
740 cacheStats.add( cache.getStatistics() );
741 }
742 }
743 ICacheStats[] stats = cacheStats.toArray( new CacheStats[0] );
744 return stats;
745 }
746
747
748
749
750
751
752
753
754
755 public void registerShutdownObserver( IShutdownObserver observer )
756 {
757
758
759 synchronized ( shutdownObservers )
760 {
761
762 shutdownObservers.add( observer );
763 }
764 }
765
766
767
768
769 public void deregisterShutdownObserver( IShutdownObserver observer )
770 {
771 synchronized ( shutdownObservers )
772 {
773 shutdownObservers.remove( observer );
774 }
775 }
776
777
778
779
780
781
782 public void setConfigurationProperties( Properties props )
783 {
784 this.configurationProperties = props;
785 }
786
787
788
789
790
791
792 public Properties getConfigurationProperties()
793 {
794 return configurationProperties;
795 }
796
797
798
799
800 public boolean isShutdown()
801 {
802 return isShutdown;
803 }
804
805
806
807
808 public boolean isConfigured()
809 {
810 return isConfigured;
811 }
812
813
814
815
816
817 class ShutdownHook
818 extends Thread
819 {
820
821
822
823
824
825 @Override
826 public void run()
827 {
828 if ( !isShutdown() )
829 {
830 log.info( "Shutdown hook activated. Shutdown was not called. Shutting down JCS." );
831 shutDown();
832 }
833 }
834 }
835 }