001package org.cache2k;
002
003/*
004 * #%L
005 * cache2k API
006 * %%
007 * Copyright (C) 2000 - 2016 headissue GmbH, Munich
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 * 
013 *      http://www.apache.org/licenses/LICENSE-2.0
014 * 
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022
023import org.cache2k.configuration.Cache2kConfiguration;
024import org.cache2k.configuration.CacheTypeCapture;
025import org.cache2k.configuration.CacheType;
026import org.cache2k.configuration.ConfigurationSection;
027import org.cache2k.configuration.ConfigurationSectionBuilder;
028import org.cache2k.configuration.CustomizationReferenceSupplier;
029import org.cache2k.expiry.ExpiryPolicy;
030import org.cache2k.event.CacheEntryOperationListener;
031import org.cache2k.integration.AdvancedCacheLoader;
032import org.cache2k.integration.CacheLoader;
033import org.cache2k.integration.CacheWriter;
034import org.cache2k.integration.ExceptionPropagator;
035import org.cache2k.integration.ResiliencePolicy;
036
037import java.lang.reflect.ParameterizedType;
038import java.lang.reflect.Type;
039import java.util.concurrent.Executor;
040import java.util.concurrent.TimeUnit;
041
042/**
043 * Builder to create a {@link Cache} instance. The usage is:
044 *
045 * <pre>{@code
046 *    Cache<Long, List<String>> c =
047 *      new Cache2kBuilder<Long, List<String>>() {}
048 *        .name("myCache")
049 *        .eternal(true)
050 *        .build();
051 * }</pre>
052 *
053 * <p>Caches belong to a cache manager. If no cache manager is set explicitly via {@link #manager} the
054 * default cache manager will be used, as defined by {@link CacheManager#getInstance()}.
055 *
056 * <p>To create a cache from a known configuration in a specified cache manager, use:
057 *
058 * <pre>{@code
059 *   CacheManager manager = ...
060 *   CacheConfiguration<Long, List<String>> config = ...
061 *
062 *   Cache<Long, List<String>> c =
063 *     Cache2kBuilder.of(config)
064 *       .manager(manager)
065 *       .build();
066 * }</pre>
067 *
068 * <p>To create a cache without type parameters or {@code Cache<Object,Object>}, use {@link Cache2kBuilder#forUnknownTypes()}.
069 *
070 * @author Jens Wilke
071 * @since 1.0
072 */
073public class Cache2kBuilder<K, V> {
074
075  private static final String MSG_NO_TYPES = "Use Cache2kBuilder.forUnknownTypes(), to construct a builder with no key and value types";
076
077  /**
078   * Create a new cache builder for a cache that has no type restrictions
079   * or to set the type information later via the builder methods {@link #keyType} or
080   * {@link #valueType}.
081   */
082  public static Cache2kBuilder forUnknownTypes() {
083    return new Cache2kBuilder(null, null);
084  }
085
086  /**
087   * Create a new cache builder for key and value types are classes with no generic parameters.
088   *
089   * @see #keyType(Class)
090   * @see #valueType(Class)
091   */
092  public static <K,T> Cache2kBuilder<K,T> of(Class<K> _keyType, Class<T> _valueType) {
093    return new Cache2kBuilder<K, T>(CacheTypeCapture.of(_keyType), CacheTypeCapture.of(_valueType));
094  }
095
096  /**
097   * Create a builder from the configuration.
098   */
099  public static <K,T> Cache2kBuilder<K, T> of(Cache2kConfiguration<K, T> c) {
100    Cache2kBuilder<K,T> cb = new Cache2kBuilder<K, T>(c);
101    return cb;
102  }
103
104  private CacheType<K> keyType;
105  private CacheType<V> valueType;
106  private Cache2kConfiguration<K,V> config = null;
107  private CacheManager manager = null;
108
109  private Cache2kBuilder(Cache2kConfiguration<K,V> cfg) {
110    withConfig(cfg);
111  }
112
113  /**
114   * Constructor to override for the usage pattern:
115   *
116   * <pre>{@code
117   *    Cache<Long, List<String>> c =
118   *      new Cache2kBuilder<Long, List<String>>() {}
119   *        .name("myCache")
120   *        .eternal(true)
121   *        .build();
122   * }</pre>
123   *
124   * The builder extracts the generic type parameters from the anonymous subclass.
125   */
126  @SuppressWarnings("unchecked")
127  protected Cache2kBuilder() {
128    Type t = this.getClass().getGenericSuperclass();
129    if (!(t instanceof ParameterizedType)) {
130      throw new IllegalArgumentException(MSG_NO_TYPES);
131    }
132    Type[] _types = ((ParameterizedType) t).getActualTypeArguments();
133    keyType = (CacheType<K>) CacheTypeCapture.of(_types[0]).getBeanRepresentation();
134    valueType = (CacheType<V>) CacheTypeCapture.of(_types[1]).getBeanRepresentation();
135    if (Object.class.equals(keyType.getType()) &&
136      Object.class.equals(valueType.getType())) {
137      throw new IllegalArgumentException(MSG_NO_TYPES);
138    }
139  }
140
141  private Cache2kBuilder(CacheType<K> _keyType, CacheType<V> _valueType) {
142    keyType = _keyType;
143    valueType = _valueType;
144  }
145
146  private void withConfig(Cache2kConfiguration<K,V> cfg) {
147    config = cfg;
148  }
149
150  private Cache2kConfiguration<K, V> config() {
151    if (config == null) {
152      if (manager == null) {
153        manager = CacheManager.getInstance();
154      }
155      config = CacheManager.PROVIDER.getDefaultConfiguration(manager);
156      if (keyType != null) {
157        config.setKeyType(keyType);
158      }
159      if (valueType != null) {
160        config.setValueType(valueType);
161      }
162    }
163    return config;
164  }
165
166  /**
167   * The manager, the created cache will belong to. If this is set, it must be the
168   * first method called.
169   *
170   * @param manager The manager the created cache should belong to,
171   *                or {@code null} if the default cache manager should be used
172   * @throws IllegalStateException if the manager is not provided immediately after the builder is created.
173   */
174  public final Cache2kBuilder<K, V> manager(CacheManager manager) {
175    if (this.manager != null) {
176      throw new IllegalStateException("manager() must be first operation on builder.");
177    }
178    this.manager = manager;
179    return this;
180  }
181
182  /**
183   * The used type of the cache key. A suitable cache key must provide a useful
184   * {@code equals} and {@code hashCode} method. Arrays are not valid for cache keys.
185   *
186   * @throws IllegalArgumentException in case the type is illegal
187   * @see CacheType for a general discussion on types
188   */
189  public final <K2> Cache2kBuilder<K2, V> keyType(Class<K2> t) {
190    config().setKeyType(t);
191    return (Cache2kBuilder<K2, V>) this;
192  }
193
194  /**
195   * Sets the value type to use. Arrays are not supported.
196   *
197   * @throws IllegalArgumentException in case the type is illegal
198   * @see CacheType for a general discussion on types
199   */
200  public final <T2> Cache2kBuilder<K, T2> valueType(Class<T2> t) {
201    config().setValueType(t);
202    return (Cache2kBuilder<K, T2>) this;
203  }
204
205  /**
206   * The used type of the cache key. A suitable cache key must provide a useful
207   * {@code equals} and {@code hashCode} method. Arrays are not valid for cache keys.
208   *
209   * @throws IllegalArgumentException in case the type is illegal
210   * @see CacheType for a general discussion on types
211   */
212  public final <K2> Cache2kBuilder<K2, V> keyType(CacheType<K2> t) {
213    config().setKeyType(t);
214    return (Cache2kBuilder<K2, V>) this;
215  }
216
217  /**
218   * Sets the value type to use. Arrays are not supported.
219   *
220   * @throws IllegalArgumentException in case the type is illegal
221   * @see CacheType for a general discussion on types
222   */
223  public final <T2> Cache2kBuilder<K, T2> valueType(CacheType<T2> t) {
224    config().setValueType(t);
225    return (Cache2kBuilder<K, T2>) this;
226  }
227
228  /**
229   * Constructs a cache name out of the class name, a field name and a unique name identifying the
230   * component in the application. Result example: {@code webImagePool~com.example.ImagePool.id2Image}
231   *
232   * <p>See {@link #name(String)} for a general discussion about cache names.
233   *
234   * @param _uniqueName unique name differentiating multiple components of the same type.
235   *                    May be {@code null}.
236   * @see #name(String)
237   */
238  public final Cache2kBuilder<K, V> name(String _uniqueName, Class<?> _class, String _fieldName) {
239    if (_fieldName == null) {
240      throw new NullPointerException();
241    }
242    if (_uniqueName == null) {
243      return name(_class, _fieldName);
244    }
245    config().setName(_uniqueName + '~' + _class.getName() + "." + _fieldName);
246    return this;
247  }
248
249  /**
250   * Constructs a cache name out of the class name and field name. Result example:
251   * {@code com.example.ImagePool.id2Image}
252   *
253   * <p>See {@link #name(String)} for a general discussion about cache names.
254   *
255   * @see #name(String)
256   */
257  public final Cache2kBuilder<K, V> name(Class<?> _class, String _fieldName) {
258    if (_fieldName == null) {
259      throw new NullPointerException();
260    }
261    config().setName(_class.getName() + "." + _fieldName);
262    return this;
263  }
264
265  /**
266   * Sets a cache name from the fully qualified class name.
267   *
268   * <p>See {@link #name(String)} for a general discussion about cache names.
269   *
270   * @see #name(String)
271   */
272  public final Cache2kBuilder<K, V> name(Class<?> _class) {
273    config().setName(_class.getName());
274    return this;
275  }
276
277  /**
278   * Sets the name of a cache. If a name is specified it must be ensured it is unique within
279   * the cache manager. Cache names are used at several places to have a unique ID of a cache.
280   * For example, for referencing additional configuration or to register JMX beans.
281   *
282   * <p>If a name is not specified the cache generates a name automatically. The name is
283   * inferred from the call stack trace and contains the simple class name, the method and
284   * the line number of the of the caller to <code>build()</code>. The name also contains
285   * a random number. Automatically generated names don't allow reliable management, logging and
286   * additional configuration of caches. If no name is set, {@link #build()} will always create
287   * a new cache with a new unique name within the cache manager. Automatically generated
288   * cache names start with the character <code>'_'</code> as prefix to separate the names from the
289   * usual class name space.
290   *
291   * <p>In case of a name collision the cache is generating a unique name by adding a counter value.
292   * This behavior may change.
293   *
294   * <p>Allowed characters for a cache name, are URL non-reserved characters,
295   * these are: <code>[A-Z]</code>, <code>[a-z]</code>, <code>[0-9]</code> and <code>[~-_.]</code>,
296   * see RFC3986 as well as the characters: <code>[()]</code>. The characters <code>[@, ]</code> are supported
297   * as well, but should be avoided.
298   *
299   * <p>The reason for restricting the characters in names, is that the names may be used to derive
300   * other resource names from it, e.g. for file based storage. The cache might not enforce the allowed
301   * character set for efficiency reasons.
302   *
303   * <p>The method is overloaded with variants to provide a naming convention of names.
304   *
305   * <p>For brevity within log messages and other displays the cache name may be
306   * shortened if the manager name is included as prefix.
307   *
308   * @see Cache#getName()
309   */
310  public final Cache2kBuilder<K, V> name(String v) {
311    config().setName(v);
312    return this;
313  }
314
315  /**
316   * Expired data is kept in the cache until the entry is evicted. This consumes memory,
317   * but if the data is accessed again the previous data can be used by the cache loader
318   * for optimizing (e.g. if-modified-since for a HTTP request). Default value: false
319   *
320   * @see AdvancedCacheLoader
321   */
322  public final Cache2kBuilder<K, V> keepDataAfterExpired(boolean v) {
323    config().setKeepDataAfterExpired(v);
324    return this;
325  }
326
327  /**
328   * The maximum number of entries hold by the cache. When the maximum size is reached, by
329   * inserting new entries, the cache eviction algorithm will remove one or more entries
330   * to keep the size within the configured limit.
331   *
332   * <p>The value {@code Long.MAX_VALUE} means the capacity is not limited.
333   *
334   * <p>The default value is: 2000. The default value is conservative, so the application
335   * will usually run stable without tuning or setting a reasonable size.
336   */
337  public final Cache2kBuilder<K, V> entryCapacity(long v) {
338    config().setEntryCapacity(v);
339    return this;
340  }
341
342  /**
343   * When set to true, cached values do not expire by time. Entries will need to be removed
344   * from the cache explicitly or will be evicted if capacity constraints are reached.
345
346   * <p>Setting eternal to false signals that the data should expire, but there is no
347   * predefined expiry value at programmatic level. This value needs to be set by other
348   * means, e.g. within a configuration file.
349   *
350   * <p>The default behavior of the cache is identical to the setting eternal, meaning no
351   * expiry.
352   *
353   * <p>Exceptions: If set to eternal with default setting and if there is no
354   * explicit expiry configured for exceptions with {@link #retryInterval(long, TimeUnit)},
355   * exceptions will not be cached and expire immediately.
356   *
357   * @throws IllegalArgumentException in case a previous setting is reset
358   */
359  public final Cache2kBuilder<K, V> eternal(boolean v) {
360    config().setEternal(v);
361    return this;
362  }
363
364  /**
365   * If an exceptions gets thrown by the cache loader, suppress it if there is
366   * a previous value. When this is active, and an exception was suppressed
367   * the expiry is determined by {@link #retryInterval(long, TimeUnit)}.
368   *
369   * <p>Setting this to false, will disable suppression or caching (aka resilience).
370   * Default value: true
371   *
372   * <p>Additional information can be found under <b>resilience</b> in
373   * the documentation.
374   */
375  public final Cache2kBuilder<K, V> suppressExceptions(boolean v) {
376    config().setSuppressExceptions(v);
377    return this;
378  }
379
380
381  /**
382   * Time duration after insert or updated an cache entry expires.
383   * To switch off time based expiry use {@link #eternal(boolean)}.
384   *
385   * <p>If an {@link ExpiryPolicy} is specified, the maximum expiry duration
386   * will not exceed the value that is specified here.
387   *
388   * <p>A value of {@code 0} means every entry should expire immediately. Low values or
389   * {@code 0} together with read through operation mode with a {@link CacheLoader} should be
390   * avoided in production environments.
391   *
392   * @throws IllegalArgumentException if {@link #eternal(boolean)} was set to true
393   */
394  public final Cache2kBuilder<K, V> expireAfterWrite(long v, TimeUnit u) {
395    config().setExpireAfterWrite(u.toMillis(v));
396    return this;
397  }
398
399  public final Cache2kBuilder<K, V> exceptionPropagator(ExceptionPropagator<K> ep) {
400    config().setExceptionPropagator(wrapCustomizationInstance(ep));
401    return this;
402  }
403
404  /** Wraps to factory but passes on nulls. */
405  private static <T> CustomizationReferenceSupplier<T> wrapCustomizationInstance(T obj) {
406    if (obj == null) { return null; }
407    return new CustomizationReferenceSupplier<T>(obj);
408  }
409
410  public final Cache2kBuilder<K, V> loader(CacheLoader<K, V> l) {
411    config().setLoader(wrapCustomizationInstance(l));
412    return this;
413  }
414
415  public final Cache2kBuilder<K, V> loader(AdvancedCacheLoader<K, V> l) {
416    config().setAdvancedLoader(wrapCustomizationInstance(l));
417    return this;
418  }
419
420  public final Cache2kBuilder<K, V> writer(CacheWriter<K, V> w) {
421    config().setWriter(wrapCustomizationInstance(w));
422    return this;
423  }
424
425  /**
426   * Add a listener. The listeners  will be executed in a synchronous mode, meaning,
427   * further processing for an entry will stall until a registered listener is executed.
428   * The expiry will be always executed asynchronously.
429   *
430   * @throws IllegalArgumentException if an identical listener is already added.
431   * @param listener The listener to add
432   */
433  public final Cache2kBuilder<K, V> addListener(CacheEntryOperationListener<K,V> listener) {
434    boolean _inserted = config().getListeners().add(wrapCustomizationInstance(listener));
435    if (!_inserted) {
436      throw new IllegalArgumentException("Listener already added");
437    }
438    return this;
439  }
440
441  /**
442   * A set of listeners. Listeners added in this collection will be
443   * executed in a synchronous mode, meaning, further processing for
444   * an entry will stall until a registered listener is executed.
445   *
446   * @throws IllegalArgumentException if an identical listener is already added.
447   * @param listener The listener to add
448   */
449  public final Cache2kBuilder<K,V> addAsyncListener(CacheEntryOperationListener<K,V> listener) {
450    boolean _inserted = config().getAsyncListeners().add(wrapCustomizationInstance(listener));
451    if (!_inserted) {
452      throw new IllegalArgumentException("Listener already added");
453    }
454    return this;
455  }
456
457  /**
458   * Set expiry policy to use.
459   *
460   * <p>If this is specified the maximum expiry time is still limited to the value in
461   * {@link #expireAfterWrite}. If {@link #expireAfterWrite(long, java.util.concurrent.TimeUnit)}
462   * is set to 0 then expiry calculation is not used, all entries expire immediately.
463   *
464   * <p>If no maximum expiry is specified via {@link #expireAfterWrite} at leas the
465   * {@link #resilienceDuration} needs to be specified, if resilience should be enabled.
466   */
467  public final Cache2kBuilder<K, V> expiryPolicy(ExpiryPolicy<K, V> c) {
468    config().setExpiryPolicy(wrapCustomizationInstance(c));
469    return this;
470  }
471
472  /**
473   * When true, enable background refresh / refresh ahead. After the expiry time of a value is reached,
474   * the loader is invoked to fetch a fresh value. The old value will be returned by the cache, although
475   * it is expired, and will be replaced by the new value, once the loader is finished. In the case
476   * there are not enough loader threads available, the value will expire immediately and
477   * the next {@code get()} request will trigger the load.
478   *
479   * <p>Once refreshed, the entry is in a trail period. If it is not accessed until the next
480   * expiry, no refresh will be done and the entry expires regularly. This means that the
481   * time an entry stays within the trail period is determined by the configured expiry time
482   * or the the {@code ExpiryPolicy}. In case an entry is not accessed any more it needs to
483   * reach the expiry time twice before removed from the cache.
484   *
485   * <p>The number of threads used to do the refresh are configured via
486   * {@link #loaderThreadCount(int)}
487   *
488   * @see CacheLoader
489   * @see #loaderThreadCount(int)
490   */
491  public final Cache2kBuilder<K, V> refreshAhead(boolean f) {
492    config().setRefreshAhead(f);
493    return this;
494  }
495
496  /**
497   * By default the expiry time is not exact, which means, a value might be visible a few
498   * milliseconds after the time of expiry. The time lag depends on the system load.
499   * Switching to true, means that values will not be visible when the time is reached that
500   * {@link ExpiryPolicy} returned.
501   */
502  public final Cache2kBuilder<K, V> sharpExpiry(boolean f) {
503    config().setSharpExpiry(f);
504    return this;
505  }
506
507  /**
508   * If no separate executor is set via {@link #loaderExecutor(Executor)} the cache will
509   * create a separate thread pool used exclusively by it. Defines the maximum number of threads
510   * this cache should use for calls to the {@link CacheLoader}. The default is one thread
511   * per available CPU.
512   *
513   * <p>If a separate executor is defined the parameter has no effect.
514   *
515   * @see #loaderExecutor(Executor)
516   * @see #prefetchExecutor(Executor)
517   */
518  public final Cache2kBuilder<K, V> loaderThreadCount(int v) {
519    config().setLoaderThreadCount(v);
520    return this;
521  }
522
523  /**
524   * Ensure that the cache value is stored via direct object reference and that
525   * no serialization takes place. Cache clients leveraging the fact that an in heap
526   * cache stores object references directly should set this value.
527   *
528   * <p>If this value is not set to true this means: The key and value objects need to have a
529   * defined serialization mechanism and the cache may choose to transfer off the heap.
530   * For cache2k version 1.0 this value has no effect. It should be
531   * used by application developers to future proof the applications with upcoming versions.
532   */
533  public final Cache2kBuilder<K, V> storeByReference(boolean v) {
534    config().setStoreByReference(v);
535    return this;
536  }
537
538  /**
539   * If a loader exception happens, this is the time interval after a
540   * retry attempt is made. If not specified, 10% of {@link #maxRetryInterval}.
541   */
542  public final Cache2kBuilder<K, V> retryInterval(long v, TimeUnit u) {
543    config().setRetryInterval(u.toMillis(v));
544    return this;
545  }
546
547  /**
548   * If a loader exception happens, this is the maximum time interval after a
549   * retry attempt is made. For retries an exponential backoff algorithm is used.
550   * It starts with the retry time and then increases the time to the maximum
551   * according to an exponential pattern.
552   *
553   * <p>By default identical to {@link #resilienceDuration}
554   */
555  public final Cache2kBuilder<K, V> maxRetryInterval(long v, TimeUnit u) {
556    config().setMaxRetryInterval(u.toMillis(v));
557    return this;
558  }
559
560  /**
561   * Time span the cache will suppress loader exceptions if a value is available from
562   * a previous load. After the time span is passed the cache will start propagating
563   * loader exceptions. If {@link #suppressExceptions} is switched off, this setting
564   * has no effect.
565   *
566   * <p>Defaults to {@link #expireAfterWrite}. If {@link #suppressExceptions}
567   * is switched off, this setting has no effect.
568   */
569  public final Cache2kBuilder<K, V> resilienceDuration(long v, TimeUnit u) {
570    config().setResilienceDuration(u.toMillis(v));
571    return this;
572  }
573
574  /**
575   * Sets a custom resilience policy to control the cache behavior in the presence
576   * of exceptions from the loader. A specified policy will be ignored if
577   * {@link #expireAfterWrite} is set to 0.
578   */
579  public final Cache2kBuilder<K,V> resiliencePolicy(ResiliencePolicy<K,V> v) {
580    config().setResiliencePolicy(wrapCustomizationInstance(v));
581    return this;
582  }
583
584  /**
585   * Add a new configuration sub section.
586   *
587   * @see org.cache2k.configuration.ConfigurationWithSections
588   */
589  public final Cache2kBuilder<K, V> with(ConfigurationSectionBuilder<? extends ConfigurationSection>... sectionBuilders) {
590    for (ConfigurationSectionBuilder<? extends ConfigurationSection> b : sectionBuilders) {
591      config().getSections().add(b.buildConfigurationSection());
592    }
593    return this;
594  }
595
596  /**
597   * To increase performance cache2k optimizes the eviction and does eviction in
598   * greater chunks. With strict eviction, the eviction is done for one entry
599   * as soon as the capacity constraint is met. This is primarily used for
600   * testing and evaluation purposes.
601   */
602  public final Cache2kBuilder<K,V> strictEviction(boolean flag) {
603    config().setStrictEviction(flag);
604    return this;
605  }
606
607  /**
608   * When {@code true}, {@code null} values are allowed in the cache. In the default configuration
609   * {@code null} values are prohibited.
610   *
611   * <p>See the chapter in the user guide for details on {@code null} values.
612   *
613   * @see CacheLoader#load(Object)
614   * @see ExpiryPolicy#calculateExpiryTime(Object, Object, long, CacheEntry)
615   */
616  public final Cache2kBuilder<K,V> permitNullValues(boolean flag) {
617    config().setPermitNullValues(flag);
618    return this;
619  }
620
621  /**
622   * By default statistic gathering is enabled. Set true to disable statistics. Disabling statistics
623   * will minimize overhead and switch off any counters that are present for informational purposes only.
624   * Counters that don't have a significant overhead or are maintained in any case are still available.
625   * The setting doesn't affect whether JMX values are exposed or not.
626   */
627  public final Cache2kBuilder<K,V> disableStatistics(boolean flag) {
628    config().setDisableStatistics(flag);
629    return this;
630  }
631
632  /**
633   * Number of eviction segments. The default is one or two if the available processor
634   * count is more than one. In case the workload has lots of concurrent inserts or eviction
635   * the segment count may be increased if the cache eviction becomes the bottle neck.
636   * A value higher then the processor count is ineffective. Setting a higher value has
637   * a negative impact on the eviction efficiency. There will be hardly any application with
638   * a little positive effect when this parameter is set. Usual applications that do mostly
639   * concurrent reads, do not need an increase.
640   */
641  public final Cache2kBuilder<K,V> evictionSegmentCount(int v) {
642    config().setEvictionSegmentCount(v);
643    return this;
644  }
645
646  /**
647   * Thread pool / executor service to use for asynchronous load operations. If no executor is specified
648   * the cache will create a thread pool, if needed.
649   *
650   * @see #loaderThreadCount(int)
651   * @see #prefetchExecutor(Executor)
652   */
653  public final Cache2kBuilder<K,V> loaderExecutor(Executor v) {
654    config().setLoaderExecutor(new CustomizationReferenceSupplier<Executor>(v));
655    return this;
656  }
657
658  /**
659   * Thread pool / executor service to use for refresh ahead and prefetch operations. If not specified the
660   * same refresh ahead operation will use the thread pool defined by {@link #loaderExecutor(Executor)}
661   * or a cache local pool is created.
662   *
663   * @see #loaderThreadCount(int)
664   * @see #loaderExecutor(Executor)
665   */
666  public final Cache2kBuilder<K,V> prefetchExecutor(Executor v) {
667    config().setPrefetchExecutor(new CustomizationReferenceSupplier<Executor>(v));
668    return this;
669  }
670
671  /**
672   * Returns the configuration object this builder operates on. Changes to the configuration also
673   * will influence the created cache when {@link #build()} is called. The method does not
674   * return the effective configuration if additional external/XML configuration is present, since
675   * this is applied when {@code build} is called. On the other hand, the method can be used
676   * to inspect the effective configuration after {@code build} completed.
677   *
678   * @return configuration objects with the parameters set in the builder.
679   */
680  public final Cache2kConfiguration<K,V> toConfiguration() {
681    return config();
682  }
683
684  /**
685   * Builds a cache with the specified configuration parameters.
686   * The builder reused to build caches with similar or identical
687   * configuration. The builder is not thread safe.
688   *
689   * @throws IllegalArgumentException if a cache of the same name is already active in the cache manager
690   */
691  public final Cache<K, V> build() {
692    return CacheManager.PROVIDER.createCache(manager, config());
693  }
694
695}