1 /**
2  *  Copyright Terracotta, Inc.
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License.
15  */

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 /**
49  * A bean, used by BeanUtils, to set configuration from an XML configuration file.
50  *
51  * @author <a href="mailto:gluck@thoughtworks.com">Greg Luck</a>
52  * @version $Id: Configuration.java 6154 2012-08-18 01:07:15Z hhuynh $
53  */

54 public final class Configuration {
55
56     /**
57      * Default value for dynamicConfig
58      */

59     public static final boolean DEFAULT_DYNAMIC_CONFIG = true;
60     /**
61      * Default value for updateCheck
62      */

63     public static final boolean DEFAULT_UPDATE_CHECK = true;
64     /**
65      * Default value for defaultTransactionTimeoutInSeconds
66      */

67     public static final int  DEFAULT_TRANSACTION_TIMEOUT = 15;
68     /**
69      * Default value for maxBytesLocalHeap when not explicitly set
70      */

71     public static final long DEFAULT_MAX_BYTES_ON_HEAP   =  0;
72     /**
73      * Default value for maxBytesLocalOffHeap when not explicitly set
74      */

75     public static final long DEFAULT_MAX_BYTES_OFF_HEAP  =  0;
76     /**
77      * Default value for maxBytesLocalDisk when not explicitly set
78      */

79     public static final long DEFAULT_MAX_BYTES_ON_DISK   =  0;
80     /**
81      * Default value for monitoring
82      */

83     public static final Monitoring DEFAULT_MONITORING = Monitoring.AUTODETECT;
84     /**
85      * Default sizeOfPolicy configuration
86      */

87     public static final SizeOfPolicyConfiguration DEFAULT_SIZEOF_POLICY_CONFIGURATION = new SizeOfPolicyConfiguration();
88
89     /**
90      * Default transactionManagerLookupConfiguration
91      */

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     /**
100      * Represents whether monitoring should be enabled or not.
101      *
102      * @author amiller
103      */

104     public enum Monitoring {
105         /** When possible, notice the use of Terracotta and auto register the SampledCacheMBean. */
106         AUTODETECT,
107
108         /** Always auto register the SampledCacheMBean */
109         ON,
110
111         /** Never auto register the SampledCacheMBean */
112         OFF;
113     }
114
115     /**
116      * Enum of all properties that can change once the Configuration is being used by a CacheManager
117      */

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                     // Double check for over-allocation again
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                 // Recalculate % based caches
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                     // Double check for over-allocation again
165                     for (CacheConfiguration cacheConfiguration : config.getConfiguration().getCacheConfigurations().values()) {
166                         cacheConfiguration.isMaxBytesLocalDiskPercentageSet();
167                     }
168                 }
169                 config.cacheManager.getOnDiskPool().setMaxSize((Long) evt.getNewValue());
170                 // Recalculate % based caches ?
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     /**
201      * Empty constructor, which is used by {@link ConfigurationFactory}, and can be also used programmatically.
202      * <p/>
203      * If you are using it programmtically you need to call the relevant add and setter methods in this class to populate everything.
204      */

205     public Configuration() {
206     }
207
208     /**
209      * Returns all active caches managed by the Manager
210      * @param cacheManager The cacheManager
211      * @return the Set of all active caches
212      */

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     /**
225      * Freezes part of the configuration that need to be, and runs validation checks on the Configuration.
226      *
227      * @param cacheManager the CacheManager instance being configured
228      * @throws InvalidConfigurationException With all the associated errors
229      */

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     /**
243      * Validates the current configuration
244      * @return the list of errors withing that configuration
245      */

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     /**
256      * Checks whether the user explicitly set the maxBytesOnDisk
257      * @return true if set by user, false otherwise
258      * @see #setMaxBytesLocalDisk(Long)
259      */

