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 static net.sf.ehcache.config.Configuration.getAllActiveCaches;
20
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Set;
27 import java.util.concurrent.CopyOnWriteArraySet;
28
29 import net.sf.ehcache.Cache;
30 import net.sf.ehcache.CacheException;
31 import net.sf.ehcache.CacheManager;
32 import net.sf.ehcache.Element;
33 import net.sf.ehcache.config.PersistenceConfiguration.Strategy;
34 import net.sf.ehcache.config.TerracottaConfiguration.Consistency;
35 import net.sf.ehcache.event.NotificationScope;
36 import net.sf.ehcache.search.attribute.DynamicAttributesExtractor;
37 import net.sf.ehcache.store.MemoryStoreEvictionPolicy;
38 import net.sf.ehcache.store.compound.ReadWriteCopyStrategy;
39
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43 /**
44  * A value object used to represent cache configuration.
45  * <h4>Construction Patterns</h4>
46  * The recommended way of creating a <code>Cache</code> in Ehcache 2.0 and above is to create a <code>CacheConfiguration</code> object
47  * and pass it to the <code>Cache</code> constructor. See {@link net.sf.ehcache.Cache#Cache(CacheConfiguration)}.
48  * <p/>
49  * This class supports setter injection and also the fluent builder pattern.
50  * e.g.
51  * <code>Cache cache = new Cache(new CacheConfiguration("test2", 1000).eternal(true).memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy.FIFO));</code>
52  * <p/>
53  * Rather than proliferation of new constructors as new versions of Ehcache come out, it intended to add the new configuration to this
54  * class.
55  * <p/>
56  * Another way to set configuration is declaratively in the <code>ehcache.xml</code> configuration file.
57  * e.g.
58  * <pre>{@code
59  * <cache name="testCache1"
60  *   maxEntriesLocalHeap="10000"
61  *   eternal="false"
62  *   timeToIdleSeconds="3600"
63  *   timeToLiveSeconds="10"
64  *   overflowToDisk="true"
65  *   diskPersistent="true"
66  *   diskExpiryThreadIntervalSeconds="120"
67  *   maxEntriesLocalDisk="10000"
68  * />
69  * }</pre>
70  * <p/>
71  * <h4>Dynamic Configuration</h4>
72  * CacheConfiguration instances retrieved from Cache instances allow the dynamic
73  * modification of certain configuration properties.  Currently the dynamic
74  * properties are:
75  * <ul>
76  * <li>Time To Idle</li>
77  * <li>Time To Live</li>
78  * <li>Max Entries in Local Heap</li>
79  * <li>Max Entries on Local Disk</li>
80  * </ul>
81  * Dynamic changes are however not persistent across cache restarts.  On restart
82  * the cache configuration will be reloaded from its original source, erasing any
83  * changes made previously at runtime.
84  *
85  * @author Greg Luck
86  * @author Chris Dennis
87  * @version $Id: CacheConfiguration.java 6879 2013-01-17 07:54:30Z vfunshte $
88  */

89 public class CacheConfiguration implements Cloneable {
90
91     /**
92      * Default value for clearOnFlush
93      */

94     public static final boolean DEFAULT_CLEAR_ON_FLUSH = true;
95
96     /**
97      * The default interval between runs of the expiry thread.
98      */

99     public static final long DEFAULT_EXPIRY_THREAD_INTERVAL_SECONDS = 120;
100
101     /**
102      * Set a buffer size for the spool of approx 30MB.
103      */

104     public static final int DEFAULT_SPOOL_BUFFER_SIZE = 30;
105
106     /**
107      * Default number of diskAccessStripes.
108      */

109     public static final int DEFAULT_DISK_ACCESS_STRIPES = 1;
110
111     /**
112      * Logging is off by default.
113      */

114     public static final boolean DEFAULT_LOGGING = false;
115
116     /**
117      * The default memory store eviction policy is LRU.
118      */

119     public static final MemoryStoreEvictionPolicy DEFAULT_MEMORY_STORE_EVICTION_POLICY = MemoryStoreEvictionPolicy.LRU;
120
121     /**
122      * The default cacheWriterConfiguration
123      */

124     public static final CacheWriterConfiguration DEFAULT_CACHE_WRITER_CONFIGURATION = new CacheWriterConfiguration();
125
126     /**
127      * Default value for copyOnRead
128      */

129     public static final boolean DEFAULT_COPY_ON_READ = false;
130
131     /**
132      * Default value for copyOnRead
133      */

134     public static final boolean DEFAULT_COPY_ON_WRITE = false;
135
136     /**
137      * Default value for ttl
138      */

139     public static final long DEFAULT_TTL = 0;
140
141     /**
142      * Default value for tti
143      */

144     public static final long DEFAULT_TTI = 0;
145
146     /**
147      * Default value for maxElementsOnDisk
148      */

149     public static final int DEFAULT_MAX_ELEMENTS_ON_DISK = 0;
150
151     /**
152      * Default value for transactionalMode
153      */

154     public static final TransactionalMode DEFAULT_TRANSACTIONAL_MODE = TransactionalMode.OFF;
155
156     /**
157      * Default value for statistics
158      */

159     public static final boolean DEFAULT_STATISTICS = false;
160
161     /**
162      * Default value for diskPersistent
163      *
164      * @deprecated The {@code diskPersistent} attribute has been replaced with {@link #persistence(PersistenceConfiguration)}.
165      */

166     @Deprecated
167     public static final boolean DEFAULT_DISK_PERSISTENT = false;
168
169     /**
170      * Default copyStrategyConfiguration
171      */

172     public static final CopyStrategyConfiguration DEFAULT_COPY_STRATEGY_CONFIGURATION = new CopyStrategyConfiguration();
173
174     /**
175      * Default maxBytesOnHeap value
176      */

177     public static final long DEFAULT_MAX_BYTES_ON_HEAP  = 0;
178
179     /**
180      * Default maxBytesOffHeap value
181      */

182     public static final long DEFAULT_MAX_BYTES_OFF_HEAP = 0;
183
184     /**
185      * Default maxBytesOnDisk value
186      */

187     public static final long DEFAULT_MAX_BYTES_ON_DISK  = 0;
188
189     /**
190      * Default eternal value
191      */

192     public static final boolean DEFAULT_ETERNAL_VALUE = false;
193
194
195     private static final Logger LOG = LoggerFactory.getLogger(CacheConfiguration.class.getName());
196     private static final int HUNDRED_PERCENT = 100;
197     private static final int MINIMUM_RECOMMENDED_IN_MEMORY = 100;
198
199     /**
200      * the name of the cache.
201      */

202     protected volatile String name;
203
204     /**
205      * Timeout in milliseconds for CacheLoader related calls
206      */

207     protected volatile long cacheLoaderTimeoutMillis;
208
209     /**
210      * the maximum objects to be held in the {@link net.sf.ehcache.store.MemoryStore}.
211      * <p/>
212      * <code>0</code> translates to no-limit.
213      */

214     protected volatile Integer maxEntriesLocalHeap;
215
216     /**
217      * the maximum objects to be held in the {@link net.sf.ehcache.store.disk.DiskStore}.
218      * <p/>
219      * <code>0</code> translates to no-limit.
220      */

221     protected volatile int maxElementsOnDisk = DEFAULT_MAX_ELEMENTS_ON_DISK;
222
223     /**
224      * The policy used to evict elements from the {@link net.sf.ehcache.store.MemoryStore}.
225      * This can be one of:
226      * <ol>
227      * <li>LRU - least recently used
228      * <li>LFU - Less frequently used
229      * <li>FIFO - first in first out, the oldest element by creation time
230      * </ol>
231      * The default value is LRU
232      *
233      * @since 1.2
234      */

235     protected volatile MemoryStoreEvictionPolicy memoryStoreEvictionPolicy = DEFAULT_MEMORY_STORE_EVICTION_POLICY;
236
237     /**
238      * Sets whether the MemoryStore should be cleared when
239      * {@link net.sf.ehcache.Ehcache#flush flush()} is called on the cache - true by default.
240      */

241     protected volatile boolean clearOnFlush = DEFAULT_CLEAR_ON_FLUSH;
242
243     /**
244      * Sets whether elements are eternal. If eternal, timeouts are ignored and the element
245      * is never expired.
246      */

247     protected volatile boolean eternal = DEFAULT_ETERNAL_VALUE;
248
249     /**
250      * the time to idle for an element before it expires. Is only used
251      * if the element is not eternal.A value of 0 means do not check for idling.
252      */

253     protected volatile long timeToIdleSeconds = DEFAULT_TTI;
254
255     /**
256      * Sets the time to idle for an element before it expires. Is only used
257      * if the element is not eternal. This attribute is optional in the configuration.
258      * A value of 0 means do not check time to live.
259      */

260     protected volatile long timeToLiveSeconds = DEFAULT_TTL;
261
262     /**
263      * whether elements can overflow to disk when the in-memory cache
264      * has reached the set limit.
265      *
266      * @deprecated The {@code overflowToDisk} attribute has been replaced with {@link Strategy#LOCALTEMPSWAP}.
267      */

268     @Deprecated
269     protected volatile Boolean overflowToDisk;
270
271     /**
272      * For caches that overflow to disk, whether the disk cache persists between CacheManager instances.
273      *
274      * @deprecated The {@code diskPersistent} attribute has been replaced with {@link #persistence(PersistenceConfiguration)}.
275      */

276     @Deprecated
277     protected volatile Boolean diskPersistent;
278
279     /**
280      * The size of the disk spool used to buffer writes
281      */

282     protected volatile int diskSpoolBufferSizeMB = DEFAULT_SPOOL_BUFFER_SIZE;
283
284     /**
285      * The number of concurrent disk access stripes.
286      */

287     protected volatile int diskAccessStripes = DEFAULT_DISK_ACCESS_STRIPES;
288
289     /**
290      * The interval in seconds between runs of the disk expiry thread.
291      * <p/>
292      * 2 minutes is the default.
293      * This is not the same thing as time to live or time to idle. When the thread runs it checks
294      * these things. So this value is how often we check for expiry.
295      */

296     protected volatile long diskExpiryThreadIntervalSeconds = DEFAULT_EXPIRY_THREAD_INTERVAL_SECONDS;
297
298     /**
299      * Indicates whether logging is enabled or not. False by default.
300      * Only used when cache is clustered with Terracotta.
301      */

302     protected volatile boolean logging = DEFAULT_LOGGING;
303
304     /**
305      * whether elements can overflow to off heap memory when the in-memory cache
306      * has reached the set limit.
307      */

308     protected volatile Boolean overflowToOffHeap;
309
310     /**
311      * The event listener factories added by BeanUtils.
312      */

313     protected volatile List<CacheEventListenerFactoryConfiguration> cacheEventListenerConfigurations =
314             new ArrayList<CacheEventListenerFactoryConfiguration>();
315
316     /**
317      * The cache extension factories added by BeanUtils.
318      */

319     protected volatile List<CacheExtensionFactoryConfiguration> cacheExtensionConfigurations =
320             new ArrayList<CacheExtensionFactoryConfiguration>();
321
322     /**
323      * The BootstrapCacheLoaderFactoryConfiguration.
324      */

325     protected BootstrapCacheLoaderFactoryConfiguration bootstrapCacheLoaderFactoryConfiguration;
326
327     /**
328      * The CacheExceptionHandlerFactoryConfiguration.
329      */

330     protected CacheExceptionHandlerFactoryConfiguration cacheExceptionHandlerFactoryConfiguration;
331
332     /**
333      * The TerracottaConfiguration.
334      */

335     protected TerracottaConfiguration terracottaConfiguration;
336
337     /**
338      * The PinningConfiguration.
339      */

340     protected volatile PinningConfiguration pinningConfiguration;
341
342     /**
343      * The CacheWriterConfiguration.
344      */

345     protected CacheWriterConfiguration cacheWriterConfiguration = DEFAULT_CACHE_WRITER_CONFIGURATION;
346
347     /**
348      * The cache loader factories added by BeanUtils.
349      */

350     protected volatile List<CacheLoaderFactoryConfiguration> cacheLoaderConfigurations = new ArrayList<CacheLoaderFactoryConfiguration>();
351
352     /**
353      * The cache decorator factories added by BeanUtils.
354      */

355     protected volatile List<CacheDecoratorFactoryConfiguration> cacheDecoratorConfigurations =
356             new ArrayList<CacheDecoratorFactoryConfiguration>();
357
358     /**
359      * The listeners for this configuration.
360      */

361     protected volatile Set<CacheConfigurationListener> listeners = new CopyOnWriteArraySet<CacheConfigurationListener>();
362
363     private volatile Set<DynamicSearchListener> dynamicSearchListeners = new CopyOnWriteArraySet<DynamicSearchListener>();
364
365     private DynamicAttributesExtractor flexIndexer;
366     private volatile boolean frozen;
367     private volatile TransactionalMode transactionalMode;
368     private volatile boolean statistics = DEFAULT_STATISTICS;
369     private volatile CopyStrategyConfiguration copyStrategyConfiguration = DEFAULT_COPY_STRATEGY_CONFIGURATION.copy();
370     private volatile SizeOfPolicyConfiguration sizeOfPolicyConfiguration;
371     private volatile PersistenceConfiguration persistenceConfiguration;
372     private volatile ElementValueComparatorConfiguration elementValueComparatorConfiguration =
373         new ElementValueComparatorConfiguration();
374     private volatile Boolean copyOnRead;
375     private volatile Boolean copyOnWrite;
376     private volatile boolean conflictingEternalValuesWarningLogged;
377     private volatile Searchable searchable;
378     private String maxBytesLocalHeapInput;
379     private String maxBytesLocalOffHeapInput;
380     private String maxBytesLocalDiskInput;
381     private Long maxBytesLocalHeap;
382     private Long maxBytesLocalOffHeap;
383     private Long maxBytesLocalDisk;
384     private Integer maxBytesLocalHeapPercentage;
385     private Integer maxBytesLocalOffHeapPercentage;
386     private Integer maxBytesLocalDiskPercentage;
387     private PoolUsage onHeapPoolUsage;
388     private PoolUsage offHeapPoolUsage;
389     private PoolUsage onDiskPoolUsage;
390     private volatile boolean maxEntriesLocalDiskExplicitlySet;
391     private volatile boolean maxBytesLocalDiskExplicitlySet;
392     private volatile boolean maxBytesLocalOffHeapExplicitlySet;
393
394     /**
395      * Default constructor.
396      * <p/>
397      * Note that an empty Cache is not valid and must have extra configuration added which can be done
398      * through the fluent methods in this class. Call <code>validateConfiguration()</code> to check your configuration.
399      *
400      * @see #validateCompleteConfiguration
401      */

402     public CacheConfiguration() {
403         // empty constructor
404     }
405
406     /**
407      * Create a new cache configuration.
408      * <p/>
409      * Extra configuration can added after construction via the fluent methods in this class.
410      * Call <code>validateConfiguration()</code> to check your configuration.
411      *
412      * @param name                the name of the cache. Note that "default" is a reserved name for the defaultCache.
413      * @param maxEntriesLocalHeap the maximum number of elements in memory, before they are evicted (0 == no limit)
414      * @see #validateCompleteConfiguration()
415      */

416     public CacheConfiguration(String name, int maxEntriesLocalHeap) {
417         this.name = name;
418         this.maxEntriesLocalHeap = maxEntriesLocalHeap;
419     }
420
421     /**
422      * Clones this object, following the usual contract.
423      *
424      * @return a copy, which independent other than configurations than cannot change.
425      */

426     @Override
427     public CacheConfiguration clone() {
428         CacheConfiguration config;
429         try {
430             config = (CacheConfiguration) super.clone();
431         } catch (CloneNotSupportedException e) {
432             throw new RuntimeException(e);
433         }
434
435         cloneCacheEventListenerConfigurations(config);
436
437         cloneCacheExtensionConfigurations(config);
438
439         if (bootstrapCacheLoaderFactoryConfiguration != null) {
440             config.bootstrapCacheLoaderFactoryConfiguration = bootstrapCacheLoaderFactoryConfiguration.clone();
441         }
442
443         if (cacheExceptionHandlerFactoryConfiguration != null) {
444             config.cacheExceptionHandlerFactoryConfiguration = cacheExceptionHandlerFactoryConfiguration.clone();
445         }
446
447         if (terracottaConfiguration != null) {
448             config.terracottaConfiguration = terracottaConfiguration.clone();
449         }
450
451         if (cacheWriterConfiguration != null) {
452             config.cacheWriterConfiguration = cacheWriterConfiguration.clone();
453         }
454
455         cloneCacheLoaderConfigurations(config);
456
457         cloneCacheDecoratorConfigurations(config);
458
459         config.listeners = new CopyOnWriteArraySet<CacheConfigurationListener>();
460         config.dynamicSearchListeners = new CopyOnWriteArraySet<DynamicSearchListener>();
461
462         return config;
463     }
464
465     private void cloneCacheEventListenerConfigurations(CacheConfiguration config) {
466         if (cacheEventListenerConfigurations.size() > 0) {
467             List<CacheEventListenerFactoryConfiguration> copy = new ArrayList<CacheEventListenerFactoryConfiguration>();
468             for (CacheEventListenerFactoryConfiguration item : cacheEventListenerConfigurations) {
469                 copy.add(item.clone());
470             }
471             config.cacheEventListenerConfigurations = copy;
472         }
473     }
474
475     private void cloneCacheExtensionConfigurations(CacheConfiguration config) {
476         if (cacheExtensionConfigurations.size() > 0) {
477             List<CacheExtensionFactoryConfiguration> copy = new ArrayList<CacheExtensionFactoryConfiguration>();
478             for (CacheConfiguration.CacheExtensionFactoryConfiguration item : cacheExtensionConfigurations) {
479                 copy.add(item.clone());
480             }
481             config.cacheExtensionConfigurations = copy;
482         }
483     }
484
485     private void cloneCacheLoaderConfigurations(CacheConfiguration config) {
486         if (cacheLoaderConfigurations.size() > 0) {
487             List<CacheLoaderFactoryConfiguration> copy = new ArrayList<CacheLoaderFactoryConfiguration>();
488             for (CacheConfiguration.CacheLoaderFactoryConfiguration item : cacheLoaderConfigurations) {
489                 copy.add(item.clone());
490             }
491             config.cacheLoaderConfigurations = copy;
492         }
493     }
494
495     private void cloneCacheDecoratorConfigurations(CacheConfiguration config) {
496         if (cacheDecoratorConfigurations.size() > 0) {
497             List<CacheDecoratorFactoryConfiguration> copy = new ArrayList<CacheDecoratorFactoryConfiguration>();
498             for (CacheDecoratorFactoryConfiguration item : cacheDecoratorConfigurations) {
499                 copy.add(item.clone());
500             }
501             config.cacheDecoratorConfigurations = copy;
502         }
503     }
504
505     private void assertArgumentNotNull(String name, Object object) {
506         if (object == null) {
507             throw new IllegalArgumentException(name + " cannot be null");
508         }
509     }
510
511     /**
512      * Sets the name of the cache.
513      *
514      * @param name the cache name. This must be unique. The / character is illegal. The # character does not work with RMI replication.
515      */

516     public final void setName(String name) {
517         checkDynamicChange();
518         assertArgumentNotNull("Cache name", name);
519         this.name = name;
520     }
521
522     /**
523      * Builder to set the name of the cache.
524      *
525      * @param name the cache name. This must be unique. The / character is illegal. The # character does not work with RMI replication.
526      * @return this configuration instance
527      * @see #setName(String)
528      */

529     public final CacheConfiguration name(String name) {
530         setName(name);
531         return this;
532     }
533
534     /**
535      * Enables or disables logging for the cache
536      * <p/>
537      * This property can be modified dynamically while the cache is operating.
538      * Only used when cache is clustered with Terracotta
539      *
540      * @param enable If true, enables logging otherwise disables logging
541      */

542     public final void setLogging(boolean enable) {
543         checkDynamicChange();
544         boolean oldLoggingEnabled = this.logging;
545         this.logging = enable;
546         fireLoggingChanged(oldLoggingEnabled, enable);
547     }
548
549     /**
550      * Enables or disables offheap store for the cache.
551      *
552      * @param overflowToOffHeap If true, enables offheap store otherwise disables it.
553      */

554     public final void setOverflowToOffHeap(boolean overflowToOffHeap) {
555         checkDynamicChange();
556         this.overflowToOffHeap = overflowToOffHeap;
557     }
558
559     /**
560      * Builder to enable or disable offheap store for the cache.
561      *
562      * @param overflowToOffHeap If true, enables offheap store otherwise disables it.
563      * @return this configuration instance
564      * @see #setOverflowToOffHeap(boolean)
565      */

566     public CacheConfiguration overflowToOffHeap(boolean overflowToOffHeap) {
567         setOverflowToOffHeap(overflowToOffHeap);
568         return this;
569     }
570
571     /**
572      * Sets the SizeOfPolicyConfiguration for this cache.
573      *
574      * @param sizeOfPolicyConfiguration the SizeOfPolicy Configuration
575      */

576     public void addSizeOfPolicy(SizeOfPolicyConfiguration sizeOfPolicyConfiguration) {
577         this.sizeOfPolicyConfiguration = sizeOfPolicyConfiguration;
578     }
579
580     /**
581      * Builder to set the SizeOfPolicyConfiguration for this cache.
582      *
583      * @param sizeOfPolicyConfiguration the SizeOfPolicy Configuration
584      * @return this configuration instance
585      * @see #addSizeOfPolicy(SizeOfPolicyConfiguration)
586      */

587     public CacheConfiguration sizeOfPolicy(SizeOfPolicyConfiguration sizeOfPolicyConfiguration) {
588         addSizeOfPolicy(sizeOfPolicyConfiguration);
589         return this;
590     }
591
592     /**
593      * Sets the PersistenceConfiguration for this cache.
594      *
595      * @param persistenceConfiguration the Persistence Configuration
596      */

597     public void addPersistence(PersistenceConfiguration persistenceConfiguration) {
598         if (diskPersistent != null) {
599             throw new InvalidConfigurationException("Cannot use both <persistence ...> and diskPersistent in a single cache configuration.");
600         }
601         if (Boolean.TRUE.equals(overflowToDisk)) {
602             throw new InvalidConfigurationException("Cannot use both <persistence ...> and overflowToDisk in a single cache configuration.");
603         }
604         this.persistenceConfiguration = persistenceConfiguration;
605     }
606
607     /**
608      * Builder to set the PersistenceConfiguration for this cache.
609      *
610      * @param persistenceConfiguration the Persistence Configuration
611      * @return this configuration instance
612      * @see #addPersistence(PersistenceConfiguration)
613      */

614     public CacheConfiguration persistence(PersistenceConfiguration persistenceConfiguration) {
615         addPersistence(persistenceConfiguration);
616         return this;
617     }
618
619     /**
620      * Sets the max off heap memory size allocated for this cache.
621      *
622      * @param maxMemoryOffHeap the max off heap memory size allocated for this cache.
623      * @deprecated See {@link #setMaxBytesLocalOffHeap(java.lang.String)}
624      */

625     @Deprecated
626     public final void setMaxMemoryOffHeap(String maxMemoryOffHeap) {
627         checkDynamicChange();
628         assertArgumentNotNull("Cache maxMemoryOffHeap", maxMemoryOffHeap);
629         setMaxBytesLocalOffHeap(maxMemoryOffHeap);
630     }
631
632     /**
633      * Builder to set the max off heap memory size allocated for this cache.
634      *
635      * @param maxMemoryOffHeap the max off heap memory size allocated for this cache.
636      * @return this configuration instance
637      * @deprecated See {@link #maxBytesLocalOffHeap(long, net.sf.ehcache.config.MemoryUnit)}
638      */

639     @Deprecated
640     public CacheConfiguration maxMemoryOffHeap(String maxMemoryOffHeap) {
641         setMaxMemoryOffHeap(maxMemoryOffHeap);
642         return this;
643     }
644
645     /**
646      * Builder to enable or disable logging for the cache
647      * <p/>
648      * This property can be modified dynamically while the cache is operating.
649      * Only used when cache is clustered with Terracotta
650      *
651      * @param enable If true, enables logging otherwise disables logging
652      * @return this configuration instance
653      * @see #setLogging(boolean)
654      */

655     public final CacheConfiguration logging(boolean enable) {
656         setLogging(enable);
657         return this;
658     }
659
660     /**
661      * Sets the maximum objects to be held in memory (0 = no limit).
662      * <p/>
663      * This property can be modified dynamically while the cache is operating.
664      *
665      * @param maxElementsInMemory The maximum number of elements in memory, before they are evicted (0 == no limit)
666      * @deprecated use {@link #setMaxEntriesLocalHeap(long)}
667      */

668     @Deprecated
669     public final void setMaxElementsInMemory(int maxElementsInMemory) {
670         setMaxEntriesLocalHeap(maxElementsInMemory);
671     }
672
673     /**
674      * Sets the maximum objects to be held in local heap memory (0 = no limit).
675      * <p/>
676      * This property can be modified dynamically while the cache is operating.
677      *
678      * @param maxEntriesInMemory The maximum number of elements in memory, before they are evicted (0 == no limit)
679      */

680     public final void setMaxEntriesLocalHeap(long maxEntriesInMemory) {
681         if (maxEntriesInMemory < 0) {
682             throw new InvalidConfigurationException("Number of entries on local heap cannot be negative");
683         }
684         if (maxEntriesInMemory > Integer.MAX_VALUE) {
685             throw new IllegalArgumentException("Values larger than Integer.MAX_VALUE are not currently supported.");
686         }
687
688         checkDynamicChange();
689         if (onHeapPoolUsage != null && onHeapPoolUsage != PoolUsage.None) {
690             throw new InvalidConfigurationException("MaxEntriesLocalHeap is not compatible with " +
691                                                     "MaxBytesLocalHeap set on cache");
692         }
693         int oldCapacity = maxEntriesLocalHeap == null ? 0 : maxEntriesLocalHeap;
694         int newCapacity = (int) maxEntriesInMemory;
695         this.maxEntriesLocalHeap = (int) maxEntriesInMemory;
696         fireMemoryCapacityChanged(oldCapacity, newCapacity);
697     }
698
699     /**
700      * Builder that sets the maximum objects to be held in memory (0 = no limit).
701      * <p/>
702      * This property can be modified dynamically while the cache is operating.
703      *
704      * @param maxElementsInMemory The maximum number of elements in memory, before they are evicted (0 == no limit)
705      * @return this configuration instance
706      * @deprecated use {@link #maxEntriesLocalHeap(int)}
707      */

708     @Deprecated
709     public final CacheConfiguration maxElementsInMemory(int maxElementsInMemory) {
710         setMaxElementsInMemory(maxElementsInMemory);
711         return this;
712     }
713
714     /**
715      * Builder that sets the maximum objects to be held in memory (0 = no limit).
716      * <p/>
717      * This property can be modified dynamically while the cache is operating.
718      *
719      * @param maxElementsInMemory The maximum number of elements in memory, before they are evicted (0 == no limit)
720      * @return this configuration instance
721      */

722     public final CacheConfiguration maxEntriesLocalHeap(int maxElementsInMemory) {
723         setMaxEntriesLocalHeap(maxElementsInMemory);
724         return this;
725     }
726
727     /**
728      * Sets the timeout for CacheLoader execution (0 = no timeout).
729      *
730      * @param cacheLoaderTimeoutMillis the timeout in milliseconds.
731      */

732     public final void setCacheLoaderTimeoutMillis(long cacheLoaderTimeoutMillis) {
733         checkDynamicChange();
734         this.cacheLoaderTimeoutMillis = cacheLoaderTimeoutMillis;
735     }
736
737     /**
738      * Builder that sets the timeout for CacheLoader execution (0 = no timeout).
739
740      * @param timeoutMillis the timeout in milliseconds.
741      * @return this configuration instance
742      */

743     public CacheConfiguration timeoutMillis(long timeoutMillis) {
744         setCacheLoaderTimeoutMillis(timeoutMillis);
745         return this;
746     }
747
748     /**
749      * Sets the eviction policy. An invalid argument will set it to LRU.
750      *
751      * @param memoryStoreEvictionPolicy a String representation of the policy. One of "LRU""LFU" or "FIFO".
752      */

753     public final void setMemoryStoreEvictionPolicy(String memoryStoreEvictionPolicy) {
754         assertArgumentNotNull("Cache memoryStoreEvictionPolicy", memoryStoreEvictionPolicy);
755         setMemoryStoreEvictionPolicyFromObject(MemoryStoreEvictionPolicy.fromString(memoryStoreEvictionPolicy));
756     }
757
758     /**
759      * Builder that sets the eviction policy. An invalid argument will set it to null.
760      *
761      * @param memoryStoreEvictionPolicy a String representation of the policy. One of "LRU""LFU" or "FIFO".
762      * @return this configuration instance
763      * @see #setMemoryStoreEvictionPolicy(String)
764      */

765     public final CacheConfiguration memoryStoreEvictionPolicy(String memoryStoreEvictionPolicy) {
766         setMemoryStoreEvictionPolicy(memoryStoreEvictionPolicy);
767         return this;
768     }
769
770     /**
771      * Sets the eviction policy. This method has a strange name to workaround a problem with XML parsing.
772      */

773     public final void setMemoryStoreEvictionPolicyFromObject(MemoryStoreEvictionPolicy memoryStoreEvictionPolicy) {
774         checkDynamicChange();
775         if (null == memoryStoreEvictionPolicy) {
776             this.memoryStoreEvictionPolicy = DEFAULT_MEMORY_STORE_EVICTION_POLICY;
777         } else {
778             this.memoryStoreEvictionPolicy = memoryStoreEvictionPolicy;
779         }
780     }
781
782     /**
783      * Builder which Sets the eviction policy. An invalid argument will set it to null.
784      *
785      * @return this configuration instance
786      * @see #setMemoryStoreEvictionPolicyFromObject(MemoryStoreEvictionPolicy)
787      */

788     public final CacheConfiguration memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy memoryStoreEvictionPolicy) {
789         setMemoryStoreEvictionPolicyFromObject(memoryStoreEvictionPolicy);
790         return this;
791     }
792
793     /**
794      * Sets whether the MemoryStore should be cleared when
795      * {@link net.sf.ehcache.Ehcache#flush flush()} is called on the cache - true by default.
796      *
797      * @param clearOnFlush true to clear on flush
798      */

