1
16
17 package net.sf.ehcache.config;
18
19 import net.sf.ehcache.Cache;
20 import net.sf.ehcache.CacheException;
21 import net.sf.ehcache.CacheManager;
22 import net.sf.ehcache.FeaturesManager;
23 import net.sf.ehcache.ObjectExistsException;
24 import net.sf.ehcache.config.generator.ConfigurationSource;
25 import net.sf.ehcache.store.Store;
26 import net.sf.ehcache.transaction.manager.DefaultTransactionManagerLookup;
27 import net.sf.ehcache.transaction.manager.TransactionManagerLookup;
28 import net.sf.ehcache.util.ClassLoaderUtil;
29 import net.sf.ehcache.util.PropertyUtil;
30
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 import java.beans.PropertyChangeEvent;
35 import java.beans.PropertyChangeListener;
36 import java.lang.reflect.InvocationTargetException;
37 import java.util.ArrayList;
38 import java.util.Collection;
39 import java.util.HashMap;
40 import java.util.HashSet;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.Properties;
44 import java.util.Set;
45 import java.util.concurrent.ConcurrentHashMap;
46 import java.util.concurrent.CopyOnWriteArrayList;
47
48
54 public final class Configuration {
55
56
59 public static final boolean DEFAULT_DYNAMIC_CONFIG = true;
60
63 public static final boolean DEFAULT_UPDATE_CHECK = true;
64
67 public static final int DEFAULT_TRANSACTION_TIMEOUT = 15;
68
71 public static final long DEFAULT_MAX_BYTES_ON_HEAP = 0;
72
75 public static final long DEFAULT_MAX_BYTES_OFF_HEAP = 0;
76
79 public static final long DEFAULT_MAX_BYTES_ON_DISK = 0;
80
83 public static final Monitoring DEFAULT_MONITORING = Monitoring.AUTODETECT;
84
87 public static final SizeOfPolicyConfiguration DEFAULT_SIZEOF_POLICY_CONFIGURATION = new SizeOfPolicyConfiguration();
88
89
92 public static final FactoryConfiguration DEFAULT_TRANSACTION_MANAGER_LOOKUP_CONFIG = getDefaultTransactionManagerLookupConfiguration();
93 private static final int HUNDRED = 100;
94 private static final Logger LOG = LoggerFactory.getLogger(Configuration.class);
95
96 private volatile RuntimeCfg cfg;
97 private final List<PropertyChangeListener> propertyChangeListeners = new CopyOnWriteArrayList<PropertyChangeListener>();
98
99
104 public enum Monitoring {
105
106 AUTODETECT,
107
108
109 ON,
110
111
112 OFF;
113 }
114
115
118 private static enum DynamicProperty {
119
120 cacheManagerName {
121 @Override
122 void applyChange(final PropertyChangeEvent evt, final RuntimeCfg config) {
123 config.cacheManagerName = (String) evt.getNewValue();
124 }
125 },
126 defaultCacheConfiguration {
127 @Override
128 void applyChange(final PropertyChangeEvent evt, final RuntimeCfg config) {
129 LOG.debug("Default Cache Configuration has changed, previously created caches remain untouched");
130 }
131 },
132 maxBytesLocalHeap {
133 @Override
134 void applyChange(final PropertyChangeEvent evt, final RuntimeCfg config) {
135
136 ArrayList<ConfigError> errors = new ArrayList<ConfigError>();
137 Long newValue = (Long)evt.getNewValue();
138 if ((Long) evt.getOldValue() > (Long) evt.getNewValue()) {
139
140 for (Cache cache : getAllActiveCaches(config.cacheManager)) {
141 CacheConfiguration cacheConfiguration = cache.getCacheConfiguration();
142 errors.addAll(cacheConfiguration.validateCachePools(config.getConfiguration()));
143 errors.addAll(cacheConfiguration.verifyPoolAllocationsBeforeAddingTo(config.cacheManager,
144 newValue, config.getConfiguration().getMaxBytesLocalOffHeap(), config.getConfiguration().getMaxBytesLocalDisk()));
145 }
146 }
147 if (!errors.isEmpty()) {
148 throw new InvalidConfigurationException("Can't reduce CacheManager byte tuning by so much", errors);
149 }
150
151 long cacheAllocated = 0;
152 for (Cache cache : getAllActiveCaches(config.cacheManager)) {
153 cache.getCacheConfiguration().configCachePools(config.getConfiguration());
154 long bytesLocalHeap = cache.getCacheConfiguration().getMaxBytesLocalHeap();
155 cacheAllocated += bytesLocalHeap;
156 }
157 config.cacheManager.getOnHeapPool().setMaxSize(newValue - cacheAllocated);
158 }
159 },
160 maxBytesLocalDisk {
161 @Override
162 void applyChange(final PropertyChangeEvent evt, final RuntimeCfg config) {
163 if ((Long)evt.getOldValue() > (Long)evt.getNewValue()) {
164
165 for (CacheConfiguration cacheConfiguration : config.getConfiguration().getCacheConfigurations().values()) {
166 cacheConfiguration.isMaxBytesLocalDiskPercentageSet();
167 }
168 }
169 config.cacheManager.getOnDiskPool().setMaxSize((Long) evt.getNewValue());
170
171 }
172 };
173
174 abstract void applyChange(PropertyChangeEvent evt, RuntimeCfg config);
175 }
176
177 private String cacheManagerName;
178 private boolean updateCheck = DEFAULT_UPDATE_CHECK;
179 private int defaultTransactionTimeoutInSeconds = DEFAULT_TRANSACTION_TIMEOUT;
180 private Monitoring monitoring = DEFAULT_MONITORING;
181 private DiskStoreConfiguration diskStoreConfiguration;
182 private CacheConfiguration defaultCacheConfiguration;
183 private final List<FactoryConfiguration> cacheManagerPeerProviderFactoryConfiguration = new ArrayList<FactoryConfiguration>();
184 private final List<FactoryConfiguration> cacheManagerPeerListenerFactoryConfiguration = new ArrayList<FactoryConfiguration>();
185 private SizeOfPolicyConfiguration sizeOfPolicyConfiguration;
186 private FactoryConfiguration transactionManagerLookupConfiguration;
187 private FactoryConfiguration cacheManagerEventListenerFactoryConfiguration;
188 private TerracottaClientConfiguration terracottaConfigConfiguration;
189 private ManagementRESTServiceConfiguration managementRESTService;
190 private final Map<String, CacheConfiguration> cacheConfigurations = new ConcurrentHashMap<String, CacheConfiguration>();
191 private ConfigurationSource configurationSource;
192 private boolean dynamicConfig = DEFAULT_DYNAMIC_CONFIG;
193 private Long maxBytesLocalHeap;
194 private String maxBytesLocalHeapInput;
195 private Long maxBytesLocalOffHeap;
196 private String maxBytesLocalOffHeapInput;
197 private Long maxBytesLocalDisk;
198 private String maxBytesLocalDiskInput;
199
200
205 public Configuration() {
206 }
207
208
213 static Set<Cache> getAllActiveCaches(CacheManager cacheManager) {
214 final Set<Cache> caches = new HashSet<Cache>();
215 for (String cacheName : cacheManager.getCacheNames()) {
216 final Cache cache = cacheManager.getCache(cacheName);
217 if (cache != null) {
218 caches.add(cache);
219 }
220 }
221 return caches;
222 }
223
224
230 public RuntimeCfg setupFor(final CacheManager cacheManager, final String fallbackName) throws InvalidConfigurationException {
231 if (cfg != null) {
232 return cfg;
233 }
234 final Collection<ConfigError> errors = validate();
235 if (!errors.isEmpty()) {
236 throw new InvalidConfigurationException(errors);
237 }
238 cfg = new Configuration.RuntimeCfg(cacheManager, fallbackName);
239 return cfg;
240 }
241
242
246 public Collection<ConfigError> validate() {
247 final Collection<ConfigError> errors = new ArrayList<ConfigError>();
248
249 for (CacheConfiguration cacheConfiguration : cacheConfigurations.values()) {
250 errors.addAll(cacheConfiguration.validate(this));
251 }
252 return errors;
253 }
254
255
260 public boolean isMaxBytesLocalDiskSet() {
261 return maxBytesLocalDisk != null;
262 }
263
264
269 public boolean isMaxBytesLocalOffHeapSet() {
270 return maxBytesLocalOffHeap != null;
271 }
272
273
278 public boolean isMaxBytesLocalHeapSet() {
279 return maxBytesLocalHeap != null;
280 }
281
282
283 private static FactoryConfiguration getDefaultTransactionManagerLookupConfiguration() {
284 FactoryConfiguration configuration = new FactoryConfiguration();
285 configuration.setClass(DefaultTransactionManagerLookup.class.getName());
286 return configuration;
287 }
288
289
297 public final Configuration name(String name) {
298 setName(name);
299 return this;
300 }
301
302
305 public final void setName(String name) {
306 assertArgumentNotNull("name", name);
307 final String prop = "cacheManagerName";
308 final boolean publishChange = checkDynChange(prop);
309 String oldValue = this.cacheManagerName;
310 this.cacheManagerName = name;
311 if (publishChange) {
312 firePropertyChange(prop, oldValue, name);
313 }
314 }
315
316 private void assertArgumentNotNull(String name, Object object) {
317 if (object == null) {
318 throw new IllegalArgumentException(name + " cannot be null");
319 }
320 }
321
322
325 public final String getName() {
326 return this.cacheManagerName;
327 }
328
329
336 public final Configuration updateCheck(boolean updateCheck) {
337 setUpdateCheck(updateCheck);
338 return this;
339 }
340
341
344 public final void setUpdateCheck(boolean updateCheck) {
345 String prop = "updateCheck";
346 final boolean publish = checkDynChange(prop);
347 final boolean oldValue = this.updateCheck;
348 this.updateCheck = updateCheck;
349 if (publish) {
350 firePropertyChange(prop, oldValue, updateCheck);
351 }
352 }
353
354
357 public final boolean getUpdateCheck() {
358 return this.updateCheck;
359 }
360
361
367 public final Configuration defaultTransactionTimeoutInSeconds(int defaultTransactionTimeoutInSeconds) {
368 setDefaultTransactionTimeoutInSeconds(defaultTransactionTimeoutInSeconds);
369 return this;
370 }
371
372
375 public final void setDefaultTransactionTimeoutInSeconds(int defaultTransactionTimeoutInSeconds) {
376 final String prop = "defaultTransactionTimeoutInSeconds";
377 final boolean publish = checkDynChange(prop);
378 final int oldValue = this.defaultTransactionTimeoutInSeconds;
379 this.defaultTransactionTimeoutInSeconds = defaultTransactionTimeoutInSeconds;
380 if (publish) {
381 firePropertyChange(prop, oldValue, defaultTransactionTimeoutInSeconds);
382 }
383 }
384
385
389 public final int getDefaultTransactionTimeoutInSeconds() {
390 return defaultTransactionTimeoutInSeconds;
391 }
392
393
400 public final Configuration monitoring(Monitoring monitoring) {
401 if (null == monitoring) {
402 throw new IllegalArgumentException("Monitoring value must be non-null");
403 }
404 final String prop = "monitoring";
405 final boolean publish = checkDynChange(prop);
406 final Monitoring oldValue = this.monitoring;
407 this.monitoring = monitoring;
408 if (publish) {
409 firePropertyChange(prop, oldValue, monitoring);
410 }
411 return this;
412 }
413
414
417 public final void setMonitoring(String monitoring) {
418 assertArgumentNotNull("Monitoring", monitoring);
419 monitoring(Monitoring.valueOf(Monitoring.class, monitoring.toUpperCase()));
420 }
421
422
425 public final Monitoring getMonitoring() {
426 return this.monitoring;
427 }
428
429
436 public final Configuration dynamicConfig(boolean dynamicConfig) {
437 setDynamicConfig(dynamicConfig);
438 return this;
439 }
440
441
444 public final void setDynamicConfig(boolean dynamicConfig) {
445 final String prop = "dynamicConfig";
446 final boolean publish = checkDynChange(prop);
447 final boolean oldValue = this.dynamicConfig;
448 this.dynamicConfig = dynamicConfig;
449 if (publish) {
450 firePropertyChange(prop, oldValue, dynamicConfig);
451 }
452 }
453
454
457 public final boolean getDynamicConfig() {
458 return this.dynamicConfig;
459 }
460
461
465 public long getMaxBytesLocalHeap() {
466 return maxBytesLocalHeap == null ? DEFAULT_MAX_BYTES_ON_HEAP : maxBytesLocalHeap;
467 }
468
469
474 public void setMaxBytesLocalHeap(final String maxBytesOnHeap) {
475 assertArgumentNotNull("MaxBytesLocalHeap", maxBytesOnHeap);
476 if (isPercentage(maxBytesOnHeap)) {
477 long maxMemory = Runtime.getRuntime().maxMemory();
478 long mem = maxMemory / HUNDRED * parsePercentage(maxBytesOnHeap);
479 setMaxBytesLocalHeap(mem);
480 } else {
481 setMaxBytesLocalHeap(MemoryUnit.parseSizeInBytes(maxBytesOnHeap));
482 }
483 maxBytesLocalHeapInput = maxBytesOnHeap;
484 }
485
486
489 public String getMaxBytesLocalHeapAsString() {
490 return maxBytesLocalHeapInput != null ? maxBytesLocalHeapInput : Long.toString(getMaxBytesLocalHeap());
491 }
492
493 private int parsePercentage(final String stringValue) {
494 String trimmed = stringValue.trim();
495 int percentage = Integer.parseInt(trimmed.substring(0, trimmed.length() - 1));
496 if (percentage > HUNDRED || percentage < 0) {
497 throw new IllegalArgumentException("Percentage need values need to be between 0 and 100 inclusive, but got : " + percentage);
498 }
499 return percentage;
500 }
501
502 private boolean isPercentage(final String stringValue) {
503 String trimmed = stringValue.trim();
504 return trimmed.charAt(trimmed.length() - 1) == '%';
505 }
506
507
511 public void setMaxBytesLocalHeap(final Long maxBytesOnHeap) {
512 final String prop = "maxBytesLocalHeap";
513 verifyGreaterThanZero(maxBytesOnHeap, prop);
514 final boolean publish = checkDynChange(prop);
515 Long oldValue = this.maxBytesLocalHeap;
516 this.maxBytesLocalHeap = maxBytesOnHeap;
517 if (publish) {
518 firePropertyChange(prop, oldValue, maxBytesOnHeap);
519 }
520 }
521
522
529 public Configuration maxBytesLocalHeap(final long amount, final MemoryUnit memoryUnit) {
530 setMaxBytesLocalHeap(memoryUnit.toBytes(amount));
531 return this;
532 }
533
534
538 public long getMaxBytesLocalOffHeap() {
539 return maxBytesLocalOffHeap == null ? DEFAULT_MAX_BYTES_OFF_HEAP : maxBytesLocalOffHeap;
540 }
541
542
547 public void setMaxBytesLocalOffHeap(final String maxBytesOffHeap) {
548 assertArgumentNotNull("MaxBytesLocalOffHeap", maxBytesOffHeap);
549 if (isPercentage(maxBytesOffHeap)) {
550 long maxMemory = getOffHeapLimit();
551 long mem = maxMemory / HUNDRED * parsePercentage(maxBytesOffHeap);
552 setMaxBytesLocalOffHeap(mem);
553 } else {
554 setMaxBytesLocalOffHeap(MemoryUnit.parseSizeInBytes(maxBytesOffHeap));
555 }
556 maxBytesLocalOffHeapInput = maxBytesOffHeap;
557 }
558
559
562 public String getMaxBytesLocalOffHeapAsString() {
563 return maxBytesLocalOffHeapInput != null ? maxBytesLocalOffHeapInput : Long.toString(getMaxBytesLocalOffHeap());
564 }
565
566
569 public long getTotalConfiguredOffheap() {
570 long total = getMaxBytesLocalOffHeap();
571 for (String cacheName : getCacheConfigurationsKeySet()) {
572 CacheConfiguration config = getCacheConfigurations().get(cacheName);
573 total += config.getMaxBytesLocalOffHeap();
574 }
575 return total;
576 }
577
578 private long getOffHeapLimit() {
579 try {
580 Class<Store> enterpriseFmClass = ClassLoaderUtil.loadClass(FeaturesManager.ENTERPRISE_FM_CLASSNAME);
581
582 try {
583 return (Long)enterpriseFmClass.getMethod("getMaxBytesAllocatable").invoke(null);
584 } catch (NoSuchMethodException e) {
585 throw new CacheException("Cache: " + getName() + " cannot find static factory"
586 + " method create(Ehcache, String)" + " in store class " + FeaturesManager.ENTERPRISE_FM_CLASSNAME, e);
587 } catch (InvocationTargetException e) {
588 Throwable cause = e.getCause();
589 throw new CacheException("Cache: " + getName() + " cannot instantiate store "
590 + FeaturesManager.ENTERPRISE_FM_CLASSNAME, cause);
591 } catch (IllegalAccessException e) {
592 throw new CacheException("Cache: " + getName() + " cannot instantiate store "
593 + FeaturesManager.ENTERPRISE_FM_CLASSNAME, e);
594 }
595 } catch (ClassNotFoundException e) {
596 throw new CacheException("Cache " + getName()
597 + " cannot be configured because the off-heap store class could not be found. "
598 + "You must use an enterprise version of Ehcache to successfully enable overflowToOffHeap.");
599 }
600 }
601
602
606 public void setMaxBytesLocalOffHeap(final Long maxBytesOffHeap) {
607 String prop = "maxBytesLocalOffHeap";
608 verifyGreaterThanZero(maxBytesOffHeap, prop);
609 boolean publish = checkDynChange(prop);
610 Long oldValue = this.maxBytesLocalOffHeap;
611 this.maxBytesLocalOffHeap = maxBytesOffHeap;
612 if (publish) {
613 firePropertyChange(prop, oldValue, maxBytesOffHeap);
614 }
615 }
616
617
623 public Configuration maxBytesLocalOffHeap(final long amount, final MemoryUnit memoryUnit) {
624 setMaxBytesLocalOffHeap(memoryUnit.toBytes(amount));
625 return this;
626 }
627
628
632 public long getMaxBytesLocalDisk() {
633 return maxBytesLocalDisk == null ? DEFAULT_MAX_BYTES_ON_DISK : maxBytesLocalDisk;
634 }
635
636
641 public void setMaxBytesLocalDisk(final String maxBytesOnDisk) {
642 assertArgumentNotNull("MaxBytesLocalDisk", maxBytesOnDisk);
643 setMaxBytesLocalDisk(MemoryUnit.parseSizeInBytes(maxBytesOnDisk));
644 maxBytesLocalDiskInput = maxBytesOnDisk;
645 }
646
647
650 public String getMaxBytesLocalDiskAsString() {
651 return maxBytesLocalDiskInput != null ? maxBytesLocalDiskInput : Long.toString(getMaxBytesLocalDisk());
652 }
653
654
658 public void setMaxBytesLocalDisk(final Long maxBytesOnDisk) {
659 String prop = "maxBytesLocalDisk";
660 verifyGreaterThanZero(maxBytesOnDisk, prop);
661 boolean publish = checkDynChange(prop);
662 Long oldValue = this.maxBytesLocalDisk;
663 this.maxBytesLocalDisk = maxBytesOnDisk;
664 if (publish) {
665 firePropertyChange(prop, oldValue, maxBytesOnDisk);
666 }
667 }
668
669
676 public Configuration maxBytesLocalDisk(final long amount, final MemoryUnit memoryUnit) {
677 setMaxBytesLocalDisk(memoryUnit.toBytes(amount));
678 return this;
679 }
680
681 private void verifyGreaterThanZero(final Long maxBytesOnHeap, final String field) {
682 if (maxBytesOnHeap != null && maxBytesOnHeap < 1) {
683 throw new IllegalArgumentException(field + " has to be larger than 0");
684 }
685 }
686
687
696 public final Configuration diskStore(DiskStoreConfiguration diskStoreConfigurationParameter) throws ObjectExistsException {
697 addDiskStore(diskStoreConfigurationParameter);
698 return this;
699 }
700
701
704 public final void addDiskStore(DiskStoreConfiguration diskStoreConfigurationParameter) throws ObjectExistsException {
705 if (diskStoreConfiguration != null) {
706 throw new ObjectExistsException("The Disk Store has already been configured");
707 }
708 final String prop = "diskStoreConfiguration";
709 boolean publish = checkDynChange(prop);
710 DiskStoreConfiguration oldValue = diskStoreConfiguration;
711 diskStoreConfiguration = diskStoreConfigurationParameter;
712 if (publish) {
713 firePropertyChange(prop, oldValue, diskStoreConfiguration);
714 }
715 }
716
717
723 public final Configuration sizeOfPolicy(SizeOfPolicyConfiguration sizeOfPolicyConfiguration) {
724 addSizeOfPolicy(sizeOfPolicyConfiguration);
725 return this;
726 }
727
728
733 public final void addSizeOfPolicy(SizeOfPolicyConfiguration sizeOfPolicy) {
734 if (sizeOfPolicyConfiguration != null) {
735 throw new ObjectExistsException("The SizeOfPolicy class has already been configured");
736 }
737 sizeOfPolicyConfiguration = sizeOfPolicy;
738 }
739
740
749 public final Configuration transactionManagerLookup(FactoryConfiguration transactionManagerLookupParameter)
750 throws ObjectExistsException {
751 addTransactionManagerLookup(transactionManagerLookupParameter);
752 return this;
753 }
754
755
758 public final void addTransactionManagerLookup(FactoryConfiguration transactionManagerLookupParameter) throws ObjectExistsException {
759 if (transactionManagerLookupConfiguration != null) {
760 throw new ObjectExistsException("The TransactionManagerLookup class has already been configured");
761 }
762 final String prop = "transactionManagerLookupConfiguration";
763 boolean publish = checkDynChange(prop);
764 FactoryConfiguration oldValue = this.transactionManagerLookupConfiguration;
765 transactionManagerLookupConfiguration = transactionManagerLookupParameter;
766 if (publish) {
767 firePropertyChange(prop, oldValue, transactionManagerLookupParameter);
768 }
769 }
770
771
776 public final Configuration cacheManagerEventListenerFactory(FactoryConfiguration cacheManagerEventListenerFactoryConfiguration) {
777 addCacheManagerEventListenerFactory(cacheManagerEventListenerFactoryConfiguration);
778 return this;
779 }
780
781
784 public final void addCacheManagerEventListenerFactory(FactoryConfiguration cacheManagerEventListenerFactoryConfiguration) {
785 final String prop = "cacheManagerEventListenerFactoryConfiguration";
786 boolean publish = checkDynChange(prop);
787 if (this.cacheManagerEventListenerFactoryConfiguration == null) {
788 this.cacheManagerEventListenerFactoryConfiguration = cacheManagerEventListenerFactoryConfiguration;
789 if (publish) {
790 firePropertyChange(prop, null, cacheManagerEventListenerFactoryConfiguration);
791 }
792 }
793 }
794
795
800 public final Configuration cacheManagerPeerProviderFactory(FactoryConfiguration factory) {
801 addCacheManagerPeerProviderFactory(factory);
802 return this;
803 }
804
805
808 public final void addCacheManagerPeerProviderFactory(FactoryConfiguration factory) {
809 final String prop = "cacheManagerPeerProviderFactoryConfiguration";
810 boolean publish = checkDynChange(prop);
811 List<FactoryConfiguration> oldValue = null;
812 if (publish) {
813 oldValue = new ArrayList<FactoryConfiguration>(cacheManagerPeerProviderFactoryConfiguration);
814 }
815 cacheManagerPeerProviderFactoryConfiguration.add(factory);
816 if (publish) {
817 firePropertyChange(prop, oldValue, cacheManagerPeerProviderFactoryConfiguration);
818 }
819 }
820
821
826 public final Configuration cacheManagerPeerListenerFactory(FactoryConfiguration factory) {
827 addCacheManagerPeerListenerFactory(factory);
828 return this;
829 }
830
831
834 public final void addCacheManagerPeerListenerFactory(FactoryConfiguration factory) {
835 final String prop = "cacheManagerPeerListenerFactoryConfiguration";
836 boolean publish = checkDynChange(prop);
837 List<FactoryConfiguration> oldValue = null;
838 if (publish) {
839 oldValue = new ArrayList<FactoryConfiguration>(cacheManagerPeerListenerFactoryConfiguration);
840 }
841 cacheManagerPeerListenerFactoryConfiguration.add(factory);
842 if (publish) {
843 firePropertyChange(prop, oldValue, cacheManagerPeerListenerFactoryConfiguration);
844 }
845 }
846
847
854 public final Configuration terracotta(TerracottaClientConfiguration terracottaConfiguration) throws ObjectExistsException {
855 addTerracottaConfig(terracottaConfiguration);
856 return this;
857 }
858
859
862 public final void addTerracottaConfig(TerracottaClientConfiguration terracottaConfiguration) throws ObjectExistsException {
863 if (this.terracottaConfigConfiguration != null) {
864 throw new ObjectExistsException("The TerracottaConfig has already been configured");
865 }
866 final String prop = "terracottaConfigConfiguration";
867 final boolean publish = checkDynChange(prop);
868 final TerracottaClientConfiguration oldValue = this.terracottaConfigConfiguration;
869 this.terracottaConfigConfiguration = terracottaConfiguration;
870 if (publish) {
871 firePropertyChange(prop, oldValue, terracottaConfiguration);
872 }
873 }
874
875
882 public final Configuration managementRESTService(ManagementRESTServiceConfiguration cfg) throws ObjectExistsException {
883 addManagementRESTService(cfg);
884 return this;
885 }
886
887
890 public final void addManagementRESTService(ManagementRESTServiceConfiguration managementRESTServiceConfiguration) throws ObjectExistsException {
891 if (this.managementRESTService != null) {
892 throw new ObjectExistsException("The ManagementRESTService has already been configured");
893 }
894
895 final String prop = "managementRESTService";
896 final boolean publish = checkDynChange(prop);
897 final ManagementRESTServiceConfiguration oldValue = this.managementRESTService;
898 this.managementRESTService = managementRESTServiceConfiguration;
899 if (publish) {
900 firePropertyChange(prop, oldValue, managementRESTServiceConfiguration);
901 }
902 }
903
904
911 public final Configuration defaultCache(CacheConfiguration defaultCacheConfiguration) throws ObjectExistsException {
912 setDefaultCacheConfiguration(defaultCacheConfiguration);
913 return this;
914 }
915
916
919 public final void addDefaultCache(CacheConfiguration defaultCacheConfiguration) throws ObjectExistsException {
920 if (this.defaultCacheConfiguration != null) {
921 throw new ObjectExistsException("The Default Cache has already been configured");
922 }
923 setDefaultCacheConfiguration(defaultCacheConfiguration);
924 }
925
926
933 public final Configuration cache(CacheConfiguration cacheConfiguration) throws ObjectExistsException {
934 addCache(cacheConfiguration);
935 return this;
936 }
937
938
941 public final void addCache(CacheConfiguration cacheConfiguration) throws ObjectExistsException {
942 addCache(cacheConfiguration, true);
943 }
944
945
950 void addCache(CacheConfiguration cacheConfiguration, final boolean strict) throws ObjectExistsException {
951 final String prop = "cacheConfigurations";
952 Object oldValue = null;
953 boolean publishChange = strict && checkDynChange(prop);
954 if (publishChange) {
955 oldValue = new HashMap<String, CacheConfiguration>(cacheConfigurations);
956 }
957 if (cacheConfigurations.get(cacheConfiguration.name) != null) {
958 throw new ObjectExistsException("Cannot create cache: " + cacheConfiguration.name + " with the same name as an existing one.");
959 }
960 if (cacheConfiguration.name.equalsIgnoreCase(net.sf.ehcache.Cache.DEFAULT_CACHE_NAME)) {
961 throw new ObjectExistsException("The Default Cache has already been configured");
962 }
963
964 cacheConfigurations.put(cacheConfiguration.name, cacheConfiguration);
965 if (publishChange) {
966 firePropertyChange(prop, oldValue, cacheConfigurations);
967 }
968 }
969
970 private boolean checkDynChange(final String prop) {
971 if (!propertyChangeListeners.isEmpty()) {
972 try {
973 if (cfg != null) {
974 DynamicProperty.valueOf(prop);
975 }
976 } catch (IllegalArgumentException e) {
977 throw new IllegalStateException(this.getClass().getName() + "." + prop + " can't be changed dynamically");
978 }
979 return true;
980 } else {
981 return false;
982 }
983 }
984
985
988 public final Set<String> getCacheConfigurationsKeySet() {
989 return cacheConfigurations.keySet();
990 }
991
992
995 public final CacheConfiguration getDefaultCacheConfiguration() {
996 return defaultCacheConfiguration;
997 }
998
999
1002 public final void setDefaultCacheConfiguration(CacheConfiguration defaultCacheConfiguration) {
1003 final String prop = "defaultCacheConfiguration";
1004 final boolean publish = checkDynChange(prop);
1005 final CacheConfiguration oldValue = this.defaultCacheConfiguration;
1006 this.defaultCacheConfiguration = defaultCacheConfiguration;
1007 if (publish) {
1008 firePropertyChange(prop, oldValue, defaultCacheConfiguration);
1009 }
1010 }
1011
1012
1015 public final DiskStoreConfiguration getDiskStoreConfiguration() {
1016 return diskStoreConfiguration;
1017 }
1018
1019
1022 public final SizeOfPolicyConfiguration getSizeOfPolicyConfiguration() {
1023 if (sizeOfPolicyConfiguration == null) {
1024 return DEFAULT_SIZEOF_POLICY_CONFIGURATION;
1025 }
1026 return sizeOfPolicyConfiguration;
1027 }
1028
1029
1032 public final FactoryConfiguration getTransactionManagerLookupConfiguration() {
1033 if (transactionManagerLookupConfiguration == null) {
1034 return getDefaultTransactionManagerLookupConfiguration();
1035 }
1036 return transactionManagerLookupConfiguration;
1037 }
1038
1039
1042 public final List<FactoryConfiguration> getCacheManagerPeerProviderFactoryConfiguration() {
1043 return cacheManagerPeerProviderFactoryConfiguration;
1044 }
1045
1046
1049 public final List<FactoryConfiguration> getCacheManagerPeerListenerFactoryConfigurations() {
1050 return cacheManagerPeerListenerFactoryConfiguration;
1051 }
1052
1053
1056 public final ManagementRESTServiceConfiguration getManagementRESTService() {
1057 return managementRESTService;
1058 }
1059
1060
1063 public final FactoryConfiguration getCacheManagerEventListenerFactoryConfiguration() {
1064 return cacheManagerEventListenerFactoryConfiguration;
1065 }
1066
1067
1070 public final TerracottaClientConfiguration getTerracottaConfiguration() {
1071 return this.terracottaConfigConfiguration;
1072 }
1073
1074
1077 public final Map<String, CacheConfiguration> getCacheConfigurations() {
1078 return cacheConfigurations;
1079 }
1080
1081
1086 public final Configuration source(ConfigurationSource configurationSource) {
1087 setSource(configurationSource);
1088 return this;
1089 }
1090
1091
1098 public final void setSource(ConfigurationSource configurationSource) {
1099 final String prop = "configurationSource";
1100 final boolean publish = checkDynChange(prop);
1101 final ConfigurationSource oldValue = this.configurationSource;
1102 this.configurationSource = configurationSource;
1103 if (publish) {
1104 firePropertyChange(prop, oldValue, configurationSource);
1105 }
1106 }
1107
1108
1111 public final ConfigurationSource getConfigurationSource() {
1112 return configurationSource;
1113 }
1114
1115
1120 public boolean addPropertyChangeListener(final PropertyChangeListener listener) {
1121 return this.propertyChangeListeners.add(listener);
1122 }
1123
1124
1129 public boolean removePropertyChangeListener(final PropertyChangeListener listener) {
1130 return this.propertyChangeListeners.remove(listener);
1131 }
1132
1133 private <T> void firePropertyChange(final String prop, final T oldValue, final T newValue) {
1134 if ((oldValue != null && !oldValue.equals(newValue)) || newValue != null) {
1135 for (PropertyChangeListener propertyChangeListener : propertyChangeListeners) {
1136 propertyChangeListener.propertyChange(new PropertyChangeEvent(Configuration.this, prop, oldValue, newValue));
1137 }
1138 }
1139 }
1140
1141
1144 public class RuntimeCfg implements PropertyChangeListener {
1145
1146 private final CacheManager cacheManager;
1147 private volatile String cacheManagerName;
1148 private final boolean named;
1149 private TransactionManagerLookup transactionManagerLookup;
1150 private boolean allowsSizeBasedTunings;
1151
1152
1157 public RuntimeCfg(final CacheManager cacheManager, final String fallbackName) {
1158 if (Configuration.this.cacheManagerName != null) {
1159 this.cacheManagerName = Configuration.this.cacheManagerName;
1160 named = true;
1161 } else if (hasTerracottaClusteredCaches()) {
1162 this.cacheManagerName = CacheManager.DEFAULT_NAME;
1163 named = false;
1164 } else {
1165 this.cacheManagerName = fallbackName;
1166 named = false;
1167 }
1168 FactoryConfiguration lookupConfiguration = getTransactionManagerLookupConfiguration();
1169 try {
1170 Properties properties = PropertyUtil.parseProperties(lookupConfiguration.getProperties(), lookupConfiguration
1171 .getPropertySeparator());
1172 Class<TransactionManagerLookup> transactionManagerLookupClass = (Class<TransactionManagerLookup>) Class
1173 .forName(lookupConfiguration.getFullyQualifiedClassPath());
1174 this.transactionManagerLookup = transactionManagerLookupClass.newInstance();
1175 this.transactionManagerLookup.setProperties(properties);
1176 } catch (Exception e) {
1177 LOG.error("could not instantiate transaction manager lookup class: {}", lookupConfiguration.getFullyQualifiedClassPath(), e);
1178 }
1179 this.cacheManager = cacheManager;
1180 propertyChangeListeners.add(this);
1181 allowsSizeBasedTunings = defaultCacheConfiguration == null || !defaultCacheConfiguration.isCountBasedTuned();
1182 for (CacheConfiguration cacheConfiguration : cacheConfigurations.values()) {
1183 if (cacheConfiguration.isCountBasedTuned()) {
1184 allowsSizeBasedTunings = false;
1185 break;
1186 }
1187 }
1188 }
1189
1190
1193 public String getCacheManagerName() {
1194 return cacheManagerName;
1195 }
1196
1197
1200 public boolean allowsDynamicCacheConfig() {
1201 return getDynamicConfig();
1202 }
1203
1204
1207 public boolean isNamed() {
1208 return named;
1209 }
1210
1211
1214 public Configuration getConfiguration() {
1215 return Configuration.this;
1216 }
1217
1218
1221 public boolean isTerracottaRejoin() {
1222 TerracottaClientConfiguration terracottaConfiguration = getTerracottaConfiguration();
1223 return terracottaConfiguration != null && terracottaConfiguration.isRejoin();
1224 }
1225
1226 private boolean hasTerracottaClusteredCaches() {
1227 if (defaultCacheConfiguration != null
1228 && defaultCacheConfiguration.isTerracottaClustered()) {
1229 return true;
1230 } else {
1231 for (CacheConfiguration config : cacheConfigurations.values()) {
1232 if (config.isTerracottaClustered()) {
1233 return true;
1234 }
1235 }
1236 }
1237 return false;
1238 }
1239
1240
1243 public TransactionManagerLookup getTransactionManagerLookup() {
1244 return transactionManagerLookup;
1245 }
1246
1247
1251 public void removeCache(final CacheConfiguration cacheConfiguration) {
1252 if (cacheManager.getOnHeapPool() != null) {
1253 cacheManager.getOnHeapPool().setMaxSize(cacheManager.getOnHeapPool()
1254 .getMaxSize() + cacheConfiguration.getMaxBytesLocalHeap());
1255 }
1256 if (cacheManager.getOnDiskPool() != null) {
1257 cacheManager.getOnDiskPool().setMaxSize(cacheManager.getOnDiskPool()
1258 .getMaxSize() + cacheConfiguration.getMaxBytesLocalDisk());
1259 }
1260 getConfiguration().getCacheConfigurations().remove(cacheConfiguration.getName());
1261 }
1262
1263
1267 public void propertyChange(final PropertyChangeEvent evt) {
1268 try {
1269 DynamicProperty.valueOf(evt.getPropertyName()).applyChange(evt, this);
1270 } catch (IllegalArgumentException e) {
1271 throw new IllegalStateException(evt.getPropertyName() + " can't be changed dynamically");
1272 }
1273 }
1274
1275
1279 public boolean hasOffHeapPool() {
1280 return isMaxBytesLocalOffHeapSet();
1281 }
1282 }
1283 }
1284