260     public boolean isMaxBytesLocalDiskSet() {
261         return maxBytesLocalDisk != null;
262     }
263
264     /**
265      * Checks whether the user explicitly set the maxBytesOffHeat
266      * @return true if set by user, false otherwise
267      * @see #setMaxBytesLocalOffHeap(Long)
268      */

269     public boolean isMaxBytesLocalOffHeapSet() {
270         return maxBytesLocalOffHeap != null;
271     }
272
273     /**
274      * Checks whether the user explicitly set the maxBytesOnHeap
275      * @return true if set by user, false otherwise
276      * @see #setMaxBytesLocalHeap(Long)
277      */

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     /**
290      * Builder to set the cache manager name.
291      *
292      * @see #setName(String)
293      * @param name
294      *            the name to set
295      * @return this configuration instance
296      */

297     public final Configuration name(String name) {
298         setName(name);
299         return this;
300     }
301
302     /**
303      * Allows BeanHandler to set the CacheManager name.
304      */

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     /**
323      * CacheManager name
324      */

325     public final String getName() {
326         return this.cacheManagerName;
327     }
328
329     /**
330      * Builder to set the state of the automated update check.
331      *
332      * @param updateCheck
333      *            {@code trueif the update check should be turned on; or {@code false} otherwise
334      * @return this configuration instance
335      */

336     public final Configuration updateCheck(boolean updateCheck) {
337         setUpdateCheck(updateCheck);
338         return this;
339     }
340
341     /**
342      * Allows BeanHandler to set the updateCheck flag.
343      */

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     /**
355      * Get flag for updateCheck
356      */

357     public final boolean getUpdateCheck() {
358         return this.updateCheck;
359     }
360
361     /**
362      * Builder to set the default transaction timeout.
363      *
364      * @param defaultTransactionTimeoutInSeconds the default transaction timeout in seconds
365      * @return this configuration instance
366      */

367     public final Configuration defaultTransactionTimeoutInSeconds(int defaultTransactionTimeoutInSeconds) {
368         setDefaultTransactionTimeoutInSeconds(defaultTransactionTimeoutInSeconds);
369         return this;
370     }
371
372     /**
373      * Allows BeanHandler to set the default transaction timeout.
374      */

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     /**
386      * Get default transaction timeout
387      * @return default transaction timeout in seconds
388      */

389     public final int getDefaultTransactionTimeoutInSeconds() {
390         return defaultTransactionTimeoutInSeconds;
391     }
392
393     /**
394      * Builder to set the monitoring approach
395      *
396      * @param monitoring
397      *            an non-null instance of {@link Monitoring}
398      * @return this configuration instance
399      */

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     /**
415      * Allows BeanHandler to set the monitoring flag
416      */

417     public final void setMonitoring(String monitoring) {
418         assertArgumentNotNull("Monitoring", monitoring);
419         monitoring(Monitoring.valueOf(Monitoring.class, monitoring.toUpperCase()));
420     }
421
422     /**
423      * Get monitoring type, should not be null
424      */

425     public final Monitoring getMonitoring() {
426         return this.monitoring;
427     }
428
429     /**
430      * Builder to set the dynamic config capability
431      *
432      * @param dynamicConfig
433      *            {@code trueif dynamic config should be enabled; or {@code false} otherwise.
434      * @return this configuration instance
435      */

436     public final Configuration dynamicConfig(boolean dynamicConfig) {
437         setDynamicConfig(dynamicConfig);
438         return this;
439     }
440
441     /**
442      * Allows BeanHandler to set the dynamic configuration flag
443      */

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     /**
455      * Get flag for dynamicConfig
456      */

457     public final boolean getDynamicConfig() {
458         return this.dynamicConfig;
459     }
460
461     /**
462      * Maximum amount of bytes the CacheManager will use on the heap
463      * @return amount of bytes, 0 is unbound
464      */

465     public long getMaxBytesLocalHeap() {
466         return maxBytesLocalHeap == null ? DEFAULT_MAX_BYTES_ON_HEAP : maxBytesLocalHeap;
467     }
468
469     /**
470      * Sets maximum amount of bytes the CacheManager will use on the Disk Tier.
471      * @param maxBytesOnHeap String representation of the size.
472      * @see MemoryUnit#parseSizeInBytes(String)
473      */

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     /**
487      * @return Original input for maxBytesLocalHeap
488      */

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     /**
508      * Sets the maximum amount of bytes the cache manager being configured will use on the OnHeap tier
509      * @param maxBytesOnHeap amount of bytes
510      */

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     /**
523      * Sets the maxOnHeap size for the cache being configured
524      * @param amount the amount of unit
525      * @param memoryUnit the actual unit
526      * @return this
527      * @see #setMaxBytesLocalHeap(Long)
528      */

529     public Configuration maxBytesLocalHeap(final long amount, final MemoryUnit memoryUnit) {
530         setMaxBytesLocalHeap(memoryUnit.toBytes(amount));
531         return this;
532     }
533
534     /**
535      * Maximum amount of bytes the CacheManager will use on the OffHeap Tier.
536      * @return amount in bytes
537      */

538     public long getMaxBytesLocalOffHeap() {
539         return maxBytesLocalOffHeap == null ? DEFAULT_MAX_BYTES_OFF_HEAP : maxBytesLocalOffHeap;
540     }
541
542     /**
543      * Sets maximum amount of bytes the CacheManager will use on the OffHeap Tier.
544      * @param maxBytesOffHeap String representation of the size.
545      * @see MemoryUnit#parseSizeInBytes(String)
546      */

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     /**
560      * @return Original input for maxBytesLocalOffHeap
561      */

562     public String getMaxBytesLocalOffHeapAsString() {
563         return maxBytesLocalOffHeapInput != null ? maxBytesLocalOffHeapInput : Long.toString(getMaxBytesLocalOffHeap());
564     }
565
566     /**
567      * @return Total amount offheap configured by current caches
568      */

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     /**
603      * Sets maximum amount of bytes the CacheManager will use on the OffHeap Tier.
604      * @param maxBytesOffHeap max bytes on disk in bytes. Needs be be greater than 0
605      */

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     /**
618      * Sets the maximum size for the OffHeap tier for all the caches this CacheManagers holds.
619      * @param amount the amount of unit
620      * @param memoryUnit the actual unit
621      * @return this
622      */

623     public Configuration maxBytesLocalOffHeap(final long amount, final MemoryUnit memoryUnit) {
624         setMaxBytesLocalOffHeap(memoryUnit.toBytes(amount));
625         return this;
626     }
627
628     /**
629      * Maximum amount of bytes the CacheManager will use on the Disk Tier.
630      * @return amount in bytes
631      */

632     public long getMaxBytesLocalDisk() {
633         return maxBytesLocalDisk == null ? DEFAULT_MAX_BYTES_ON_DISK : maxBytesLocalDisk;
634     }
635
636     /**
637      * Sets maximum amount of bytes the CacheManager will use on the Disk Tier.
638      * @param maxBytesOnDisk String representation of the size.
639      * @see MemoryUnit#parseSizeInBytes(String)
640      */

641     public void setMaxBytesLocalDisk(final String maxBytesOnDisk) {
642         assertArgumentNotNull("MaxBytesLocalDisk", maxBytesOnDisk);
643         setMaxBytesLocalDisk(MemoryUnit.parseSizeInBytes(maxBytesOnDisk));
644         maxBytesLocalDiskInput = maxBytesOnDisk;
645     }
646
647     /**
648      * @return Original input for maxBytesLocalDisk
649      */