799     public final void setClearOnFlush(boolean clearOnFlush) {
800         checkDynamicChange();
801         this.clearOnFlush = clearOnFlush;
802     }
803
804     /**
805      * Builder which sets whether the MemoryStore should be cleared when
806      * {@link net.sf.ehcache.Ehcache#flush flush()} is called on the cache - true by default.
807      *
808      * @param clearOnFlush true to clear on flush
809      * @return this configuration instance
810      * @see #setClearOnFlush(boolean)
811      */

812     public final CacheConfiguration clearOnFlush(boolean clearOnFlush) {
813         setClearOnFlush(clearOnFlush);
814         return this;
815     }
816
817     /**
818      * Sets whether elements are eternal. If eternal, timeouts are ignored and the element is never expired. False by default.
819      *
820      * @param eternal true for eternal
821      */

822     public final void setEternal(boolean eternal) {
823         checkDynamicChange();
824         isEternalValueConflictingWithTTIOrTTL(eternal, getTimeToLiveSeconds(), getTimeToIdleSeconds());
825         this.eternal = eternal;
826         if (eternal) {
827             setTimeToIdleSeconds(0);
828             setTimeToLiveSeconds(0);
829         }
830     }
831
832     private boolean isEternalValueConflictingWithTTIOrTTL(boolean newEternalValue, long newTTLValue, long newTTIValue) {
833         boolean conflicting = false;
834
835         if (newEternalValue && (newTTLValue != 0 || newTTIValue != 0)) {
836             conflicting = true;
837         }
838
839         if (conflicting && !conflictingEternalValuesWarningLogged) {
840             conflictingEternalValuesWarningLogged = true;
841             LOG.warn("Cache '" + getName() + "' is set to eternal but also has TTI/TTL set. "
842                     + " To avoid this warning, clean up the config " + "removing conflicting values of eternal,"
843                     + " TTI and TTL. Effective configuration for Cache '" + getName() + "' will be eternal='" + newEternalValue
844                     + "', timeToIdleSeconds='0', timeToLiveSeconds='0'.");
845         }
846         return conflicting;
847     }
848
849     /**
850      * Builder which sets whether elements are eternal. If eternal, timeouts are ignored and the element is never expired. False by default.
851      *
852      * @param eternal true for eternal
853      * @return this configuration instance
854      * @see #setEternal(boolean)
855      */

856     public final CacheConfiguration eternal(boolean eternal) {
857         setEternal(eternal);
858         return this;
859     }
860
861     /**
862      * Sets the time to idle for an element before it expires. Is only used if the element is not eternal. This can be overidden in
863      * {@link net.sf.ehcache.Element}
864      * <p/>
865      * This property can be modified dynamically while the cache is operating.
866      *
867      * @param timeToIdleSeconds the default amount of time to live for an element from its last accessed or modified date
868      */

869     public final void setTimeToIdleSeconds(long timeToIdleSeconds) {
870         checkDynamicChange();
871         if (!isEternalValueConflictingWithTTIOrTTL(eternal, 0, timeToIdleSeconds)) {
872             long oldTti = this.timeToIdleSeconds;
873             long newTti = timeToIdleSeconds;
874             this.timeToIdleSeconds = timeToIdleSeconds;
875             fireTtiChanged(oldTti, newTti);
876         }
877     }
878
879     /**
880      * Builder which sets the time to idle for an element before it expires. Is only used if the element is not eternal.
881      * This default can be overridden in {@link net.sf.ehcache.Element}
882      * <p/>
883      * This property can be modified dynamically while the cache is operating.
884      *
885      * @param timeToIdleSeconds the default amount of time to live for an element from its last accessed or modified date
886      * @return this configuration instance
887      * @see #setTimeToIdleSeconds(long)
888      */

889     public final CacheConfiguration timeToIdleSeconds(long timeToIdleSeconds) {
890         setTimeToIdleSeconds(timeToIdleSeconds);
891         return this;
892     }
893
894     /**
895      * Sets the time to idle for an element before it expires. Is only used if the element is not eternal.
896      * This default can be overridden in {@link net.sf.ehcache.Element}
897      * <p/>
898      * This property can be modified dynamically while the cache is operating.
899      *
900      * @param timeToLiveSeconds the default amount of time to live for an element from its creation date
901      */

902     public final void setTimeToLiveSeconds(long timeToLiveSeconds) {
903         checkDynamicChange();
904         if (!isEternalValueConflictingWithTTIOrTTL(eternal, timeToLiveSeconds, 0)) {
905             long oldTtl = this.timeToLiveSeconds;
906             long newTtl = timeToLiveSeconds;
907             this.timeToLiveSeconds = timeToLiveSeconds;
908             fireTtlChanged(oldTtl, newTtl);
909         }
910     }
911
912     /**
913      * Builder which sets the time to idle for an element before it expires. Is only used if the element is not eternal.
914      * This default can be overridden in {@link net.sf.ehcache.Element}
915      * <p/>
916      * This property can be modified dynamically while the cache is operating.
917      *
918      * @param timeToLiveSeconds the default amount of time to live for an element from its creation date
919      * @return this configuration instance
920      * @see #setTimeToLiveSeconds(long)
921      */

922     public final CacheConfiguration timeToLiveSeconds(long timeToLiveSeconds) {
923         setTimeToLiveSeconds(timeToLiveSeconds);
924         return this;
925     }
926
927     /**
928      * Sets whether elements can overflow to disk when the in-memory cache has reached the set limit.
929      *
930      * @param overflowToDisk whether to use the disk store
931      * @deprecated The {@code overflowToDisk} attribute has been replaced with {@link Strategy#LOCALTEMPSWAP}.
932      */

933     @Deprecated
934     public final void setOverflowToDisk(boolean overflowToDisk) {
935         checkDynamicChange();
936         if (persistenceConfiguration != null && Boolean.TRUE.equals(overflowToDisk)) {
937             throw new InvalidConfigurationException("Cannot use both <persistence ...> and overflowToDisk in a single cache configuration.");
938         }
939         this.overflowToDisk = overflowToDisk;
940         validateConfiguration();
941     }
942
943     /**
944      * Builder which sets whether elements can overflow to disk when the in-memory cache has reached the set limit.
945      *
946      * @param overflowToDisk whether to use the disk store
947      * @return this configuration instance
948      * @see #setOverflowToDisk(boolean)
949      * @deprecated The {@code overflowToDisk} attribute has been replaced with {@link Strategy#LOCALTEMPSWAP}.
950      */

951     @Deprecated
952     public final CacheConfiguration overflowToDisk(boolean overflowToDisk) {
953         setOverflowToDisk(overflowToDisk);
954         return this;
955     }
956
957     /**
958      * Sets whether the disk store persists between CacheManager instances. Note that this operates independently of {@link #overflowToDisk}.
959      *
960      * @param diskPersistent whether to persist the cache to disk between JVM restarts
961      * @deprecated The {@code diskPersistent} attribute has been replaced with {@link #persistence(PersistenceConfiguration)}.
962      */

963     @Deprecated
964     public final void setDiskPersistent(boolean diskPersistent) {
965         checkDynamicChange();
966         if (persistenceConfiguration != null) {
967             throw new InvalidConfigurationException("Cannot use both <persistence ...> and diskPersistent in a single cache configuration.");
968         }
969         this.diskPersistent = diskPersistent;
970         validateConfiguration();
971     }
972
973     /**
974      * Builder which sets whether the disk store persists between CacheManager instances. Note that this operates independently of {@link #overflowToDisk}.
975      *
976      * @param diskPersistent whether to persist the cache to disk between JVM restarts.
977      * @return this configuration instance
978      * @see #setDiskPersistent(boolean)
979      * @deprecated The {@code diskPersistent} attribute has been replaced with {@link #persistence(PersistenceConfiguration)}.
980      */

981     @Deprecated
982     public final CacheConfiguration diskPersistent(boolean diskPersistent) {
983         setDiskPersistent(diskPersistent);
984         return this;
985     }
986
987     /**
988      * Sets the disk spool size, which is used to buffer writes to the DiskStore.
989      * If not set it defaults to {@link #DEFAULT_SPOOL_BUFFER_SIZE}
990      *
991      * @param diskSpoolBufferSizeMB a positive number
992      */

993     public void setDiskSpoolBufferSizeMB(int diskSpoolBufferSizeMB) {
994         checkDynamicChange();
995         if (diskSpoolBufferSizeMB <= 0) {
996             this.diskSpoolBufferSizeMB = DEFAULT_SPOOL_BUFFER_SIZE;
997         } else {
998             this.diskSpoolBufferSizeMB = diskSpoolBufferSizeMB;
999         }
1000     }
1001
1002     /**
1003      * Builder which sets the disk spool size, which is used to buffer writes to the DiskStore.
1004      * If not set it defaults to {@link #DEFAULT_SPOOL_BUFFER_SIZE}
1005      *
1006      * @param diskSpoolBufferSizeMB a positive number
1007      * @return this configuration instance
1008      * @see #setDiskSpoolBufferSizeMB(int)
1009      */

1010     public final CacheConfiguration diskSpoolBufferSizeMB(int diskSpoolBufferSizeMB) {
1011         setDiskSpoolBufferSizeMB(diskSpoolBufferSizeMB);
1012         return this;
1013     }
1014
1015     /**
1016      * Sets the number of disk stripes. RandomAccessFiles used to access the data file. By default there
1017      * is one stripe.
1018      *
1019      * @param stripes number of stripes (rounded up to a power-of-2)
1020      */

1021     public void setDiskAccessStripes(int stripes) {
1022         checkDynamicChange();
1023         if (stripes <= 0) {
1024             this.diskAccessStripes = DEFAULT_DISK_ACCESS_STRIPES;
1025         } else {
1026             this.diskAccessStripes = stripes;
1027         }
1028     }
1029
1030     /**
1031      * Builder which sets the number of disk stripes. RandomAccessFiles used to access the data file. By default there
1032      * is one stripe.
1033      *
1034      * @return this configuration instance
1035      * @see #setDiskAccessStripes(int)
1036      */

1037     public final CacheConfiguration diskAccessStripes(int stripes) {
1038         setDiskAccessStripes(stripes);
1039         return this;
1040     }
1041
1042     /**
1043      * Sets the maximum number elements on Disk. 0 means unlimited.
1044      * <p/>
1045      * This property can be modified dynamically while the cache is operating.
1046      *
1047      * @param maxElementsOnDisk the maximum number of Elements to allow on the disk. 0 means unlimited.
1048      */

1049     public void setMaxElementsOnDisk(int maxElementsOnDisk) {
1050         if (onDiskPoolUsage != null && onDiskPoolUsage != PoolUsage.None) {
1051             throw new InvalidConfigurationException("MaxEntriesLocalDisk is not compatible with " +
1052                                                     "MaxBytesLocalDisk set on cache");
1053         }
1054         checkDynamicChange();
1055         int oldCapacity = this.maxElementsOnDisk;
1056         this.maxElementsOnDisk = maxElementsOnDisk;
1057         fireDiskCapacityChanged(oldCapacity, this.maxElementsOnDisk);
1058     }
1059
1060     /**
1061      * Sets the maximum number elements on Disk. 0 means unlimited.
1062      * <p/>
1063      * This property can be modified dynamically while the cache is operating.
1064      *
1065      * @param maxEntriesOnDisk the maximum number of Elements to allow on the disk. 0 means unlimited.
1066      */

1067     public void setMaxEntriesLocalDisk(long maxEntriesOnDisk) {
1068         if (maxEntriesOnDisk < 0) {
1069             throw new InvalidConfigurationException("Number of entries on disk cannot be negative");
1070         }
1071         if (maxEntriesOnDisk > Integer.MAX_VALUE) {
1072             throw new IllegalArgumentException("Values greater than Integer.MAX_VALUE are not currently supported.");
1073         }
1074         // This check against pool usage is only there to see if this configuration backs up a running cache
1075         if (onDiskPoolUsage != null && isTerracottaClustered()) {
1076             throw new IllegalStateException("Can't use local disks with Terracotta clustered caches!");
1077         }
1078         maxEntriesLocalDiskExplicitlySet = true;
1079         setMaxElementsOnDisk((int)maxEntriesOnDisk);
1080     }
1081
1082     /**
1083      * Builder which sets the maximum number elements on Disk. 0 means unlimited.
1084      * <p/>
1085      * This property can be modified dynamically while the cache is operating.
1086      *
1087      * @param maxElementsOnDisk the maximum number of Elements to allow on the disk. 0 means unlimited.
1088      * @return this configuration instance
1089      * @see #setMaxElementsOnDisk(int)
1090      */

1091     public final CacheConfiguration maxElementsOnDisk(int maxElementsOnDisk) {
1092         setMaxElementsOnDisk(maxElementsOnDisk);
1093         return this;
1094     }
1095
1096     /**
1097      * Builder which sets the maximum number elements on Disk. 0 means unlimited.
1098      * <p/>
1099      * This property can be modified dynamically while the cache is operating.
1100      *
1101      * @param maxElementsOnDisk the maximum number of Elements to allow on the disk. 0 means unlimited.
1102      * @return this configuration instance
1103      * @see #setMaxElementsOnDisk(int)
1104      */

1105     public final CacheConfiguration maxEntriesLocalDisk(int maxElementsOnDisk) {
1106         setMaxEntriesLocalDisk(maxElementsOnDisk);
1107         return this;
1108     }
1109
1110     /**
1111      * Sets the interval in seconds between runs of the disk expiry thread.
1112      * <p/>
1113      * 2 minutes is the default.
1114      * This is not the same thing as time to live or time to idle. When the thread runs it checks
1115      * these things. So this value is how often we check for expiry.
1116      */

1117     public final void setDiskExpiryThreadIntervalSeconds(long diskExpiryThreadIntervalSeconds) {
1118         checkDynamicChange();
1119         if (diskExpiryThreadIntervalSeconds <= 0) {
1120             this.diskExpiryThreadIntervalSeconds = DEFAULT_EXPIRY_THREAD_INTERVAL_SECONDS;
1121         } else {
1122             this.diskExpiryThreadIntervalSeconds = diskExpiryThreadIntervalSeconds;
1123         }
1124     }
1125
1126     /**
1127      * Builder which sets the interval in seconds between runs of the disk expiry thread.
1128      * <p/>
1129      * 2 minutes is the default.
1130      * This is not the same thing as time to live or time to idle. When the thread runs it checks
1131      * these things. So this value is how often we check for expiry.
1132      *
1133      * @return this configuration instance
1134      * @see #setDiskExpiryThreadIntervalSeconds(long)
1135      */

1136     public final CacheConfiguration diskExpiryThreadIntervalSeconds(long diskExpiryThreadIntervalSeconds) {
1137         setDiskExpiryThreadIntervalSeconds(diskExpiryThreadIntervalSeconds);
1138         return this;
1139     }
1140
1141     /**
1142      * Freeze this configuration. Any subsequent changes will throw a CacheException
1143      */

1144     public void freezeConfiguration() {
1145         frozen = true;
1146         if (searchable != null) {
1147             searchable.freezeConfiguration();
1148         }
1149     }
1150
1151     /**
1152      * @return true is this configuration is frozen - it cannot be changed dynamically.
1153      */

1154     public boolean isFrozen() {
1155         return frozen;
1156     }
1157
1158     /**
1159      * Getter to the CopyStrategy set in the config (really? how?).
1160      * This will always return the same unique instance per cache
1161      *
1162      * @return the {@link ReadWriteCopyStrategy} for instance for this cache
1163      */

1164     public ReadWriteCopyStrategy<Element> getCopyStrategy() {
1165         // todo really make this pluggable through config!
1166         return copyStrategyConfiguration.getCopyStrategyInstance();
1167     }
1168
1169     /**
1170      * Whether the Cache should copy elements it returns
1171      *
1172      * @param copyOnRead trueif copyOnRead
1173      */

1174     public CacheConfiguration copyOnRead(boolean copyOnRead) {
1175         this.setCopyOnRead(copyOnRead);
1176         return this;
1177     }
1178
1179     /**
1180      * Whether the Cache should copy elements it returns
1181      *
1182      * @return true, is copyOnRead
1183      */

1184     public boolean isCopyOnRead() {
1185         validateTransactionalSettings();
1186         return copyOnRead;
1187     }
1188
1189     /**
1190      * Whether the Cache should copy elements it returns
1191      *
1192      * @param copyOnRead trueif copyOnRead
1193      */

1194     public void setCopyOnRead(final boolean copyOnRead) {
1195         this.copyOnRead = copyOnRead;
1196     }
1197
1198     /**
1199      * Whether the Cache should copy elements it gets
1200      *
1201      * @param copyOnWrite trueif copyOnWrite
1202      */

1203     public CacheConfiguration copyOnWrite(boolean copyOnWrite) {
1204         this.copyOnWrite = copyOnWrite;
1205         return this;
1206     }
1207
1208     /**
1209      * Whether the Cache should copy elements it gets
1210      *
1211      * @return trueif copyOnWrite
1212      */

1213     public boolean isCopyOnWrite() {
1214         validateTransactionalSettings();
1215         return copyOnWrite;
1216     }
1217
1218     /**
1219      * Whether the Cache should copy elements it gets
1220      *
1221      * @param copyOnWrite trueif copyOnWrite
1222      */

1223     public void setCopyOnWrite(final boolean copyOnWrite) {
1224         this.copyOnWrite = copyOnWrite;
1225     }
1226
1227     /**
1228      * Sets the CopyStrategyConfiguration for this cache
1229      *
1230      * @param copyStrategyConfiguration the CopyStrategy Configuration
1231      */

1232     public void addCopyStrategy(CopyStrategyConfiguration copyStrategyConfiguration) {
1233         this.copyStrategyConfiguration = copyStrategyConfiguration;
1234     }
1235
1236     /**
1237      * Sets the ElementValueComparatorConfiguration for this cache
1238      *
1239      * @param elementValueComparatorConfiguration the ElementComparator Configuration
1240      */

1241     public void addElementValueComparator(ElementValueComparatorConfiguration elementValueComparatorConfiguration) {
1242         this.elementValueComparatorConfiguration = elementValueComparatorConfiguration;
1243     }
1244
1245     /**
1246      * Add configuration to make this cache searchable
1247      *
1248      * @param searchable search config to add
1249      */

1250     public final void addSearchable(Searchable searchable) {
1251         checkDynamicChange();
1252         this.searchable = searchable;
1253     }
1254
1255     /**
1256      * The maximum amount of bytes the cache should occupy on heap
1257      * @return value in bytes, 0 if none set
1258      */

1259     public long getMaxBytesLocalHeap() {
1260         return maxBytesLocalHeap == null ? DEFAULT_MAX_BYTES_ON_HEAP : maxBytesLocalHeap;
1261     }
1262
1263     /**
1264      * Setter for maxBytesLocalHeap as a String. Value can have a one char unit suffix or be a percentage (ending in %)
1265      * @param maxBytesHeap String representation of the size, can be relative (in %)
1266      */

1267     public void setMaxBytesLocalHeap(final String maxBytesHeap) {
1268         assertArgumentNotNull("Cache maxBytesLocalHeap", maxBytesHeap);
1269         if (isPercentage(maxBytesHeap)) {
1270             maxBytesLocalHeapPercentage = parsePercentage(maxBytesHeap);
1271         } else {
1272             setMaxBytesLocalHeap(MemoryUnit.parseSizeInBytes(maxBytesHeap));
1273         }
1274         maxBytesLocalHeapInput = maxBytesHeap;
1275     }
1276
1277     /**
1278      * Setter for maxBytesLocalHeap in bytes
1279      * @param maxBytesHeap max bytes in heap in bytes
1280      */

1281     public void setMaxBytesLocalHeap(final Long maxBytesHeap) {
1282         if (onHeapPoolUsage != null && getMaxEntriesLocalHeap() > 0) {
1283             throw new InvalidConfigurationException("MaxEntriesLocalHeap is not compatible with " +
1284                                                     "MaxBytesLocalHeap set on cache");
1285         }
1286         if (onHeapPoolUsage != null && onHeapPoolUsage != PoolUsage.Cache) {
1287             throw new IllegalStateException("A Cache can't switch memory pool!");
1288         }
1289         verifyGreaterThanZero(maxBytesHeap, "maxBytesLocalHeap");
1290         Long oldValue = this.maxBytesLocalHeap;
1291         this.maxBytesLocalHeap = maxBytesHeap;
1292         fireMaxBytesOnLocalHeapChanged(oldValue, maxBytesHeap);
1293     }
1294
1295     private void fireMaxBytesOnLocalHeapChanged(final Long oldValue, final Long newValue) {
1296         if ((oldValue != null && !oldValue.equals(newValue)) || (newValue != null && !newValue.equals(oldValue))) {
1297             for (CacheConfigurationListener listener : listeners) {
1298                 listener.maxBytesLocalHeapChanged(oldValue != null ? oldValue : 0, newValue);
1299             }
1300         }
1301     }
1302
1303     private void fireMaxBytesOnLocalDiskChanged(final Long oldValue, final Long newValue) {
1304         if ((oldValue != null && !oldValue.equals(newValue)) || (newValue != null && !newValue.equals(oldValue))) {
1305             for (CacheConfigurationListener listener : listeners) {
1306                 listener.maxBytesLocalDiskChanged(oldValue != null ? oldValue : 0, newValue);
1307             }
1308         }
1309     }
1310
1311     private void fireDynamicAttributesExtractorAdded(DynamicAttributesExtractor oldValue, DynamicAttributesExtractor newValue) {
1312         if (oldValue != newValue) {
1313             for (DynamicSearchListener lsnr : dynamicSearchListeners) {
1314                 lsnr.extractorChanged(oldValue, newValue);
1315             }
1316         }
1317     }
1318
1319     /**
1320      * Sets the maxOnHeap size
1321      * @param amount the amount of unit
1322      * @param memoryUnit the actual unit
1323      * @return this
1324      */

1325
1326     public CacheConfiguration maxBytesLocalHeap(final long amount, final MemoryUnit memoryUnit) {
1327         setMaxBytesLocalHeap(memoryUnit.toBytes(amount));
1328         return this;
1329     }
1330
1331     /**
1332      * The maximum amount of bytes the cache should occupy off heap
1333      * @return value in bytes, 0 if none set
1334      */

1335     public long getMaxBytesLocalOffHeap() {
1336         return maxBytesLocalOffHeap == null ? DEFAULT_MAX_BYTES_OFF_HEAP : maxBytesLocalOffHeap;
1337     }
1338
1339     /**
1340      * The string form of the maximum amount of bytes the cache should occupy off heap
1341      * @return value as string in bytes
1342      */

1343     public String getMaxBytesLocalOffHeapAsString() {
1344         return maxBytesLocalOffHeapInput != null ? maxBytesLocalOffHeapInput : Long.toString(getMaxBytesLocalOffHeap());
1345     }
1346
1347     /**
1348      * Setter for maximum bytes off heap as a String. Value can have a one char unit suffix or be a percentage (ending in %)
1349      * @param maxBytesOffHeap String representation of the size, can be relative (in %)
1350      */

1351     public void setMaxBytesLocalOffHeap(final String maxBytesOffHeap) {
1352         assertArgumentNotNull("Cache maxBytesLocalOffHeap", maxBytesOffHeap);
1353         if (isPercentage(maxBytesOffHeap)) {
1354             maxBytesLocalOffHeapPercentage = parsePercentage(maxBytesOffHeap);
1355         } else {
1356             setMaxBytesLocalOffHeap(MemoryUnit.parseSizeInBytes(maxBytesOffHeap));
1357         }
1358         maxBytesLocalOffHeapInput = maxBytesOffHeap;
1359         maxBytesLocalOffHeapExplicitlySet = true;
1360     }
1361
1362     /**
1363      * Getter for maximum bytes off heap expressed as a percentage
1364      * @return percentage (between 0 and 100)
1365      */

1366     public Integer getMaxBytesLocalOffHeapPercentage() {
1367         return maxBytesLocalOffHeapPercentage;
1368     }
1369
1370     /**
1371      * Getter for maximum bytes on heap expressed as a percentage
1372      * @return percentage (between 0 and 100)
1373      */

1374     public Integer getMaxBytesLocalHeapPercentage() {
1375         return maxBytesLocalHeapPercentage;
1376     }
1377
1378     /**
1379      * The string form of the maximum amount of bytes the cache should occupy on heap
1380      * @return value as string in bytes
1381      */

1382     public String getMaxBytesLocalHeapAsString() {
1383         return maxBytesLocalHeapInput != null ? maxBytesLocalHeapInput : Long.toString(getMaxBytesLocalHeap());
1384     }
1385
1386     /**
1387      * Getter for maximum bytes on disk expressed as a percentage
1388      * @return percentage (between 0 and 100)
1389      */

1390     public Integer getMaxBytesLocalDiskPercentage() {
1391         return maxBytesLocalDiskPercentage;
1392     }
1393
1394     private int parsePercentage(final String stringValue) {
1395         String trimmed = stringValue.trim();
1396         int percentage = Integer.parseInt(trimmed.substring(0, trimmed.length() - 1));
1397         if (percentage > HUNDRED_PERCENT || percentage < 0) {
1398             throw new IllegalArgumentException("Percentage need values need to be between 0 and 100 inclusive, but got : " + percentage);
1399         }
1400         return percentage;
1401     }
1402
1403     private boolean isPercentage(final String stringValue) {
1404         String trimmed = stringValue.trim();
1405         return trimmed.charAt(trimmed.length() - 1) == '%';
1406     }
1407
1408     /**
1409      * Sets the maximum amount of bytes the cache being configured will use on the OffHeap tier
1410      * @param maxBytesOffHeap max bytes on disk in bytes
1411      */

1412     public void setMaxBytesLocalOffHeap(final Long maxBytesOffHeap) {
1413         if (offHeapPoolUsage != null) {
1414             throw new IllegalStateException("OffHeap can't be set dynamically!");
1415         }
1416         verifyGreaterThanZero(maxBytesOffHeap, "maxBytesLocalOffHeap");
1417         this.maxBytesLocalOffHeapExplicitlySet = true;
1418         this.maxBytesLocalOffHeap = maxBytesOffHeap;
1419     }
1420
1421     /**
1422      * Sets the maxOffHeap tier size
1423      * @param amount the amount of unit
1424      * @param memoryUnit the actual unit
1425      * @return this
1426      */

