All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.cache2k.Cache2kBuilder Maven / Gradle / Ivy

There is a newer version: 2.6.1.Final
Show newest version
package org.cache2k;

/*
 * #%L
 * cache2k API
 * %%
 * Copyright (C) 2000 - 2016 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.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.ResiliencePolicy;
import org.cache2k.spi.Cache2kCoreProvider;
import org.cache2k.spi.SingleProviderResolver;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.concurrent.TimeUnit;

/**
 * Builder to create a {@link Cache} instance. The usage is:
 *
 * 
{@code
 *    Cache> c =
 *      new Cache2kBuilder>() {}
 *        .name("myCache")
 *        .eternal(true)
 *        .build();
 * }
* *

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()}. * *

To create a cache from a known configuration in a specified cache manager, use: * *

{@code
 *   CacheManager manager = ...
 *   CacheConfiguration> config = ...
 *
 *   Cache> c =
 *     Cache2kBuilder.of(config)
 *       .manager(manager)
 *       .build();
 * }
* *

To create a cache without type parameters or {@code Cache}, use {@link Cache2kBuilder#forUnknownTypes()}. * * @author Jens Wilke * @since 1.0 */ public class Cache2kBuilder implements Cloneable { private static final Cache2kCoreProvider CORE_PROVIDER; private static final String MSG_NO_TYPES = "Use Cache2kBuilder.forUnknownTypes(), to construct a builder with no key and value types"; static { CORE_PROVIDER = SingleProviderResolver.getInstance().resolve(Cache2kCoreProvider.class); } /** * 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 of(new Cache2kConfiguration()); } /** * Create a new cache builder if key and value types are classes with no generic parameters. */ public static Cache2kBuilder of(Class _keyType, Class _valueType) { return of(Cache2kConfiguration.of(_keyType, _valueType)); } /** * Create a builder from the configuration. */ public static Cache2kBuilder of(Cache2kConfiguration c) { Cache2kBuilder cb = new Cache2kBuilder(c); return cb; } Cache2kConfiguration config; private CacheManager manager; private Cache2kBuilder(Cache2kConfiguration cfg) { config = cfg; } /** * Constructor to override for the usage pattern: * *

{@code
   *    Cache> c =
   *      new Cache2kBuilder>() {}
   *        .name("myCache")
   *        .eternal(true)
   *        .build();
   * }
* * 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(); CacheType _keyType = (CacheType) CacheTypeCapture.of(_types[0]).getBeanRepresentation(); CacheType _valueType = (CacheType) CacheTypeCapture.of(_types[1]).getBeanRepresentation(); if (Object.class.equals(_keyType.getType()) && Object.class.equals(_valueType.getType())) { throw new IllegalArgumentException(MSG_NO_TYPES); } config = Cache2kConfiguration.of(_keyType, _valueType); } /** * Sets the key type to use. * * @throws IllegalArgumentException if key type is already set */ public final Cache2kBuilder keyType(Class t) { config.setKeyType(t); return (Cache2kBuilder) this; } /** * Sets the value type to use. * * @throws IllegalArgumentException if value type is already set */ public final Cache2kBuilder valueType(Class t) { config.setValueType(t); return (Cache2kBuilder) this; } /** * Sets the key type to use. * * @throws IllegalArgumentException if key type is already set */ public final Cache2kBuilder keyType(CacheType t) { config.setKeyType(t); return (Cache2kBuilder) this; } /** * Sets the value type to use. * * @throws IllegalArgumentException if value type is already set */ public final Cache2kBuilder valueType(CacheType t) { config.setValueType(t); return (Cache2kBuilder) this; } /** * Constructs a cache name out of the class name and fieldname. * *

See {@link #name(String)} for a general discussion about cache names. * * @see #name(String) */ public final Cache2kBuilder name(Class _class, String _fieldName) { config.setName(_class.getName() + "." + _fieldName); return this; } /** * Sets a cache name from the fully qualified class name. * *

See {@link #name(String)} for a general discussion about cache names. * * @see #name(String) */ public final Cache2kBuilder name(Class _class) { config.setName(_class.getName()); return this; } /** * The manager, the created cache will belong to. */ public final Cache2kBuilder manager(CacheManager m) { manager = m; 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, to register JMX beans. Another usage is derive a filename for a persistence * cache. * *

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 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 '_' as prefix to separate the names from the * usual class name space. * *

In case of a name collision the cache is generating a unique name by adding a counter value. * This behavior may change. * *

Allowed characters for a cache name, are URL non-reserved characters, * these are: [A-Z], [a-z], [0-9] and [~-_.], * see RFC3986 as well as the characters: [,()]. * 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. * *

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 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 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. The default value is: 2000. */ public final Cache2kBuilder entryCapacity(long v) { config.setEntryCapacity(v); return this; } /** * Cached values do not expire by time. Entries will need to be removed from the * cache explicitly or evicted if capacity constraints are reached. * *

Exceptions: If there is no explicit expiry configured for exceptions * with {@link #retryInterval(long, TimeUnit)}, exceptions will * not be cached and expire immediately. */ public final Cache2kBuilder eternal(boolean v) { config.setEternal(v); return this; } /** * If an exceptions gets thrown by the cache loader, suppress it if there is * a previous value. When this is active, and an exception was suppressed * the expiry is determined by {@link #retryInterval(long, TimeUnit)}. * *

Setting this to false, will disable suppression or caching (aka resilience). * Default value: true * *

Additional information can be found under resilience in * the documentation. */ public final Cache2kBuilder 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)}. * *