650     public String getMaxBytesLocalDiskAsString() {
651         return maxBytesLocalDiskInput != null ? maxBytesLocalDiskInput : Long.toString(getMaxBytesLocalDisk());
652     }
653
654     /**
655      * Sets maximum amount of bytes the CacheManager will use on the Disk Tier.
656      * @param maxBytesOnDisk max bytes on disk in bytes. Needs be be greater than 0
657      */

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     /**
670      * Sets the maxOnDisk size
671      * @param amount the amount of unit
672      * @param memoryUnit the actual unit
673      * @return this
674      * @see #setMaxBytesLocalDisk(Long)
675      */

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     /**
688      * Builder to add a disk store to the cache manager, only one disk store can be added.
689      *
690      * @param diskStoreConfigurationParameter
691      *            the disk store configuration to use
692      * @return this configuration instance
693      * @throws ObjectExistsException
694      *             if the disk store has already been configured
695      */

696     public final Configuration diskStore(DiskStoreConfiguration diskStoreConfigurationParameter) throws ObjectExistsException {
697         addDiskStore(diskStoreConfigurationParameter);
698         return this;
699     }
700
701     /**
702      * Allows BeanHandler to add disk store location to the configuration.
703      */

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     /**
718      * Builder to set the default SizeOfPolicyConfiguration for this cache manager.
719      *
720      * @param sizeOfPolicyConfiguration the SizeOfPolicy Configuration
721      * @return this configuration instance
722      */

723     public final Configuration sizeOfPolicy(SizeOfPolicyConfiguration sizeOfPolicyConfiguration) {
724         addSizeOfPolicy(sizeOfPolicyConfiguration);
725         return this;
726     }
727
728     /**
729      * Sets the default SizeOfPolicyConfiguration for this cache manager.
730      *
731      * @param sizeOfPolicy the SizeOfPolicy Configuration
732      */

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     /**
741      * Builder to add a transaction manager lookup class to the cache manager, only one of these can be added.
742      *
743      * @param transactionManagerLookupParameter
744      *            the transaction manager lookup class to use
745      * @return this configuration instance
746      * @throws ObjectExistsException
747      *             if the transaction manager lookup has already been configured
748      */

749     public final Configuration transactionManagerLookup(FactoryConfiguration transactionManagerLookupParameter)
750             throws ObjectExistsException {
751         addTransactionManagerLookup(transactionManagerLookupParameter);
752         return this;
753     }
754
755     /**
756      * Allows BeanHandler to add transaction manager lookup to the configuration.
757      */

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     /**
772      * Builder to set the event lister through a factory, only one of these can be added and subsequent calls are ignored.
773      *
774      * @return this configuration instance
775      */

776     public final Configuration cacheManagerEventListenerFactory(FactoryConfiguration cacheManagerEventListenerFactoryConfiguration) {
777         addCacheManagerEventListenerFactory(cacheManagerEventListenerFactoryConfiguration);
778         return this;
779     }
780
781     /**
782      * Allows BeanHandler to add the CacheManagerEventListener to the configuration.
783      */

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     /**
796      * Builder method to add a peer provider through a factory.
797      *
798      * @return this configuration instance
799      */

800     public final Configuration cacheManagerPeerProviderFactory(FactoryConfiguration factory) {
801         addCacheManagerPeerProviderFactory(factory);
802         return this;
803     }
804
805     /**
806      * Adds a CacheManagerPeerProvider through FactoryConfiguration.
807      */

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     /**
822      * Builder method to add a peer listener through a factory.
823      *
824      * @return this configuration instance
825      */

826     public final Configuration cacheManagerPeerListenerFactory(FactoryConfiguration factory) {
827         addCacheManagerPeerListenerFactory(factory);
828         return this;
829     }
830
831     /**
832      * Adds a CacheManagerPeerListener through FactoryConfiguration.
833      */

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     /**
848      * Builder method to Terracotta capabilities to the cache manager through a dedicated configuration, this can only be used once.
849      *
850      * @return this configuration instance
851      * @throws ObjectExistsException
852      *             if the Terracotta config has already been configured
853      */