1427     public CacheConfiguration maxBytesLocalOffHeap(final long amount, final MemoryUnit memoryUnit) {
1428         setMaxBytesLocalOffHeap(memoryUnit.toBytes(amount));
1429         return this;
1430     }
1431
1432     /**
1433      * The maximum amount of bytes the cache should occupy on disk
1434      * @return value in bytes, 0 if none set
1435      */

1436     public long getMaxBytesLocalDisk() {
1437         return maxBytesLocalDisk == null ? DEFAULT_MAX_BYTES_ON_DISK : maxBytesLocalDisk;
1438     }
1439
1440     /**
1441      * The string form of the maximum amount of bytes the cache should occupy on disk
1442      * @return value as string in bytes
1443      */

1444     public String getMaxBytesLocalDiskAsString() {
1445         return maxBytesLocalDiskInput != null ? maxBytesLocalDiskInput : Long.toString(getMaxBytesLocalDisk());
1446     }
1447
1448     /**
1449      * Setter for maxBytesOnDisk as a String. Value can have a one char unit suffix or be a percentage (ending in %)
1450      * @param maxBytesDisk String representation of the size, can be relative (in %)
1451      */

1452     public void setMaxBytesLocalDisk(final String maxBytesDisk) {
1453         assertArgumentNotNull("Cache maxBytesLocalDisk", maxBytesDisk);
1454         if (isPercentage(maxBytesDisk)) {
1455             maxBytesLocalDiskPercentage = parsePercentage(maxBytesDisk);
1456         } else {
1457             setMaxBytesLocalDisk(MemoryUnit.parseSizeInBytes(maxBytesDisk));
1458         }
1459         maxBytesLocalDiskExplicitlySet = true;
1460         maxBytesLocalDiskInput = maxBytesDisk;
1461     }
1462
1463     /**
1464      * Sets the maximum amount of bytes the cache being configured will use on the OnDisk tier
1465      * @param maxBytesDisk max bytes on disk in bytes
1466      */

1467     public void setMaxBytesLocalDisk(final Long maxBytesDisk) {
1468         if (onDiskPoolUsage != null && getMaxEntriesLocalDisk() > 0) {
1469             throw new InvalidConfigurationException("MaxEntriesLocalDisk is not compatible with " +
1470                                                     "MaxBytesLocalDisk set on cache");
1471         }
1472         if (onDiskPoolUsage != null && onDiskPoolUsage != PoolUsage.Cache) {
1473             throw new IllegalStateException("A Cache can't switch disk pool!");
1474         }
1475         verifyGreaterThanZero(maxBytesDisk, "maxBytesLocalDisk");
1476         maxBytesLocalDiskExplicitlySet = true;
1477         Long oldValue = this.maxBytesLocalDisk;
1478         this.maxBytesLocalDisk = maxBytesDisk;
1479         fireMaxBytesOnLocalDiskChanged(oldValue, maxBytesDisk);
1480     }
1481
1482     /**
1483      * Sets the maxOnDisk size
1484      * @param amount the amount of unit
1485      * @param memoryUnit the actual unit
1486      * @return this
1487      */

1488     public CacheConfiguration maxBytesLocalDisk(final long amount, final MemoryUnit memoryUnit) {
1489         setMaxBytesLocalDisk(memoryUnit.toBytes(amount));
1490         return this;
1491     }
1492
1493     /**
1494      * Sets dynamic search attributes extractor
1495      * @param extractor extractor to use
1496      */

1497     public void setDynamicAttributesExtractor(DynamicAttributesExtractor extractor) {
1498         if (searchable == null || !searchable.isDynamicIndexingAllowed()) {
1499             throw new IllegalArgumentException("Dynamic search attribute extraction not supported");
1500         }
1501         if (extractor == null && this.flexIndexer != null) {
1502             throw new IllegalArgumentException("Dynamic search attributes extractor cannot be set to null by user");
1503         }
1504         DynamicAttributesExtractor old = this.flexIndexer;
1505         this.flexIndexer = extractor;
1506         fireDynamicAttributesExtractorAdded(old, this.flexIndexer);
1507     }
1508
1509     /**
1510      * Sets dynamic search attributes extractor
1511      * @param extractor extractor to use
1512      * @return this
1513      */

1514     public CacheConfiguration dynamicAttributeExtractor(DynamicAttributesExtractor extractor) {
1515         setDynamicAttributesExtractor(extractor);
1516         return this;
1517     }
1518
1519     private void verifyGreaterThanZero(final Long maxBytesOnHeap, final String field) {
1520         if (maxBytesOnHeap != null && maxBytesOnHeap < 1) {
1521             throw new IllegalArgumentException(field + " has to be larger than 0");
1522         }
1523     }
1524
1525     /**
1526      * Returns the copyStrategyConfiguration
1527      *
1528      * @return the copyStrategyConfiguration
1529      */

1530     public CopyStrategyConfiguration getCopyStrategyConfiguration() {
1531         return this.copyStrategyConfiguration;
1532     }
1533
1534     /**
1535      * Returns the elementComparatorConfiguration
1536      *
1537      * @return the elementComparatorConfiguration
1538      */

1539     public ElementValueComparatorConfiguration getElementValueComparatorConfiguration() {
1540         return elementValueComparatorConfiguration;
1541     }
1542
1543     /**
1544      * Checks whether the user explicitly set the maxBytesOnHeapPercentage
1545      * @return true if set by user, false otherwise
1546      * @see #setMaxBytesLocalHeap(String)
1547      */

1548     public boolean isMaxBytesLocalHeapPercentageSet() {
1549         return maxBytesLocalHeapPercentage != null;
1550     }
1551
1552     /**
1553      * Checks whether the user explicitly set the maxBytesOffHeapPercentage
1554      * @return true if set by user, false otherwise
1555      * @see #setMaxBytesLocalOffHeap(String)
1556      */

1557     public boolean isMaxBytesLocalOffHeapPercentageSet() {
1558         return maxBytesLocalOffHeapPercentage != null;
1559     }
1560
1561     /**
1562      * Checks whether the user explicitly set the maxBytesOnDiskPercentage
1563      * @return true if set by user, false otherwise
1564      * @see #setMaxBytesLocalDisk(String)
1565      */

1566     public boolean isMaxBytesLocalDiskPercentageSet() {
1567         return maxBytesLocalDiskPercentage != null;
1568     }
1569
1570     /**
1571      * Sets up the CacheConfiguration for runtime consumption, also registers this cache configuration with the cache manager's configuration
1572      * @param cacheManager The CacheManager as part of which the cache is being setup
1573      */

1574     public void setupFor(final CacheManager cacheManager) {
1575         setupFor(cacheManager, true);
1576     }
1577
1578     /**
1579      * Sets up the CacheConfiguration for runtime consumption
1580      * @param cacheManager The CacheManager as part of which the cache is being setup
1581      * @param register true to register this cache configuration with the cache manager.
1582      */

1583     public void setupFor(final CacheManager cacheManager, final boolean register) {
1584         final Collection<ConfigError> errors = validate(cacheManager.getConfiguration());
1585         configCachePools(cacheManager.getConfiguration());
1586         errors.addAll(verifyPoolAllocationsBeforeAddingTo(cacheManager,
1587             cacheManager.getConfiguration().getMaxBytesLocalHeap(),
1588             cacheManager.getConfiguration().getMaxBytesLocalOffHeap(),
1589             cacheManager.getConfiguration().getMaxBytesLocalDisk()));
1590         if (!errors.isEmpty()) {
1591             throw new InvalidConfigurationException(errors);
1592         }
1593
1594
1595         if (!isTerracottaClustered()) {
1596             updateCacheManagerPoolSizes(cacheManager);
1597         }
1598
1599         if (register) {
1600             registerCacheConfiguration(cacheManager);
1601         }
1602         if (cacheManager.getConfiguration().isMaxBytesLocalHeapSet() || cacheManager.getConfiguration().isMaxBytesLocalDiskSet()) {
1603             addConfigurationListener(new AbstractCacheConfigurationListener() {
1604                 @Override
1605                 public void maxBytesLocalHeapChanged(final long oldValue, final long newValue) {
1606                     if (getMaxBytesLocalHeap() > 0
1607                        && cacheManager.getConfiguration().getCacheConfigurations().keySet().contains(getName())
1608                        && cacheManager.getConfiguration().isMaxBytesLocalHeapSet()) {
1609                         long previous = cacheManager.getOnHeapPool().getMaxSize();
1610                         cacheManager.getOnHeapPool().setMaxSize(previous + oldValue - newValue);
1611                     }
1612                 }
1613
1614                 @Override
1615                 public void maxBytesLocalDiskChanged(final long oldValue, final long newValue) {
1616                     if (getMaxBytesLocalDisk() > 0
1617                        && cacheManager.getConfiguration().getCacheConfigurations().keySet().contains(getName())
1618                        && cacheManager.getConfiguration().isMaxBytesLocalDiskSet()) {
1619                         long previous = cacheManager.getOnDiskPool().getMaxSize();
1620                         cacheManager.getOnDiskPool().setMaxSize(previous + oldValue - newValue);
1621                     }
1622                 }
1623             });
1624         }
1625
1626         consolidatePersistenceSettings(cacheManager);
1627
1628         if (overflowToOffHeap == null && (cacheManager.getConfiguration().isMaxBytesLocalOffHeapSet() || getMaxBytesLocalOffHeap() > 0)) {
1629             overflowToOffHeap = true;
1630         }
1631         if ((persistenceConfiguration != null && Strategy.LOCALTEMPSWAP.equals(persistenceConfiguration.getStrategy()))) {
1632             overflowToDisk = true;
1633         }
1634         if (overflowToDisk == null && cacheManager.getConfiguration().isMaxBytesLocalDiskSet() || getMaxBytesLocalDisk() > 0) {
1635             if (persistenceConfiguration != null && Strategy.LOCALRESTARTABLE.equals(persistenceConfiguration.getStrategy())) {
1636                 throw new InvalidConfigurationException("Cannot use localRestartable persistence and disk overflow in the same cache");
1637             } else {
1638                 overflowToDisk = true;
1639             }
1640         }
1641         warnMaxEntriesLocalHeap(register, cacheManager);
1642         warnMaxEntriesForOverflowToOffHeap(register);
1643         warnSizeOfPolicyConfiguration();
1644         freezePoolUsages(cacheManager);
1645     }
1646
1647     private void consolidatePersistenceSettings(CacheManager manager) {
1648         if (persistenceConfiguration == null) {
1649             if (diskPersistent == Boolean.TRUE) {
1650                 persistenceConfiguration = new PersistenceConfiguration().strategy(Strategy.LOCALTEMPSWAP);
1651             }
1652         } else {
1653             switch (persistenceConfiguration.getStrategy()) {
1654                 case DISTRIBUTED:
1655                 case NONE:
1656                     diskPersistent = Boolean.FALSE;
1657                     break;
1658                 case LOCALTEMPSWAP:
1659                     if (diskPersistent == null) {
1660                         diskPersistent = Boolean.FALSE;
1661                     }
1662                     break;
1663                 case LOCALRESTARTABLE:
1664                     diskPersistent = Boolean.TRUE;
1665                     break;
1666                 default:
1667                     break;
1668             }
1669         }
1670
1671         if (persistenceConfiguration != null && persistenceConfiguration.getSynchronousWrites()) {
1672             switch (persistenceConfiguration.getStrategy()) {
1673                 case NONE:
1674                 case LOCALTEMPSWAP:
1675                     throw new InvalidConfigurationException("Persistence: synchronousWrites=\"true\" is not supported "
1676                             + "with strategy \"localTempSwap\" or \"none\"");
1677                 default:
1678                     break;
1679             }
1680         }
1681     }
1682
1683     private void warnMaxEntriesForOverflowToOffHeap(final boolean register) {
1684         if (overflowToOffHeap != null && overflowToOffHeap && register) {
1685             if (getMaxEntriesLocalHeap() > 0 && getMaxEntriesLocalHeap() < MINIMUM_RECOMMENDED_IN_MEMORY) {
1686                 LOG.warn("The " + getName() + " cache is configured for off-heap and has a maxEntriesLocalHeap/maxElementsInMemory of "
1687                         + getMaxEntriesLocalHeap() + ".  It is recommended to set maxEntriesLocalHeap/maxElementsInMemory to at least "
1688                         + MINIMUM_RECOMMENDED_IN_MEMORY + " elements when using an off-heap store, otherwise performance "
1689                         + "will be seriously degraded.");
1690               }
1691         }
1692     }
1693
1694     private void warnMaxEntriesLocalHeap(final boolean register, CacheManager cacheManager) {
1695         if (getMaxEntriesLocalHeap() == 0 && register) {
1696             if (getMaxBytesLocalHeap() == 0 && (!cacheManager.getConfiguration().isMaxBytesLocalHeapSet())) {
1697             LOG.warn("Cache: " + getName() +
1698                     " has a maxElementsInMemory of 0. This might lead to performance degradation or OutOfMemoryError at Terracotta client." +
1699                     "From Ehcache 2.0 onwards this has been changed to mean a store" +
1700                     " with no capacity limit. Set it to 1 if you want" +
1701                     " no elements cached in memory");
1702             }
1703         }
1704     }
1705
1706     private void warnSizeOfPolicyConfiguration() {
1707         if (isTerracottaClustered() && getSizeOfPolicyConfiguration() != null) {
1708             LOG.warn("Terracotta clustered cache: " + getName() + " has a sizeOf policy configuration specificed. " +
1709                     "SizeOfPolicyConfiguration is unsupported for Terracotta clustered caches.");
1710         }
1711     }
1712
1713     private void freezePoolUsages(final CacheManager cacheManager) {
1714         if (getMaxBytesLocalHeap() > 0) {
1715             onHeapPoolUsage = CacheConfiguration.PoolUsage.Cache;
1716         } else if (cacheManager.getConfiguration().isMaxBytesLocalHeapSet()) {
1717             onHeapPoolUsage = CacheConfiguration.PoolUsage.CacheManager;
1718         } else {
1719             onHeapPoolUsage = CacheConfiguration.PoolUsage.None;
1720         }
1721
1722         if (getMaxBytesLocalOffHeap() > 0) {
1723             offHeapPoolUsage = CacheConfiguration.PoolUsage.Cache;
1724         } else if (cacheManager.getConfiguration().isMaxBytesLocalOffHeapSet()) {
1725             offHeapPoolUsage = CacheConfiguration.PoolUsage.CacheManager;
1726         } else {
1727             offHeapPoolUsage = CacheConfiguration.PoolUsage.None;
1728         }
1729
1730         if (isTerracottaClustered()) {
1731             onDiskPoolUsage = CacheConfiguration.PoolUsage.None;
1732         } else {
1733             if (getMaxBytesLocalDisk() > 0) {
1734                 onDiskPoolUsage = CacheConfiguration.PoolUsage.Cache;
1735             } else if (cacheManager.getConfiguration().isMaxBytesLocalDiskSet()) {
1736                 onDiskPoolUsage = CacheConfiguration.PoolUsage.CacheManager;
1737             } else {
1738                 onDiskPoolUsage = CacheConfiguration.PoolUsage.None;
1739             }
1740         }
1741     }
1742
1743     private void registerCacheConfiguration(final CacheManager cacheManager) {
1744         Map<String, CacheConfiguration> configMap = cacheManager.getConfiguration().getCacheConfigurations();
1745         if (!configMap.containsKey(getName())) {
1746             cacheManager.getConfiguration().addCache(thisfalse);
1747         }
1748     }
1749
1750     private void updateCacheManagerPoolSizes(final CacheManager cacheManager) {
1751         if (cacheManager.getOnHeapPool() != null) {
1752             cacheManager.getOnHeapPool().setMaxSize(cacheManager.getOnHeapPool().getMaxSize() - getMaxBytesLocalHeap());
1753         }
1754         if (cacheManager.getOnDiskPool() != null) {
1755             cacheManager.getOnDiskPool().setMaxSize(cacheManager.getOnDiskPool().getMaxSize() - getMaxBytesLocalDisk());
1756         }
1757     }
1758
1759     /**
1760      * Will verify that we don't overallocate pools
1761      * @param cacheManager The cacheManager that will manage the cache
1762      * @param managerMaxBytesLocalHeap bytes for local heap
1763      * @param managerMaxBytesLocalOffHeap bytes for local offheap
1764      * @param managerMaxBytesLocalDisk bytes for local disk
1765      * @return a list with potential errors
1766      */

