package org.cache2k;
/*
* #%L
* cache2k API
* %%
* Copyright (C) 2000 - 2017 headissue GmbH, Munich
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.cache2k.configuration.Cache2kConfiguration;
import org.cache2k.configuration.CacheTypeCapture;
import org.cache2k.configuration.CacheType;
import org.cache2k.configuration.ConfigurationSection;
import org.cache2k.configuration.ConfigurationSectionBuilder;
import org.cache2k.configuration.CustomizationReferenceSupplier;
import org.cache2k.expiry.ExpiryPolicy;
import org.cache2k.event.CacheEntryOperationListener;
import org.cache2k.integration.AdvancedCacheLoader;
import org.cache2k.integration.CacheLoader;
import org.cache2k.integration.CacheWriter;
import org.cache2k.integration.ExceptionPropagator;
import org.cache2k.integration.FunctionalCacheLoader;
import org.cache2k.integration.ResiliencePolicy;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
/**
* Builder to create a {@link Cache} instance. The usage is:
*
* <pre>{@code
* Cache<Long, List<String>> c =
* new Cache2kBuilder<Long, List<String>>() {}
* .name("myCache")
* .eternal(true)
* .build();
* }</pre>
*
* <p>Caches belong to a cache manager. If no cache manager is set explicitly via {@link #manager} the
* default cache manager will be used, as defined by {@link CacheManager#getInstance()}.
*
* <p>To create a cache from a known configuration in a specified cache manager, use:
*
* <pre>{@code
* CacheManager manager = ...
* CacheConfiguration<Long, List<String>> config = ...
*
* Cache<Long, List<String>> c =
* Cache2kBuilder.of(config)
* .manager(manager)
* .build();
* }</pre>
*
* <p>To create a cache without type parameters or {@code Cache<Object,Object>}, use {@link Cache2kBuilder#forUnknownTypes()}.
*
* @author Jens Wilke
* @since 1.0
*/
public class Cache2kBuilder<K, V> {
private static final String MSG_NO_TYPES = "Use Cache2kBuilder.forUnknownTypes(), to construct a builder with no key and value types";
/**
* Create a new cache builder for a cache that has no type restrictions
* or to set the type information later via the builder methods {@link #keyType} or
* {@link #valueType}.
*/
public static Cache2kBuilder forUnknownTypes() {
return new Cache2kBuilder(null, null);
}
/**
* Create a new cache builder for key and value types of classes with no generic parameters.
*
* @see #keyType(Class)
* @see #valueType(Class)
*/
public static <K,T> Cache2kBuilder<K,T> of(Class<K> _keyType, Class<T> _valueType) {
return new Cache2kBuilder<K, T>(CacheTypeCapture.of(_keyType), CacheTypeCapture.of(_valueType));
}
/**
* Create a builder from the configuration.
*/
public static <K,T> Cache2kBuilder<K, T> of(Cache2kConfiguration<K, T> c) {
Cache2kBuilder<K,T> cb = new Cache2kBuilder<K, T>(c);
return cb;
}
private CacheType<K> keyType;
private CacheType<V> valueType;
private Cache2kConfiguration<K,V> config = null;
private CacheManager manager = null;
private Cache2kBuilder(Cache2kConfiguration<K,V> cfg) {
withConfig(cfg);
}
/**
* Constructor to override for the usage pattern:
*
* <pre>{@code
* Cache<Long, List<String>> c =
* new Cache2kBuilder<Long, List<String>>() {}
* .name("myCache")
* .eternal(true)
* .build();
* }</pre>
*
* The builder extracts the generic type parameters from the anonymous subclass.
*/
@SuppressWarnings("unchecked")
protected Cache2kBuilder() {
Type t = this.getClass().getGenericSuperclass();
if (!(t instanceof ParameterizedType)) {
throw new IllegalArgumentException(MSG_NO_TYPES);
}
Type[] _types = ((ParameterizedType) t).getActualTypeArguments();
keyType = (CacheType<K>) CacheTypeCapture.of(_types[0]).getBeanRepresentation();
valueType = (CacheType<V>) CacheTypeCapture.of(_types[1]).getBeanRepresentation();
if (Object.class.equals(keyType.getType()) &&
Object.class.equals(valueType.getType())) {
throw new IllegalArgumentException(MSG_NO_TYPES);
}
}
private Cache2kBuilder(CacheType<K> _keyType, CacheType<V> _valueType) {
keyType = _keyType;
valueType = _valueType;
}
private void withConfig(Cache2kConfiguration<K,V> cfg) {
config = cfg;
}
private Cache2kConfiguration<K, V> config() {
if (config == null) {
if (manager == null) {
manager = CacheManager.getInstance();
}
config = CacheManager.PROVIDER.getDefaultConfiguration(manager);
if (keyType != null) {
config.setKeyType(keyType);
}
if (valueType != null) {
config.setValueType(valueType);
}
}
return config;
}
/**
* The manager, the created cache will belong to. If this is set, it must be the
* first method called.
*
* @param manager The manager the created cache should belong to,
* or {@code null} if the default cache manager should be used
* @throws IllegalStateException if the manager is not provided immediately after the builder is created.
*/
public final Cache2kBuilder<K, V> manager(CacheManager manager) {
if (this.manager != null) {
throw new IllegalStateException("manager() must be first operation on builder.");
}
this.manager = manager;
return this;
}
/**
* The used type of the cache key. A suitable cache key must provide a useful
* {@code equals} and {@code hashCode} method. Arrays are not valid for cache keys.
*
* @throws IllegalArgumentException in case the type is illegal
* @see CacheType for a general discussion on types
*/
public final <K2> Cache2kBuilder<K2, V> keyType(Class<K2> t) {
config().setKeyType(t);
return (Cache2kBuilder<K2, V>) this;
}
/**
* Sets the value type to use. Arrays are not supported.
*
* @throws IllegalArgumentException in case the type is illegal
* @see CacheType for a general discussion on types
*/
public final <T2> Cache2kBuilder<K, T2> valueType(Class<T2> t) {
config().setValueType(t);
return (Cache2kBuilder<K, T2>) this;
}
/**
* The used type of the cache key. A suitable cache key must provide a useful
* {@code equals} and {@code hashCode} method. Arrays are not valid for cache keys.
*
* @throws IllegalArgumentException in case the type is illegal
* @see CacheType for a general discussion on types
*/
public final <K2> Cache2kBuilder<K2, V> keyType(CacheType<K2> t) {
config().setKeyType(t);
return (Cache2kBuilder<K2, V>) this;
}
/**
* Sets the value type to use. Arrays are not supported.
*
* @throws IllegalArgumentException in case the type is illegal
* @see CacheType for a general discussion on types
*/
public final <T2> Cache2kBuilder<K, T2> valueType(CacheType<T2> t) {
config().setValueType(t);
return (Cache2kBuilder<K, T2>) this;
}
/**
* Constructs a cache name out of the class name, a field name and a unique name identifying the
* component in the application. Result example: {@code webImagePool~com.example.ImagePool.id2Image}
*
* <p>See {@link #name(String)} for a general discussion about cache names.
*
* @param _uniqueName unique name differentiating multiple components of the same type.
* May be {@code null}.
* @see #name(String)
*/
public final Cache2kBuilder<K, V> name(String _uniqueName, Class<?> _class, String _fieldName) {
if (_fieldName == null) {
throw new NullPointerException();
}
if (_uniqueName == null) {
return name(_class, _fieldName);
}
config().setName(_uniqueName + '~' + _class.getName() + "." + _fieldName);
return this;
}
/**
* Constructs a cache name out of the class name and field name. Result example:
* {@code com.example.ImagePool.id2Image}
*
* <p>See {@link #name(String)} for a general discussion about cache names.
*
* @see #name(String)
*/
public final Cache2kBuilder<K, V> name(Class<?> _class, String _fieldName) {
if (_fieldName == null) {
throw new NullPointerException();
}
config().setName(_class.getName() + "." + _fieldName);
return this;
}
/**
* Sets a cache name from the fully qualified class name.
*
* <p>See {@link #name(String)} for a general discussion about cache names.
*
* @see #name(String)
*/
public final Cache2kBuilder<K, V> name(Class<?> _class) {
config().setName(_class.getName());
return this;
}
/**
* Sets the name of a cache. If a name is specified it must be ensured it is unique within
* the cache manager. Cache names are used at several places to have a unique ID of a cache.
* For example, for referencing additional configuration or to register JMX beans.
*
* <p>If a name is not specified the cache generates a name automatically. The name is
* inferred from the call stack trace and contains the simple class name, the method and
* the line number of the of the caller to {@code build()}. The name also contains
* a random number. Automatically generated names don't allow reliable management, logging and
* additional configuration of caches. If no name is set, {@link #build()} will always create
* a new cache with a new unique name within the cache manager. Automatically generated
* cache names start with the character {@code '_'} as prefix to separate the names from the
* usual class name space.
*
* <p>In case of a name collision the cache is generating a unique name by adding a counter value.
* This behavior may change.
*
* <p>Allowed characters for a cache name, are URL non-reserved characters,
* these are: {@code [A-Z]}, {@code [a-z]}, {@code [0-9]} and {@code [~-_.]},
* see RFC3986 as well as the characters: {@code [()]}. The characters {@code [@, ]} are supported
* as well, but should be avoided.
*
* <p>The reason for restricting the characters in names, is that the names may be used to derive
* other resource names from it, e.g. for file based storage. The cache might not enforce the allowed
* character set for efficiency reasons.
*
* <p>The method is overloaded with variants to provide a naming convention of names.
*
* <p>For brevity within log messages and other displays the cache name may be
* shortened if the manager name is included as prefix.
*
* @see Cache#getName()
*/
public final Cache2kBuilder<K, V> name(String v) {
config().setName(v);
return this;
}
/**
* Expired data is kept in the cache until the entry is evicted. This consumes memory,
* but if the data is accessed again the previous data can be used by the cache loader
* for optimizing (e.g. if-modified-since for a HTTP request). Default value: false
*
* @see AdvancedCacheLoader
*/
public final Cache2kBuilder<K, V> keepDataAfterExpired(boolean v) {
config().setKeepDataAfterExpired(v);
return this;
}
/**
* The maximum number of entries hold by the cache. When the maximum size is reached, by
* inserting new entries, the cache eviction algorithm will remove one or more entries
* to keep the size within the configured limit.
*
* <p>The value {@code Long.MAX_VALUE} means the capacity is not limited.
*
* <p>The default value is 2000. The default value is conservative, so the application
* will usually run stable without tuning or setting a reasonable size.
*/
public final Cache2kBuilder<K, V> entryCapacity(long v) {
config().setEntryCapacity(v);
return this;
}
/**
* When set to {@code true}, cached values do not expire by time. Entries will need to be removed
* from the cache explicitly or will be evicted if capacity constraints are reached.
*
* <p>Setting eternal to {@code false} signals that the data should expire, but there is no
* predefined expiry value at programmatic level. This value needs to be set by other
* means, e.g. within a configuration file.
*
* <p>The default behavior of the cache is identical to the setting of eternal. Entries will not expire.
* When eternal was set explicitly it cannot be reset to another value afterwards. This should protect against
* misconfiguration.
*
* <p>Exceptions: If set to eternal with default setting and if there is no
* explicit expiry configured for exceptions with {@link #retryInterval(long, TimeUnit)},
* exceptions will not be cached and expire immediately.
*
* @throws IllegalArgumentException in case a previous setting is reset
*/
public final Cache2kBuilder<K, V> eternal(boolean v) {
config().setEternal(v);
return this;
}
/**
* Suppress an exception from the cache loader, if there is previous data.
* When a load was not successful, the operation is retried at shorter interval then
* the normal expiry, see {@link #retryInterval(long, TimeUnit)}.
*
* <p>Exception suppression is only active when entries expire (eternal is not true) or the explicit
* configuration of the timing parameters for resilience, e.g. {@link #resilienceDuration(long, TimeUnit)}.
* Check the user guide chapter for details.
*
* <p>Setting this to {@code false}, will disable exceptions suppression or caching (aka resilience).
* Default value: {@code true}
*
* @see <a href="https://cache2k.org/docs/1.0/user-guide.html#resilience-and-exceptions">cache2k user guide - Exceptions and Resilience</a>
*/
public final Cache2kBuilder<K, V> suppressExceptions(boolean v) {
config().setSuppressExceptions(v);
return this;
}
/**
* Time duration after insert or updated an cache entry expires.
* To switch off time based expiry use {@link #eternal(boolean)}.
*
* <p>If an {@link ExpiryPolicy} is specified, the maximum expiry duration
* will not exceed the value that is specified here.
*
* <p>A value of {@code 0} means every entry should expire immediately. Low values or
* {@code 0} together with read through operation mode with a {@link CacheLoader} should be
* avoided in production environments.
*
* @throws IllegalArgumentException if {@link #eternal(boolean)} was set to true
*/
public final Cache2kBuilder<K, V> expireAfterWrite(long v, TimeUnit u) {
config().setExpireAfterWrite(u.toMillis(v));
return this;
}
/**
* Sets customization for propagating loader exceptions. By default loader exceptions
* are wrapped into a {@link org.cache2k.integration.CacheLoaderException}.
*/
public final Cache2kBuilder<K, V> exceptionPropagator(ExceptionPropagator<K> ep) {
config().setExceptionPropagator(wrapCustomizationInstance(ep));
return this;
}
/** Wraps to factory but passes on nulls. */
private static <T> CustomizationReferenceSupplier<T> wrapCustomizationInstance(T obj) {
if (obj == null) { return null; }
return new CustomizationReferenceSupplier<T>(obj);
}
/**
* Enables read through operation and sets a cache loader that provides the the
* cached data. By default read through is not enabled, which means
* the methods {@link Cache#get} and {@link Cache#peek} have identical behavior.
*
* @see CacheLoader for general discussion on cache loaders
*/
public final Cache2kBuilder<K, V> loader(FunctionalCacheLoader<K, V> l) {
config().setLoader(wrapCustomizationInstance(l));
return this;
}
/**
* Enables read through operation and sets a cache loader that provides the the
* cached data. By default read through is not enabled, which means
* the methods {@link Cache#get} and {@link Cache#peek} have identical behavior.
*
* @see CacheLoader for general discussion on cache loaders
*/
public final Cache2kBuilder<K, V> loader(CacheLoader<K, V> l) {
config().setLoader(wrapCustomizationInstance(l));
return this;
}
/**
* Enables read through operation and sets a cache loader that provides the the
* cached data. By default read through is not enabled, which means
* the methods {@link Cache#get} and {@link Cache#peek} have identical behavior.
*
* @see CacheLoader for general discussion on cache loaders
*/
public final Cache2kBuilder<K, V> loader(AdvancedCacheLoader<K, V> l) {
config().setAdvancedLoader(wrapCustomizationInstance(l));
return this;
}
/**
* Enables write through operation and sets a writer customization that gets
* called synchronously upon cache mutations. By default write through is not enabled.
*/
public final Cache2kBuilder<K, V> writer(CacheWriter<K, V> w) {
config().setWriter(wrapCustomizationInstance(w));
return this;
}
/**
* Add a listener. The listeners will be executed in a synchronous mode, meaning,
* further processing for an entry will stall until a registered listener is executed.
* The expiry will be always executed asynchronously.
*
* @throws IllegalArgumentException if an identical listener is already added.
* @param listener The listener to add
*/
public final Cache2kBuilder<K, V> addListener(CacheEntryOperationListener<K,V> listener) {
boolean _inserted = config().getListeners().add(wrapCustomizationInstance(listener));
if (!_inserted) {
throw new IllegalArgumentException("Listener already added");
}
return this;
}
/**
* A set of listeners. Listeners added in this collection will be
* executed in a asynchronous mode.
*
* @throws IllegalArgumentException if an identical listener is already added.
* @param listener The listener to add
*/
public final Cache2kBuilder<K,V> addAsyncListener(CacheEntryOperationListener<K,V> listener) {
boolean _inserted = config().getAsyncListeners().add(wrapCustomizationInstance(listener));
if (!_inserted) {
throw new IllegalArgumentException("Listener already added");
}
return this;
}
/**
* Set expiry policy to use.
*
* <p>If this is specified the maximum expiry time is still limited to the value in
* {@link #expireAfterWrite}. If {@link #expireAfterWrite(long, java.util.concurrent.TimeUnit)}
* is set to 0 then expiry calculation is not used, all entries expire immediately.
*
* <p>If no maximum expiry is specified via {@link #expireAfterWrite} at leas the
* {@link #resilienceDuration} needs to be specified, if resilience should be enabled.
*/
public final Cache2kBuilder<K, V> expiryPolicy(ExpiryPolicy<K, V> c) {
config().setExpiryPolicy(wrapCustomizationInstance(c));
return this;
}
/**
* When true, enable background refresh / refresh ahead. After the expiry time of a value is reached,
* the loader is invoked to fetch a fresh value. The old value will be returned by the cache, although
* it is expired, and will be replaced by the new value, once the loader is finished. In the case
* there are not enough loader threads available, the value will expire immediately and
* the next {@code get()} request will trigger the load.
*
* <p>Once refreshed, the entry is in a trail period. If it is not accessed until the next
* expiry, no refresh will be done and the entry expires regularly. This means that the
* time an entry stays within the trail period is determined by the configured expiry time
* or the the {@code ExpiryPolicy}. In case an entry is not accessed any more it needs to
* reach the expiry time twice before removed from the cache.
*
* <p>The number of threads used to do the refresh are configured via
* {@link #loaderThreadCount(int)}
*
* @see CacheLoader
* @see #loaderThreadCount(int)
* @see #prefetchExecutor(Executor)
*/
public final Cache2kBuilder<K, V> refreshAhead(boolean f) {
config().setRefreshAhead(f);
return this;
}
/**
* By default the expiry time is not exact, which means, a value might be visible a few
* milliseconds after the time of expiry. The time lag depends on the system load.
* Switching to true, means that values will not be visible when the time is reached that
* {@link ExpiryPolicy} returned.
*/
public final Cache2kBuilder<K, V> sharpExpiry(boolean f) {
config().setSharpExpiry(f);
return this;
}
/**
* If no separate executor is set via {@link #loaderExecutor(Executor)} the cache will
* create a separate thread pool used exclusively by it. Defines the maximum number of threads
* this cache should use for calls to the {@link CacheLoader}. The default is one thread
* per available CPU.
*
* <p>If a separate executor is defined the parameter has no effect.
*
* @see #loaderExecutor(Executor)
* @see #prefetchExecutor(Executor)
*/
public final Cache2kBuilder<K, V> loaderThreadCount(int v) {
config().setLoaderThreadCount(v);
return this;
}
/**
* Ensure that the cache value is stored via direct object reference and that
* no serialization takes place. Cache clients leveraging the fact that an in heap
* cache stores object references directly should set this value.
*
* <p>If this value is not set to true this means: The key and value objects need to have a
* defined serialization mechanism and the cache may choose to transfer off the heap.
* For cache2k version 1.0 this value has no effect. It should be
* used by application developers to future proof the applications with upcoming versions.
*/
public final Cache2kBuilder<K, V> storeByReference(boolean v) {
config().setStoreByReference(v);
return this;
}
/**
* If a loader exception happens, this is the time interval after a
* retry attempt is made. If not specified, 10% of {@link #maxRetryInterval}.
*/
public final Cache2kBuilder<K, V> retryInterval(long v, TimeUnit u) {
config().setRetryInterval(u.toMillis(v));
return this;
}
/**
* If a loader exception happens, this is the maximum time interval after a
* retry attempt is made. For retries an exponential backoff algorithm is used.
* It starts with the retry time and then increases the time to the maximum
* according to an exponential pattern.
*
* <p>By default identical to {@link #resilienceDuration}
*/
public final Cache2kBuilder<K, V> maxRetryInterval(long v, TimeUnit u) {
config().setMaxRetryInterval(u.toMillis(v));
return this;
}
/**
* Time span the cache will suppress loader exceptions if a value is available from
* a previous load. After the time span is passed the cache will start propagating
* loader exceptions. If {@link #suppressExceptions} is switched off, this setting
* has no effect.
*
* <p>Defaults to {@link #expireAfterWrite}. If {@link #suppressExceptions}
* is switched off, this setting has no effect.
*/
public final Cache2kBuilder<K, V> resilienceDuration(long v, TimeUnit u) {
config().setResilienceDuration(u.toMillis(v));
return this;
}
/**
* Sets a custom resilience policy to control the cache behavior in the presence
* of exceptions from the loader. A specified policy will be ignored if
* {@link #expireAfterWrite} is set to 0.
*/
public final Cache2kBuilder<K,V> resiliencePolicy(ResiliencePolicy<K,V> v) {
config().setResiliencePolicy(wrapCustomizationInstance(v));
return this;
}
/**
* Add a new configuration sub section.
*
* @see org.cache2k.configuration.ConfigurationWithSections
*/
public final Cache2kBuilder<K, V> with(ConfigurationSectionBuilder<? extends ConfigurationSection>... sectionBuilders) {
for (ConfigurationSectionBuilder<? extends ConfigurationSection> b : sectionBuilders) {
config().getSections().add(b.buildConfigurationSection());
}
return this;
}
/**
* To increase performance cache2k optimizes the eviction and does eviction in
* greater chunks. With strict eviction, the eviction is done for one entry
* as soon as the capacity constraint is met. This is primarily used for
* testing and evaluation purposes.
*/
public final Cache2kBuilder<K,V> strictEviction(boolean flag) {
config().setStrictEviction(flag);
return this;
}
/**
* When {@code true}, {@code null} values are allowed in the cache. In the default configuration
* {@code null} values are prohibited.
*
* <p>See the chapter in the user guide for details on {@code null} values.
*
* @see CacheLoader#load(Object)
* @see ExpiryPolicy#calculateExpiryTime(Object, Object, long, CacheEntry)
*/
public final Cache2kBuilder<K,V> permitNullValues(boolean flag) {
config().setPermitNullValues(flag);
return this;
}
/**
* By default statistic gathering is enabled. Switching this to {@code true} will disable all statistics
* that have significant overhead. The cache will also no be accessible via JMX.
*/
public final Cache2kBuilder<K,V> disableStatistics(boolean flag) {
config().setDisableStatistics(flag);
return this;
}
/**
* Disable that the last modification time is available at {@link CacheEntry#getLastModification()}.
* This also disables the recording of the average load time that can be retrieved via JMX.
*
* <p>When expiry is used, this parameter has no effect. The last modification time may be used
* by the loaders, expiry policy or resilience policy.
*/
public final Cache2kBuilder<K,V> disableLastModificationTime(boolean flag) {
config().setDisableLastModificationTime(flag);
return this;
}
/**
* When {@code true}, optimize for high core counts and applications that do lots of mutations
* in the cache. When switched on, the cache will occupy slightly more memory and eviction efficiency
* may drop slightly. This overhead is negligible for big cache sizes (100K and more).
*
* <p>Typical interactive do not need to enable this. May improve concurrency for applications
* that utilize all cores and cache operations account for most CPU cycles.
*/
public final Cache2kBuilder<K,V> boostConcurrency(boolean f) {
config().setBoostConcurrency(f);
return this;
}
/**
* Thread pool / executor service to use for asynchronous load operations. If no executor is specified
* the cache will create a thread pool, if needed.
*
* @see #loaderThreadCount(int)
* @see #prefetchExecutor(Executor)
*/
public final Cache2kBuilder<K,V> loaderExecutor(Executor v) {
config().setLoaderExecutor(new CustomizationReferenceSupplier<Executor>(v));
return this;
}
/**
* Thread pool / executor service to use for refresh ahead and prefetch operations. If not specified the
* same refresh ahead operation will use the thread pool defined by {@link #loaderExecutor(Executor)}
* or a cache local pool is created.
*
* @see #loaderThreadCount(int)
* @see #loaderExecutor(Executor)
*/
public final Cache2kBuilder<K,V> prefetchExecutor(Executor v) {
config().setPrefetchExecutor(new CustomizationReferenceSupplier<Executor>(v));
return this;
}
/**
* Executor for asynchronous listeners. If no executor is specified, an internal
* executor is used that has unbounded thread capacity.
*
* @see #addAsyncListener(CacheEntryOperationListener)
*/
public final Cache2kBuilder<K,V> asyncListenerExecutor(Executor v) {
config().setAsyncListenerExecutor(new CustomizationReferenceSupplier<Executor>(v));
return this;
}
/**
* Returns the configuration object this builder operates on. Changes to the configuration also
* will influence the created cache when {@link #build()} is called. The method does not
* return the effective configuration if additional external/XML configuration is present, since
* this is applied when {@code build} is called. On the other hand, the method can be used
* to inspect the effective configuration after {@code build} completed.
*
* @return configuration objects with the parameters set in the builder.
*/
public final Cache2kConfiguration<K,V> toConfiguration() {
return config();
}
/**
* Builds a cache with the specified configuration parameters.
* The builder reused to build caches with similar or identical
* configuration. The builder is not thread safe.
*
* @throws IllegalArgumentException if a cache of the same name is already active in the cache manager
*/
public final Cache<K, V> build() {
return CacheManager.PROVIDER.createCache(manager, config());
}
}