854     public final Configuration terracotta(TerracottaClientConfiguration terracottaConfiguration) throws ObjectExistsException {
855         addTerracottaConfig(terracottaConfiguration);
856         return this;
857     }
858
859     /**
860      * Allows BeanHandler to add a Terracotta configuration to the configuration
861      */

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     /**
876      * Builder method to REST management capabilities to the cache manager through a dedicated configuration, this can only be used once.
877      *
878      * @return this configuration instance
879      * @throws ObjectExistsException
880      *             if the REST management config has already been configured
881      */

882     public final Configuration managementRESTService(ManagementRESTServiceConfiguration cfg) throws ObjectExistsException {
883         addManagementRESTService(cfg);
884         return this;
885     }
886
887     /**
888      * Allows BeanHandler to add a ManagementRESTService configuration to the configuration
889      */

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     /**
905      * Builder method to set the default cache configuration, this can only be used once.
906      *
907      * @return this configuration instance
908      * @throws ObjectExistsException
909      *             if the default cache config has already been configured
910      */

911     public final Configuration defaultCache(CacheConfiguration defaultCacheConfiguration) throws ObjectExistsException {
912         setDefaultCacheConfiguration(defaultCacheConfiguration);
913         return this;
914     }
915
916     /**
917      * Allows BeanHandler to add a default configuration to the configuration.
918      */

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     /**
927      * Builder to add a new cache through its config
928      *
929      * @return this configuration instance
930      * @throws ObjectExistsException
931      *             if a cache with the same name already exists, or if the name conflicts with the name of the default cache
932      */

933     public final Configuration cache(CacheConfiguration cacheConfiguration) throws ObjectExistsException {
934         addCache(cacheConfiguration);
935         return this;
936     }
937
938     /**
939      * Allows BeanHandler to add Cache Configurations to the configuration.
940      */

941     public final void addCache(CacheConfiguration cacheConfiguration) throws ObjectExistsException {
942         addCache(cacheConfiguration, true);
943     }
944
945     /**
946      * Maintains the known Cache's configuration map in this Configuration
947      * @param cacheConfiguration the CacheConfiguration
948      * @param strict true if added regularly, validation dyn config constraints, false if added through the cache being added
949      */

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     /**
986      * Gets a Map of cacheConfigurations.
987      */

988     public final Set<String> getCacheConfigurationsKeySet() {
989         return cacheConfigurations.keySet();
990     }
991
992     /**
993      * @return the configuration's default cache configuration
994      */

995     public final CacheConfiguration getDefaultCacheConfiguration() {
996         return defaultCacheConfiguration;
997     }
998
999     /**
1000      * @param defaultCacheConfiguration
1001      */

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     /**
1013      * Gets the disk store configuration.
1014      */

1015     public final DiskStoreConfiguration getDiskStoreConfiguration() {
1016         return diskStoreConfiguration;
1017     }
1018
1019     /**
1020      * Gets the SizeOf policy configuration.
1021      */

1022     public final SizeOfPolicyConfiguration getSizeOfPolicyConfiguration() {
1023         if (sizeOfPolicyConfiguration == null) {
1024             return DEFAULT_SIZEOF_POLICY_CONFIGURATION;
1025         }
1026         return sizeOfPolicyConfiguration;
1027     }
1028
1029     /**
1030      * Gets the transaction manager lookup configuration.
1031      */

1032     public final FactoryConfiguration getTransactionManagerLookupConfiguration() {
1033         if (transactionManagerLookupConfiguration == null) {
1034             return getDefaultTransactionManagerLookupConfiguration();
1035         }
1036         return transactionManagerLookupConfiguration;
1037     }
1038
1039     /**
1040      * Gets the CacheManagerPeerProvider factory configuration.
1041      */

1042     public final List<FactoryConfiguration> getCacheManagerPeerProviderFactoryConfiguration() {
1043         return cacheManagerPeerProviderFactoryConfiguration;
1044     }
1045
1046     /**
1047      * Gets the CacheManagerPeerListener factory configuration.
1048      */