1767     List<ConfigError> verifyPoolAllocationsBeforeAddingTo(CacheManager cacheManager,
1768                                                      long managerMaxBytesLocalHeap,
1769                                                      long managerMaxBytesLocalOffHeap,
1770                                                      long managerMaxBytesLocalDisk) {
1771         final List<ConfigError> configErrors = new ArrayList<ConfigError>();
1772
1773         long totalOnHeapAssignedMemory  = 0;
1774         long totalOffHeapAssignedMemory = 0;
1775         long totalOnDiskAssignedMemory  = 0;
1776
1777         boolean isUpdate = false;
1778         for (Cache cache : getAllActiveCaches(cacheManager)) {
1779             isUpdate = cache.getName().equals(getName()) || isUpdate;
1780             final CacheConfiguration config = cache.getCacheConfiguration();
1781             totalOnHeapAssignedMemory += config.getMaxBytesLocalHeap();
1782             totalOffHeapAssignedMemory += config.getMaxBytesLocalOffHeap();
1783             totalOnDiskAssignedMemory += config.getMaxBytesLocalDisk();
1784         }
1785
1786         if (!isUpdate) {
1787             totalOnHeapAssignedMemory += getMaxBytesLocalHeap();
1788             totalOffHeapAssignedMemory += getMaxBytesLocalOffHeap();
1789             totalOnDiskAssignedMemory += getMaxBytesLocalDisk();
1790         }
1791
1792         verifyLocalHeap(managerMaxBytesLocalHeap, configErrors, totalOnHeapAssignedMemory);
1793         verifyLocalOffHeap(managerMaxBytesLocalOffHeap, configErrors, totalOffHeapAssignedMemory);
1794         verifyLocalDisk(managerMaxBytesLocalDisk, configErrors, totalOnDiskAssignedMemory);
1795
1796         if (managerMaxBytesLocalHeap > 0 && managerMaxBytesLocalHeap - totalOnHeapAssignedMemory == 0) {
1797             LOG.warn("All the onHeap memory has been assigned, there is none left for dynamically added caches");
1798         }
1799
1800         if (Runtime.getRuntime().maxMemory() - totalOnHeapAssignedMemory < 0) {
1801             // todo this could be a nicer message (with actual values)
1802             configErrors.add(new ConfigError("You've assigned more memory to the on-heap than the VM can sustain, " +
1803                                             "please adjust your -Xmx setting accordingly"));
1804         }
1805
1806         if (totalOnHeapAssignedMemory / (float) Runtime.getRuntime().maxMemory() > CacheManager.ON_HEAP_THRESHOLD) {
1807             LOG.warn("You've assigned over 80% of your VM's heap to be used by the cache!");
1808         }
1809
1810         return configErrors;
1811     }
1812
1813     private void verifyLocalDisk(final long managerMaxBytesLocalDisk,
1814                                  final List<ConfigError> configErrors, final long totalOnDiskAssignedMemory) {
1815         if ((isMaxBytesLocalDiskPercentageSet() || getMaxBytesLocalDisk() > 0)
1816             && managerMaxBytesLocalDisk > 0 && managerMaxBytesLocalDisk - totalOnDiskAssignedMemory < 0) {
1817             configErrors.add(new ConfigError("Cache '" + getName()
1818                                                     + "' over-allocates CacheManager's localOnDisk limit!"));
1819         }
1820     }
1821
1822     private void verifyLocalOffHeap(final long managerMaxBytesLocalOffHeap,
1823                                     final List<ConfigError> configErrors, final long totalOffHeapAssignedMemory) {
1824         if ((isMaxBytesLocalOffHeapPercentageSet() || getMaxBytesLocalOffHeap() > 0)
1825             && managerMaxBytesLocalOffHeap > 0 && managerMaxBytesLocalOffHeap - totalOffHeapAssignedMemory < 0) {
1826             configErrors.add(new ConfigError("Cache '" + getName()
1827                                             + "' over-allocates CacheManager's localOffHeap limit!"));
1828         }
1829     }
1830
1831     private void verifyLocalHeap(final long managerMaxBytesLocalHeap,
1832                                  final List<ConfigError> configErrors, final long totalOnHeapAssignedMemory) {
1833         if ((isMaxBytesLocalHeapPercentageSet() || getMaxBytesLocalHeap() > 0)
1834             && managerMaxBytesLocalHeap > 0 && managerMaxBytesLocalHeap - totalOnHeapAssignedMemory < 0) {
1835             configErrors.add(new ConfigError("Cache '" + getName()
1836                                                     + "' over-allocates CacheManager's localOnHeap limit!"));
1837         }
1838     }
1839
1840     /**
1841      * Configures the cache pools
1842      * @param configuration the Configuration of the CacheManager managing this cache
1843      */

1844     void configCachePools(Configuration configuration) {
1845
1846         long cacheAssignedMem;
1847         if (getMaxBytesLocalHeapPercentage() != null) {
1848             cacheAssignedMem = configuration.getMaxBytesLocalHeap() * getMaxBytesLocalHeapPercentage() / HUNDRED_PERCENT;
1849             setMaxBytesLocalHeap(cacheAssignedMem);
1850         }
1851
1852         if (offHeapPoolUsage == null && getMaxBytesLocalOffHeapPercentage() != null) {
1853             cacheAssignedMem = configuration.getMaxBytesLocalOffHeap() * getMaxBytesLocalOffHeapPercentage() / HUNDRED_PERCENT;
1854             setMaxBytesLocalOffHeap(cacheAssignedMem);
1855         }
1856
1857         if (getMaxBytesLocalDiskPercentage() != null) {
1858             cacheAssignedMem = configuration.getMaxBytesLocalDisk() * getMaxBytesLocalDiskPercentage() / HUNDRED_PERCENT;
1859             setMaxBytesLocalDisk(cacheAssignedMem);
1860         }
1861
1862     }
1863
1864     /**
1865      * Validates the configuration
1866      * @param configuration the CacheManager configuration this is going to be used with
1867      * @return the errors in the config
1868      */

1869     public Collection<ConfigError> validate(final Configuration configuration) {
1870
1871         final Collection<ConfigError> errors = new ArrayList<ConfigError>();
1872
1873         verifyClusteredCacheConfiguration(configuration, errors);
1874
1875         if (maxEntriesLocalHeap == null && !configuration.isMaxBytesLocalHeapSet() && maxBytesLocalHeap == null) {
1876             errors.add(new CacheConfigError("If your CacheManager has no maxBytesLocalHeap set, you need to either set " +
1877                     "maxEntriesLocalHeap or maxBytesLocalHeap at the Cache level", getName()));
1878         }
1879
1880         if (configuration.isMaxBytesLocalHeapSet() && Runtime.getRuntime().maxMemory() - configuration.getMaxBytesLocalHeap() < 0) {
1881             errors.add(new ConfigError("You've assigned more memory to the on-heap than the VM can sustain, " +
1882                                                     "please adjust your -Xmx setting accordingly"));
1883         }
1884
1885         //commenting this check until fixed for cachemanger is fixed
1886         //if (isOverflowToOffHeapSet() && !maxBytesLocalOffHeapExplicitlySet) {
1887         //    errors.add(new CacheConfigError("\"overFlowToOffHeap\" is set, but \"maxBytesLocalOffHeap\" is not set.", getName()));
1888         //}
1889
1890         if (persistenceConfiguration != null && persistenceConfiguration.getStrategy() == null) {
1891             errors.add(new ConfigError("Persistence configuration found with no strategy set."));
1892         }
1893
1894         errors.addAll(validateCachePools(configuration));
1895
1896         return errors;
1897     }
1898
1899     private void verifyClusteredCacheConfiguration(final Configuration configuration, final Collection<ConfigError> errors) {
1900         if (!isTerracottaClustered()) { return; }
1901
1902         if (getPinningConfiguration() != null && getPinningConfiguration().getStore() == PinningConfiguration.Store.INCACHE
1903                 && getMaxElementsOnDisk() != 0) {
1904             errors.add(new CacheConfigError("maxElementsOnDisk may not be used on a pinned cache.", getName()));
1905         }
1906
1907         if (maxEntriesLocalDiskExplicitlySet) {
1908             errors.add(new CacheConfigError("You can't set maxEntriesLocalDisk when clustering your cache with Terracotta, " +
1909                     "local disks won't be used! To control elements going in the cache cluster wide, " +
1910                     "use maxElementsOnDisk instead", getName()));
1911         }
1912
1913
1914         if (maxBytesLocalDiskExplicitlySet) {
1915             errors.add(new CacheConfigError("You can't set maxBytesLocalDisk when clustering your cache with Terracotta",
1916                     getName()));
1917         }
1918
1919         validateTerracottaConfig(configuration, errors);
1920     }
1921
1922     /**
1923      * Validates the CacheConfiguration against the CacheManager's Configuration
1924      * @param configuration The CacheManager Configuration
1925      * @return the list of errors encountered, or an empty list
1926      */

1927     List<CacheConfigError> validateCachePools(final Configuration configuration) {
1928         List<CacheConfigError> errors = new ArrayList<CacheConfigError>();
1929
1930         if (configuration.isMaxBytesLocalHeapSet()
1931             && getMaxEntriesLocalHeap() > 0) {
1932             errors.add(new CacheConfigError("MaxElementsInMemory is not compatible with " +
1933                                             "MaxBytesLocalHeap set on cache manager", getName()));
1934         }
1935         if (getMaxBytesLocalHeap() > 0 && getMaxEntriesLocalHeap() > 0) {
1936             errors.add(new CacheConfigError("MaxElementsInMemory is not compatible with " +
1937                                             "MaxBytesLocalHeap set on cache", getName()));
1938         }
1939         if (isMaxBytesLocalHeapPercentageSet() && !configuration.isMaxBytesLocalHeapSet()) {
1940             errors.add(new CacheConfigError("Defines a percentage maxBytesOnHeap value but no CacheManager " +
1941                                             "wide value was configured", getName()));
1942         }
1943         if (isMaxBytesLocalOffHeapPercentageSet() && !configuration.isMaxBytesLocalOffHeapSet()) {
1944             errors.add(new CacheConfigError("Defines a percentage maxBytesOffHeap value but no CacheManager " +
1945                                             "wide value was configured", getName()));
1946         }
1947         if (isMaxBytesLocalDiskPercentageSet() && !configuration.isMaxBytesLocalDiskSet()) {
1948             errors.add(new CacheConfigError("Defines a percentage maxBytesOnDisk value but no CacheManager " +
1949                                             "wide value was configured", getName()));
1950         }
1951         return errors;
1952     }
1953
1954     private void validateTerracottaConfig(final Configuration configuration, final Collection<ConfigError> errors) {
1955         final TerracottaClientConfiguration clientConfiguration = configuration.getTerracottaConfiguration();
1956         if (clientConfiguration != null && clientConfiguration.isRejoin() && !getTerracottaConfiguration().isNonstopEnabled()) {
1957             errors.add(new CacheConfigError("Terracotta clustered caches must be nonstop when rejoin is enabled.", getName()));
1958         }
1959     }
1960
1961     /**
1962      * Whether this cache is Count based
1963      * @return true if maxEntries set, false otherwise
1964      */

1965     public boolean isCountBasedTuned() {
1966         return (maxEntriesLocalHeap != null && maxEntriesLocalHeap > 0) || maxElementsOnDisk > 0;
1967     }
1968
1969     /**
1970      * Checks whether the overflowing to off heap behavior was explicitly set
1971      * @return true if explicitly set, false otherwise
1972      */

1973     public boolean isOverflowToOffHeapSet() {
1974         return overflowToOffHeap != null;
1975     }
1976
1977
1978     /**
1979      * Configuration for the CacheEventListenerFactory.
1980      */

1981     public static final class CacheEventListenerFactoryConfiguration extends FactoryConfiguration<CacheEventListenerFactoryConfiguration> {
1982         private NotificationScope notificationScope = NotificationScope.ALL;
1983
1984         /**
1985          * Used by BeanHandler to set the mode during parsing. Convert listenFor string to uppercase and
1986          * look up enum constant in NotificationScope.
1987          */

1988         public void setListenFor(String listenFor) {
1989             if (listenFor == null) {
1990                 throw new IllegalArgumentException("listenFor must be non-null");
1991             }
1992             this.notificationScope = NotificationScope.valueOf(NotificationScope.class, listenFor.toUpperCase());
1993         }
1994
1995         /**
1996          * @return this factory configuration instance
1997          * @see #setListenFor(String)
1998          */

1999         public final CacheEventListenerFactoryConfiguration listenFor(String listenFor) {
2000             setListenFor(listenFor);
2001             return this;
2002         }
2003
2004         /**
2005          * Get the value mode in terms of the mode enum
2006          */

2007         public NotificationScope getListenFor() {
2008             return this.notificationScope;
2009         }
2010     }
2011
2012     /**
2013      * Used by BeanUtils to add cacheEventListenerFactory elements to the cache configuration.
2014      */

2015     public final void addCacheEventListenerFactory(CacheEventListenerFactoryConfiguration factory) {
2016         checkDynamicChange();
2017         cacheEventListenerConfigurations.add(factory);
2018         validateConfiguration();
2019     }
2020
2021     /**
2022      * @return this configuration instance
2023      * @see #addCacheEventListenerFactory(CacheEventListenerFactoryConfiguration)
2024      */

2025     public final CacheConfiguration cacheEventListenerFactory(CacheEventListenerFactoryConfiguration factory) {
2026         addCacheEventListenerFactory(factory);
2027         return this;
2028     }
2029
2030     /**
2031      * Configuration for the CacheExtensionFactoryConfiguration.
2032      */

2033     public static final class CacheExtensionFactoryConfiguration extends FactoryConfiguration<CacheExtensionFactoryConfiguration> {
2034     }
2035
2036     /**
2037      * Used by BeanUtils to add cacheExtensionFactory elements to the cache configuration.
2038      */

2039     public final void addCacheExtensionFactory(CacheExtensionFactoryConfiguration factory) {
2040         checkDynamicChange();
2041         cacheExtensionConfigurations.add(factory);
2042     }
2043
2044     /**
2045      * @return this configuration instance
2046      * @see #addCacheExtensionFactory(CacheExtensionFactoryConfiguration)
2047      */

2048     public final CacheConfiguration cacheExtensionFactory(CacheExtensionFactoryConfiguration factory) {
2049         /**
2050          * {@inheritDoc}
2051          */

2052         addCacheExtensionFactory(factory);
2053         return this;
2054     }
2055
2056     /**
2057      * Configuration for the BootstrapCacheLoaderFactoryConfiguration.
2058      */

2059     public static final class BootstrapCacheLoaderFactoryConfiguration extends
2060             FactoryConfiguration<BootstrapCacheLoaderFactoryConfiguration> {
2061     }
2062
2063     /**
2064      * Allows BeanHandler to add the CacheManagerEventListener to the configuration.
2065      */

2066     public final void addBootstrapCacheLoaderFactory(BootstrapCacheLoaderFactoryConfiguration factory) {
2067         checkDynamicChange();
2068         this.bootstrapCacheLoaderFactoryConfiguration = factory;
2069     }
2070
2071     /**
2072      * @return this configuration instance
2073      * @see #addBootstrapCacheLoaderFactory(BootstrapCacheLoaderFactoryConfiguration)
2074      */

2075     public final CacheConfiguration bootstrapCacheLoaderFactory(BootstrapCacheLoaderFactoryConfiguration factory) {
2076         addBootstrapCacheLoaderFactory(factory);
2077         return this;
2078     }
2079
2080     /**
2081      * Configuration for the BootstrapCacheLoaderFactoryConfiguration.
2082      */

2083     public static final class CacheExceptionHandlerFactoryConfiguration extends
2084             FactoryConfiguration<CacheExceptionHandlerFactoryConfiguration> {
2085     }
2086
2087     /**
2088      * Add the CacheExceptionHandlerFactory to the configuration.
2089      * <p/>
2090      * Note that this will not have any effect when creating a cache solely through its constructed. The exception
2091      * handler will only be taken into account when {@link ConfigurationHelper} is used, for example through
2092      * {@link net.sf.ehcache.CacheManager}.
2093      */

2094     public final void addCacheExceptionHandlerFactory(CacheExceptionHandlerFactoryConfiguration factory) {
2095         checkDynamicChange();
2096         this.cacheExceptionHandlerFactoryConfiguration = factory;
2097     }
2098
2099     /**
2100      * @return this configuration instance
2101      * @see #addCacheExceptionHandlerFactory(CacheExceptionHandlerFactoryConfiguration)
2102      */

2103     public final CacheConfiguration cacheExceptionHandlerFactory(CacheExceptionHandlerFactoryConfiguration factory) {
2104         addCacheExceptionHandlerFactory(factory);
2105         return this;
2106     }
2107
2108     /**
2109      * Configuration for the CacheLoaderFactoryConfiguration.
2110      */

2111     public static final class CacheLoaderFactoryConfiguration extends FactoryConfiguration<CacheLoaderFactoryConfiguration> {
2112     }
2113
2114     /**
2115      * Used by BeanUtils to add each cacheLoaderFactory to the cache configuration.
2116      *
2117      * @param factory
2118      */

2119     public final void addCacheLoaderFactory(CacheLoaderFactoryConfiguration factory) {
2120         checkDynamicChange();
2121         cacheLoaderConfigurations.add(factory);
2122     }
2123
2124     /**
2125      * Configuration for the CacheDecoratorFactoryConfiguration.
2126      */

2127     public static final class CacheDecoratorFactoryConfiguration extends FactoryConfiguration<CacheDecoratorFactoryConfiguration> {
2128     }
2129
2130     /**
2131      * Used by BeanUtils to add each cacheDecoratorFactory to the cache configuration.
2132      *
2133      * @param factory
2134      */

2135     public final void addCacheDecoratorFactory(CacheDecoratorFactoryConfiguration factory) {
2136         checkDynamicChange();
2137         cacheDecoratorConfigurations.add(factory);
2138     }
2139
2140     /**
2141      * @return this configuration instance
2142      * @see #addCacheLoaderFactory(CacheLoaderFactoryConfiguration)
2143      */

2144     public final CacheConfiguration cacheLoaderFactory(CacheLoaderFactoryConfiguration factory) {
2145         addCacheLoaderFactory(factory);
2146         return this;
2147     }
2148
2149     /**
2150      * Allows BeanHandler to add the TerracottaConfiguration to the configuration.
2151      */

2152     public final void addTerracotta(TerracottaConfiguration terracottaConfiguration) {
2153         this.terracottaConfiguration = terracottaConfiguration;
2154         validateConfiguration();
2155     }
2156
2157     /**
2158      * Allows BeanHandler to add the PinningConfiguration to the configuration.
2159      */

2160     public final void addPinning(PinningConfiguration pinningConfiguration) {
2161         this.pinningConfiguration = pinningConfiguration;
2162         validateConfiguration();
2163     }
2164
2165     /**
2166      * @return this configuration instance
2167      * @see #addPinning(PinningConfiguration)
2168      */

2169     public final CacheConfiguration pinning(PinningConfiguration pinningConfiguration) {
2170         addPinning(pinningConfiguration);
2171         return this;
2172     }
2173
2174     /**
2175      * @return this configuration instance
2176      * @see #addTerracotta(TerracottaConfiguration)
2177      */

2178     public final CacheConfiguration terracotta(TerracottaConfiguration terracottaConfiguration) {
2179         addTerracotta(terracottaConfiguration);
2180         return this;
2181     }
2182
2183     /**
2184      * @see #addSearchable(Searchable)
2185      * @param searchable
2186      * @return this
2187      */

2188     public final CacheConfiguration searchable(Searchable searchable) {
2189         addSearchable(searchable);
2190         return this;
2191     }
2192
2193     /**
2194      * Allows BeanHandler to add the CacheWriterConfiguration to the configuration.
2195      */

2196     public final void addCacheWriter(CacheWriterConfiguration cacheWriterConfiguration) {
2197         if (null == cacheWriterConfiguration) {
2198             this.cacheWriterConfiguration = new CacheWriterConfiguration();
2199         } else {
2200             this.cacheWriterConfiguration = cacheWriterConfiguration;
2201         }
2202     }
2203
2204     /**
2205      * @return this configuration instance
2206      * @see #addCacheWriter(CacheWriterConfiguration)
2207      */

2208     public final CacheConfiguration cacheWriter(CacheWriterConfiguration cacheWriterConfiguration) {
2209         addCacheWriter(cacheWriterConfiguration);
2210         return this;
2211     }
2212
2213     /**
2214      * Sets the transactionalMode
2215      *
2216      * @param transactionalMode one of OFF, LOCAL, XA, XA_STRICT
2217      */

2218     public final void setTransactionalMode(final String transactionalMode) {
2219         assertArgumentNotNull("Cache transactionalMode", transactionalMode);
2220         transactionalMode(TransactionalMode.valueOf(transactionalMode.toUpperCase()));
2221     }
2222
2223     /**
2224      * Builder which sets the transactionalMode
2225      *
2226      * @param transactionalMode one of OFF, LOCAL, XA, XA_STRICT
2227      * @return this configuration instance
2228      * @see #setTransactionalMode(String)
2229      */

2230     public final CacheConfiguration transactionalMode(String transactionalMode) {
2231         setTransactionalMode(transactionalMode);
2232         return this;
2233     }
2234
2235     /**
2236      * Builder which sets the transactionalMode
2237      *
2238      * @param transactionalMode one of OFF, LOCAL, XA, XA_STRICT
2239      * @return this configuration instance
2240      * @see #setTransactionalMode(String)
2241      */

2242     public final CacheConfiguration transactionalMode(TransactionalMode transactionalMode) {
2243         if (transactionalMode == null) {
2244             throw new IllegalArgumentException("TransactionalMode value must be non-null");
2245         }
2246         if (this.transactionalMode != null) {
2247             throw new InvalidConfigurationException("transactionalMode cannot be changed once set");
2248         }
2249         this.transactionalMode = transactionalMode;
2250         return this;
2251     }
2252
2253     /**
2254      * Sets whether the cache's statistics are enabled. at startup
2255      */

2256     public final void setStatistics(boolean enabled) {
2257         this.statistics = enabled;
2258     }
2259
2260     /**
2261      * Builder which sets whether the cache's statistics are enabled.
2262      *
2263      * @return this configuration instance
2264      * @see #setStatistics(boolean)
2265      */

2266     public final CacheConfiguration statistics(boolean statistics) {
2267         setStatistics(statistics);
2268         return this;
2269     }
2270
2271     /**
2272      * Gets whether the cache's statistics will be enabled at startup
2273      */

2274     public final boolean getStatistics() {
2275         return statistics;
2276     }
2277
2278     /**
2279      * Used to validate what should be a complete Cache Configuration.
2280      */

2281     public void validateCompleteConfiguration() {
2282
2283         validateConfiguration();
2284
2285         // Extra checks that a completed cache config should have
2286
2287         if (name == null) {
2288             throw new InvalidConfigurationException("Caches must be named.");
2289         }
2290     }
2291
2292     /**
2293      * Used to validate a Cache Configuration.
2294      */

2295     public void validateConfiguration() {
2296         if (terracottaConfiguration != null && terracottaConfiguration.isClustered()) {
2297             if (overflowToDisk != null && overflowToDisk) {
2298                 throw new InvalidConfigurationException("overflowToDisk isn't supported for a clustered Terracotta cache");
2299             }
2300             if (diskPersistent == Boolean.TRUE) {
2301                 throw new InvalidConfigurationException("diskPersistent isn't supported for a clustered Terracotta cache");
2302             }
2303             if (persistenceConfiguration != null && !Strategy.DISTRIBUTED.equals(persistenceConfiguration.getStrategy())) {
2304                 throw new InvalidConfigurationException(persistenceConfiguration.getStrategy() +
2305                         " persistence strategy isn't supported for a clustered Terracotta cache");
2306             }
2307             if (cacheEventListenerConfigurations != null) {
2308                 for (CacheEventListenerFactoryConfiguration listenerConfig : cacheEventListenerConfigurations) {
2309                     if (null == listenerConfig.getFullyQualifiedClassPath()) {
2310                         continue;
2311                     }
2312                     if (!listenerConfig.getFullyQualifiedClassPath().startsWith("net.sf.ehcache.") &&
2313                             LOG.isWarnEnabled()) {
2314                         LOG.warn("The non-standard CacheEventListenerFactory '" + listenerConfig.getFullyQualifiedClassPath() +
2315                                 "' is used with a clustered Terracotta cache, " +
2316                                 "if the purpose of this listener is replication it is not supported in a clustered context");
2317                     }
2318                 }
2319             }
2320         }
2321         if (cacheWriterConfiguration != null) {
2322             if (!cacheWriterConfiguration.getWriteBatching() && cacheWriterConfiguration.getWriteBatchSize() != 1) {
2323                 throw new InvalidConfigurationException("CacheWriter Batch Size !=1 and CacheWriter Batching " +
2324                         "turned off");
2325             }
2326         }
2327     }
2328
2329     private void validateTransactionalSettings() {
2330         boolean transactional = getTransactionalMode().isTransactional();
2331         if (copyOnRead == null) {
2332             if (terracottaConfiguration != null && terracottaConfiguration.isCopyOnReadSet()) {
2333                 copyOnRead = terracottaConfiguration.isCopyOnRead();
2334             } else {
2335                 copyOnRead = transactional;
2336             }
2337         }
2338         if (copyOnWrite == null) {
2339             copyOnWrite = transactional;
2340         }
2341
2342         if (transactional) {
2343             if (!copyOnRead || !copyOnWrite) {
2344                 throw new InvalidConfigurationException("A transactional cache has to be copyOnRead and copyOnWrite!");
2345             }
2346         }
2347     }
2348
2349     /**
2350      * Accessor
2351      */

2352     public String getName() {
2353         return name;
2354     }
2355
2356     /**
2357      * Accessor
2358      *
2359      * @deprecated use {@link #getMaxEntriesLocalHeap()}
2360      */

2361     @Deprecated
2362     public int getMaxElementsInMemory() {
2363         return (int)getMaxEntriesLocalHeap();
2364     }
2365
2366     /**
2367      * Accessor
2368      */

2369     public long getCacheLoaderTimeoutMillis() {
2370         return cacheLoaderTimeoutMillis;
2371     }
2372
2373     /**
2374      * Accessor
2375      *
2376      */

2377     public int getMaxElementsOnDisk() {
2378         return maxElementsOnDisk;
2379     }
2380
2381     /**
2382      * Configured maximum number of entries for the local disk store.
2383      */