If an {@link ExpiryPolicy} is specified, the maximum expiry duration * will not exceed the value that is specified here. * *

A value of 0 means every entry should expire immediately. */ public final Cache2kBuilder expireAfterWrite(long v, TimeUnit u) { config.setExpireAfterWriteMillis(u.toMillis(v)); return this; } public final Cache2kBuilder exceptionPropagator(ExceptionPropagator ep) { config.setExceptionPropagator(ep); return this; } public final Cache2kBuilder loader(CacheLoader l) { config.setLoader(l); return this; } public final Cache2kBuilder loader(AdvancedCacheLoader l) { config.setAdvancedLoader(l); return this; } public final Cache2kBuilder writer(CacheWriter w) { config.setWriter(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 addListener(CacheEntryOperationListener listener) { boolean _inserted = config.getListeners().add(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 synchronous mode, meaning, further processing for * an entry will stall until a registered listener is executed. * * @throws IllegalArgumentException if an identical listener is already added. * @param listener The listener to add */ public final Cache2kBuilder addAsyncListener(CacheEntryOperationListener listener) { boolean _inserted = config.getAsyncListeners().add(listener); if (!_inserted) { throw new IllegalArgumentException("Listener already added"); } return this; } /** * Set expiry policy to use. * *

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. * *

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 expiryPolicy(ExpiryPolicy c) { config.setExpiryPolicy(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. * *

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. * *

The number of threads used to do the refresh are configured via * {@link #loaderThreadCount(int)} * * @see CacheLoader * @see #loaderThreadCount(int) */ public final Cache2kBuilder 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 timing depends on the system load. * Switching to true, means an entry is not visible exactly at and after the time of * expiry. */ public final Cache2kBuilder sharpExpiry(boolean f) { config.setSharpExpiry(f); return this; } /** * Maximum number of threads this cache should use for calls to the {@link CacheLoader} */ public final Cache2kBuilder 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. * *

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 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 retryInterval(long v, TimeUnit u) { config.setRetryIntervalMillis(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. * *

By default identical to {@link #resilienceDuration} */ public final Cache2kBuilder maxRetryInterval(long v, TimeUnit u) { config.setMaxRetryIntervalMillis(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. * *

Defaults to {@link #expireAfterWrite}. If {@link #suppressExceptions} * is switched off, this setting has no effect. */ public final Cache2kBuilder resilienceDuration(long v, TimeUnit u) { config.setResilienceDurationMillis(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 resiliencePolicy(ResiliencePolicy v) { config.setResiliencePolicy(v); return this; } /** * Add a new configuration sub section. */ public final Cache2kBuilder with(ConfigurationSectionBuilder... sectionBuilders) { for (ConfigurationSectionBuilder 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 strictEviction(boolean flag) { config.setStrictEviction(flag); return this; } /** * By default cache2k allows the use of null in a value. Setting * this to true will make the cache throw an exception when * a null value is inserted. */ public final Cache2kBuilder permitNullValues(boolean flag) { config.setPermitNullValues(flag); return this; } /** * By default statistic gathering is enabled. Set true to disable statistics. */ public final Cache2kBuilder disableStatistics(boolean flag) { config.setDisableStatistics(flag); return this; } /** * Number of eviction segments. The default is one or two if the available processor * count is more than one. In case the workload has lots of concurrent inserts or eviction * the segment count may be increased if the cache eviction becomes the bottle neck. * A value higher then the processor count is ineffective. Setting a higher value has * a negative impact on the eviction efficiency. There will be hardly any application with * a little positive effect when this parameter is set. Usual applications that do mostly * concurrent reads, do not need an increase. */ public final Cache2kBuilder evictionSegmentCount(int v) { config.setEvictionSegmentCount(v); return this; } public final Cache2kConfiguration 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. */ public final Cache build() { return CORE_PROVIDER.createCache(manager, config); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy