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