1049     public final List<FactoryConfiguration> getCacheManagerPeerListenerFactoryConfigurations() {
1050         return cacheManagerPeerListenerFactoryConfiguration;
1051     }
1052
1053     /**
1054      * Gets the ManagementRESTServiceConfiguration
1055      */

1056     public final ManagementRESTServiceConfiguration getManagementRESTService() {
1057         return managementRESTService;
1058     }
1059
1060     /**
1061      * Gets the CacheManagerEventListener factory configuration.
1062      */

1063     public final FactoryConfiguration getCacheManagerEventListenerFactoryConfiguration() {
1064         return cacheManagerEventListenerFactoryConfiguration;
1065     }
1066
1067     /**
1068      * Gets the TerracottaClientConfiguration
1069      */

1070     public final TerracottaClientConfiguration getTerracottaConfiguration() {
1071         return this.terracottaConfigConfiguration;
1072     }
1073
1074     /**
1075      * Gets a Map of cache configurations, keyed by name.
1076      */

1077     public final Map<String, CacheConfiguration> getCacheConfigurations() {
1078         return cacheConfigurations;
1079     }
1080
1081     /**
1082      * Builder to set the configuration source.
1083      *
1084      * @return this configuration instance
1085      */

1086     public final Configuration source(ConfigurationSource configurationSource) {
1087         setSource(configurationSource);
1088         return this;
1089     }
1090
1091     /**
1092      * Sets the configuration source.
1093      *
1094      * @param configurationSource
1095      *            an informative description of the source, preferably
1096      *            including the resource name and location.
1097      */

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     /**
1109      * Gets a description of the source from which this configuration was created.
1110      */

1111     public final ConfigurationSource getConfigurationSource() {
1112         return configurationSource;
1113     }
1114
1115     /**
1116      * Adds a {@link PropertyChangeListener} for this configuration
1117      * @param listener the listener instance
1118      * @return true if added, false otherwise
1119      */

1120     public boolean addPropertyChangeListener(final PropertyChangeListener listener) {
1121         return this.propertyChangeListeners.add(listener);
1122     }
1123
1124     /**
1125      * Removes a {@link PropertyChangeListener} for this configuration
1126      * @param listener the listener to be removed
1127      * @return true if removed, false otherwise
1128      */

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     /**
1142      * Runtime configuration as being used by the CacheManager
1143      */

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         /**
1153          * Constructor
1154          * @param cacheManager the cacheManager instance using this config
1155          * @param fallbackName the fallbackName in case the configuration doesn't declare an explicit name
1156          */

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         /**
1191          * @return the CacheManager's name
1192          */

1193         public String getCacheManagerName() {
1194             return cacheManagerName;
1195         }
1196
1197         /**
1198          * @return Whether dynamic config changes are available
1199          */

1200         public boolean allowsDynamicCacheConfig() {
1201             return getDynamicConfig();
1202         }
1203
1204         /**
1205          * @return Whether the CacheManager is explicitly named
1206          */

1207         public boolean isNamed() {
1208             return named;
1209         }
1210
1211         /**
1212          * @return the underlying Configuration instance
1213          */

1214         public Configuration getConfiguration() {
1215             return Configuration.this;
1216         }
1217
1218         /**
1219          * @return Whether terracotta clustering is being used and rejoin is enabled
1220          */

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         /**
1241          * @return The transactionManagerLookup instance
1242          */

1243         public TransactionManagerLookup getTransactionManagerLookup() {
1244             return transactionManagerLookup;
1245         }
1246
1247         /**
1248          * Removes a cache from the known list
1249          * @param cacheConfiguration the cacheConfiguration to be removed
1250          */

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         /**
1264          * Handles changes to the Configuration this RuntimeCfg backs
1265          * @param evt the PropertyChangeEvent
1266          */

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         /**
1276          * Checks whether the CacheManager uses a OffHeapPool
1277          * @return true if using one, false otherwise
1278          */

1279         public boolean hasOffHeapPool() {
1280             return isMaxBytesLocalOffHeapSet();
1281         }
1282     }
1283 }
1284