2384     public long getMaxEntriesLocalDisk() {
2385         return maxElementsOnDisk;
2386     }
2387
2388     /**
2389      * Configured maximum number of entries for the local memory heap.
2390      */

2391     public long getMaxEntriesLocalHeap() {
2392         return maxEntriesLocalHeap == null ? 0 : maxEntriesLocalHeap;
2393     }
2394
2395     /**
2396      * Accessor
2397      */

2398     public MemoryStoreEvictionPolicy getMemoryStoreEvictionPolicy() {
2399         return memoryStoreEvictionPolicy;
2400     }
2401
2402     /**
2403      * Accessor
2404      */

2405     public boolean isClearOnFlush() {
2406         return clearOnFlush;
2407     }
2408
2409     /**
2410      * Accessor
2411      */

2412     public boolean isEternal() {
2413         return eternal;
2414     }
2415
2416     /**
2417      * Accessor
2418      */

2419     public long getTimeToIdleSeconds() {
2420         return timeToIdleSeconds;
2421     }
2422
2423     /**
2424      * Accessor
2425      */

2426     public long getTimeToLiveSeconds() {
2427         return timeToLiveSeconds;
2428     }
2429
2430     /**
2431      * Accessor
2432      *
2433      * @deprecated The {@code overflowToDisk} attribute has been replaced with {@link Strategy#LOCALTEMPSWAP}.
2434      */

2435     @Deprecated
2436     public boolean isOverflowToDisk() {
2437         return overflowToDisk == null ? false : overflowToDisk;
2438     }
2439
2440     /**
2441      * Accessor
2442      *
2443      * @deprecated The {@code diskPersistent} attribute has been replaced with {@link #persistence(PersistenceConfiguration)}.
2444      */

2445     @Deprecated
2446     public boolean isDiskPersistent() {
2447         Boolean persistent = diskPersistent;
2448         return diskPersistent == null ? DEFAULT_DISK_PERSISTENT : persistent;
2449     }
2450
2451     /**
2452      * Accessor
2453      */

2454     public boolean isSearchable() {
2455         return searchable != null;
2456     }
2457
2458     /**
2459      * Accessor
2460      */

2461     public int getDiskSpoolBufferSizeMB() {
2462         return diskSpoolBufferSizeMB;
2463     }
2464
2465     /**
2466      * Accessor
2467      */

2468     public long getDiskExpiryThreadIntervalSeconds() {
2469         return diskExpiryThreadIntervalSeconds;
2470     }
2471
2472     /**
2473      * Accessor
2474      */

2475     public int getDiskAccessStripes() {
2476         return diskAccessStripes;
2477     }
2478
2479     /**
2480      * Accessor
2481      */

2482     public DynamicAttributesExtractor getDynamicExtractor() {
2483         return flexIndexer;
2484     }
2485     /**
2486      * Only used when cache is clustered with Terracotta
2487      *
2488      * @return true if logging is enabled otherwise false
2489      */

2490     public boolean getLogging() {
2491         return logging;
2492     }
2493
2494     /**
2495      * Accessor
2496      *
2497      * @return true if offheap store is enabled, otherwise false.
2498      */

2499     public boolean isOverflowToOffHeap() {
2500         return overflowToOffHeap == null ? false : overflowToOffHeap;
2501     }
2502
2503     /**
2504      * Accessor
2505      *
2506      * @return the SizeOfPolicy Configuration for this cache.
2507      */

2508     public SizeOfPolicyConfiguration getSizeOfPolicyConfiguration() {
2509         return sizeOfPolicyConfiguration;
2510     }
2511
2512     /**
2513      * Accessor
2514      *
2515      * @return the persistence configuration for this cache.
2516      */

2517     public PersistenceConfiguration getPersistenceConfiguration() {
2518         return persistenceConfiguration;
2519     }
2520
2521     /**
2522      * Accessor
2523      *
2524      * @return the max memory of the offheap store for this cache.
2525      * @deprecated See {@link #getMaxBytesLocalOffHeapAsString()}
2526      */

2527     @Deprecated
2528     public String getMaxMemoryOffHeap() {
2529         return maxBytesLocalOffHeapInput;
2530     }
2531
2532     /**
2533      * Accessor
2534      *
2535      * @return the max memory of the offheap store for this cache, in bytes.
2536      * @deprecated {@link #getMaxBytesLocalOffHeap()}
2537      */

2538     @Deprecated
2539     public long getMaxMemoryOffHeapInBytes() {
2540         return getMaxBytesLocalOffHeap();
2541     }
2542
2543     /**
2544      * Accessor
2545      */

2546     public List getCacheEventListenerConfigurations() {
2547         return cacheEventListenerConfigurations;
2548     }
2549
2550     /**
2551      * Accessor
2552      *
2553      * @return the configuration
2554      */

2555     public List getCacheExtensionConfigurations() {
2556         return cacheExtensionConfigurations;
2557     }
2558
2559     /**
2560      * Accessor
2561      *
2562      * @return the configuration
2563      */

2564     public List getCacheLoaderConfigurations() {
2565         return cacheLoaderConfigurations;
2566     }
2567
2568     /**
2569      * Accessor
2570      *
2571      * @return the configuration
2572      */

2573     public List<CacheDecoratorFactoryConfiguration> getCacheDecoratorConfigurations() {
2574         return cacheDecoratorConfigurations;
2575     }
2576
2577     /**
2578      * Accessor
2579      *
2580      * @return the configuration
2581      */

2582     public BootstrapCacheLoaderFactoryConfiguration getBootstrapCacheLoaderFactoryConfiguration() {
2583         return bootstrapCacheLoaderFactoryConfiguration;
2584     }
2585
2586     /**
2587      * Accessor
2588      *
2589      * @return the configuration
2590      */

2591     public CacheExceptionHandlerFactoryConfiguration getCacheExceptionHandlerFactoryConfiguration() {
2592         return cacheExceptionHandlerFactoryConfiguration;
2593     }
2594
2595     /**
2596      * Accessor
2597      *
2598      * @return the terracotta configuration
2599      */

2600     public TerracottaConfiguration getTerracottaConfiguration() {
2601         return terracottaConfiguration;
2602     }
2603
2604     /**
2605      * Accessor
2606      *
2607      * @return the pinning configuration
2608      */

2609     public PinningConfiguration getPinningConfiguration() {
2610         return pinningConfiguration;
2611     }
2612
2613     /**
2614      * Accessor
2615      *
2616      * @return the writer configuration
2617      */

2618     public CacheWriterConfiguration getCacheWriterConfiguration() {
2619         return cacheWriterConfiguration;
2620     }
2621
2622     /**
2623      * Helper method to compute whether the cache is clustered or not
2624      *
2625      * @return True if the &lt;terracotta/&gt; element exists with {@code clustered="true"}
2626      */

2627     public boolean isTerracottaClustered() {
2628         return terracottaConfiguration != null && terracottaConfiguration.isClustered();
2629     }
2630
2631     /**
2632      * Accessor
2633      *
2634      * @return the CoherenceMode if Terracotta-clustered or null
2635      */

2636     public Consistency getTerracottaConsistency() {
2637         return terracottaConfiguration != null ? terracottaConfiguration.getConsistency() : null;
2638     }
2639
2640     /**
2641      * To what transactionalMode was the Cache set
2642      *
2643      * @return transactionaMode
2644      */

2645     public final TransactionalMode getTransactionalMode() {
2646         if (transactionalMode == null) {
2647             return DEFAULT_TRANSACTIONAL_MODE;
2648         }
2649         return transactionalMode;
2650     }
2651
2652     /**
2653      * Helper method to compute whether the cache is XA transactional or not
2654      *
2655      * @return true if transactionalMode="xa_strict"
2656      */

2657     public boolean isXaStrictTransactional() {
2658         validateTransactionalSettings();
2659         return getTransactionalMode().equals(TransactionalMode.XA_STRICT);
2660     }
2661
2662     /**
2663      * Helper method to compute whether the cache is local transactional or not
2664      *
2665      * @return true if transactionalMode="local"
2666      */

2667     public boolean isLocalTransactional() {
2668         validateTransactionalSettings();
2669         return getTransactionalMode().equals(TransactionalMode.LOCAL);
2670     }
2671
2672     /**
2673      * Helper method to compute whether the cache is local_jta transactional or not
2674      *
2675      * @return true if transactionalMode="xa"
2676      */

2677     public boolean isXaTransactional() {
2678         validateTransactionalSettings();
2679         return getTransactionalMode().equals(TransactionalMode.XA);
2680     }
2681
2682     /**
2683      * An enum to identify what pool a resource uses
2684      */

2685     private static enum PoolUsage {
2686
2687         CacheManager(true), Cache(true), None(false);
2688
2689         private final boolean usingPool;
2690         private PoolUsage(final boolean poolUser) {
2691             this.usingPool = poolUser;
2692         }
2693
2694         public boolean isUsingPool() {
2695             return usingPool;
2696         }
2697     }
2698     /**
2699      * Represents whether the Cache is transactional or not.
2700      *
2701      * @author alexsnaps
2702      */

2703     public static enum TransactionalMode {
2704
2705         /**
2706          * No Transactions
2707          */

2708         OFF(false),
2709
2710         /**
2711          * Local Transactions
2712          */

2713         LOCAL(true),
2714
2715         /**
2716          * XA Transactions
2717          */

2718         XA(true),
2719
2720         /**
2721          * XA Strict (true 2PC) Transactions
2722          */

2723         XA_STRICT(true);
2724
2725         private final boolean transactional;
2726
2727         /**
2728          * @param transactional
2729          */

2730         TransactionalMode(final boolean transactional) {
2731             this.transactional = transactional;
2732         }
2733
2734         /**
2735          * @return transactional
2736          */

2737         public boolean isTransactional() {
2738             return transactional;
2739         }
2740     }
2741
2742     /**
2743      * Add a listener to this cache configuration
2744      *
2745      * @param listener listener instance to add
2746      * @return true if a listener was added
2747      */

2748     public boolean addConfigurationListener(CacheConfigurationListener listener) {
2749         boolean added = listeners.add(listener);
2750         if (added) {
2751             listener.registered(this);
2752         }
2753         return added;
2754     }
2755
2756     /**
2757      * Add a dynamic extractor configuration listener
2758      * @param listener
2759      * @return true if a listener was added
2760      */

2761     public boolean addDynamicSearchListener(DynamicSearchListener listener) {
2762         return dynamicSearchListeners.add(listener);
2763     }
2764
2765     /**
2766      * Remove the supplied cache configuration listener.
2767      *
2768      * @param listener listener to remove
2769      * @return true if a listener was removed
2770      */

2771     public boolean removeConfigurationListener(CacheConfigurationListener listener) {
2772         boolean removed = listeners.remove(listener);
2773         if (removed) {
2774             listener.deregistered(this);
2775         }
2776         return removed;
2777     }
2778
2779     private void fireTtiChanged(long oldTti, long newTti) {
2780         if (oldTti != newTti) {
2781             for (CacheConfigurationListener l : listeners) {
2782                 l.timeToIdleChanged(oldTti, newTti);
2783             }
2784         }
2785     }
2786
2787     private void fireTtlChanged(long oldTtl, long newTtl) {
2788         if (oldTtl != newTtl) {
2789             for (CacheConfigurationListener l : listeners) {
2790                 l.timeToLiveChanged(oldTtl, newTtl);
2791             }
2792         }
2793     }
2794
2795     private void fireLoggingChanged(boolean oldValue, boolean newValue) {
2796         if (oldValue != newValue) {
2797             for (CacheConfigurationListener l : listeners) {
2798                 l.loggingChanged(oldValue, newValue);
2799             }
2800         }
2801     }
2802
2803     private void fireDiskCapacityChanged(int oldCapacity, int newCapacity) {
2804         if (oldCapacity != newCapacity) {
2805             for (CacheConfigurationListener l : listeners) {
2806                 l.diskCapacityChanged(oldCapacity, newCapacity);
2807             }
2808         }
2809     }
2810
2811     private void fireMemoryCapacityChanged(int oldCapacity, int newCapacity) {
2812         if (oldCapacity != newCapacity) {
2813             for (CacheConfigurationListener l : listeners) {
2814                 l.memoryCapacityChanged(oldCapacity, newCapacity);
2815             }
2816         }
2817     }
2818
2819     private void checkDynamicChange() {
2820         if (frozen) {
2821             throw new CacheException("Dynamic configuration changes are disabled for this cache");
2822         }
2823     }
2824
2825     /**
2826      * Intended for internal use only, and subject to change.
2827      * This is required so that changes in store implementation's config
2828      * (probably from other nodes) can propagate up to here
2829      */

2830     public void internalSetTimeToIdle(long timeToIdle) {
2831         this.timeToIdleSeconds = timeToIdle;
2832     }
2833
2834     /**
2835      * Intended for internal use only, and subject to change.
2836      */

2837     public void internalSetTimeToLive(long timeToLive) {
2838         this.timeToLiveSeconds = timeToLive;
2839     }
2840
2841     /**
2842      * Intended for internal use only, and subject to change.
2843      */

2844     public void internalSetMemCapacity(int capacity) {
2845         this.maxEntriesLocalHeap = capacity;
2846     }
2847
2848     /**
2849      * Intended for internal use only, and subject to change.
2850      */

2851     public void internalSetMemCapacityInBytes(long capacity) {
2852         this.maxBytesLocalHeap = capacity;
2853     }
2854
2855     /**
2856      * Intended for internal use only, and subject to change.
2857      */

2858     public void internalSetDiskCapacity(int capacity) {
2859         this.maxElementsOnDisk = capacity;
2860     }
2861
2862     /**
2863      * Intended for internal use only, and subject to change.
2864      */

2865     public void internalSetLogging(boolean logging) {
2866         this.logging = logging;
2867     }
2868
2869     /**
2870      * Get the defined search attributes indexed by attribute name
2871      *
2872      * @return search attributes
2873      */

2874     public Map<String, SearchAttribute> getSearchAttributes() {
2875         if (searchable == null) {
2876             return Collections.emptyMap();
2877         }
2878         return searchable.getSearchAttributes();
2879     }
2880
2881     /**
2882      * Get the search configuration for this cache (if any)
2883      *
2884      * @return search config (may be null)
2885      */

2886     public Searchable getSearchable() {
2887         return searchable;
2888     }
2889
2890 }
2891