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

io.helidon.security.providers.EvictableCache Maven / Gradle / Ivy

There is a newer version: 0.10.6
Show newest version
/*
 * Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
 *
 * 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.
 */

package io.helidon.security.providers;

import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Supplier;

import io.helidon.config.Config;

/**
 * Generic cache with eviction and max size.
 *
 * @param  type of keys in this cache
 * @param  type of values in this cache
 */
public interface EvictableCache {
    /**
     * Default timeout of records in minutes (inactivity timeout).
     */
    long CACHE_TIMEOUT_MINUTES = 60;
    /**
     * Default eviction period in minutes (how often to evict records).
     */
    long CACHE_EVICT_PERIOD_MINUTES = 5;
    /**
     * Default eviction delay in minutes (how long to wait after the cache is started).
     */
    long CACHE_EVICT_DELAY_MINUTES = 1;
    /**
     * Maximal number of records in the cache.
     * If the cache is full, no caching is done and the supplier of value is called for every uncached value.
     */
    long CACHE_MAX_SIZE = 100_000;
    /**
     * Parameter to {@link ConcurrentHashMap#forEachKey(long, Consumer)} used for eviction.
     */
    long EVICT_PARALLELISM_THRESHOLD = 10000;

    /**
     * Create a new builder for a cache.
     *
     * @param  type of keys in the cache
     * @param  type of values in the cache
     * @return a builder to build the cache
     */
    static  Builder builder() {
        return new Builder<>();
    }

    /**
     * Create a new cache with default values.
     *
     * @param  type of keys in the cache
     * @param  type of values in the cache
     * @return new cache built with default values
     */
    static  EvictableCache create() {
        Builder builder = builder();
        return builder.build();
    }

    /**
     * Create a new cache and configure it from the provided configuration.
     * See {@link Builder#fromConfig(Config)} for the list of configuration keys.
     *
     * @param config config to read configuration of this cache from
     * @param     type of keys in the cache
     * @param     type of values in the cache
     * @return new cache configured from config
     */
    static  EvictableCache create(Config config) {
        Builder builder = builder();

        return builder.fromConfig(config)
                .build();
    }

    /**
     * This method has same semantics as {@link #create(Config)} and is here to allow automatic
     * loading of instances from config using {@link Config#as(Class)}.
     *
     * @param config config to read configuration of this cache from
     * @param     type of keys in the cache
     * @param     type of values in the cache
     * @return new cache configured from config
     * @deprecated Do not use directly, please use {@link #create(Config)}
     */
    @Deprecated
    static  EvictableCache from(Config config) {
        return create(config);
    }

    /**
     * Create a new cache that is not a cache (e.g. never caches, delegates
     * all calls to the {@link Supplier} in {@link #computeValue(Object, Supplier)}.
     *
     * @param  Type of keys
     * @param  Type of values
     * @return a new instance that is not caching
     */
    @SuppressWarnings("unchecked")
    static  EvictableCache noCache() {
        // there is no support for restricted visibility in interface in current java version
        return (EvictableCache) EvictableCacheImpl.NO_CACHE;
    }

    /**
     * Remove a key from the cache. Return the value if it was cached and valid.
     *
     * @param key key to remove
     * @return value if it was removed and valid, empty otherwise
     */
    default Optional remove(K key) {
        return Optional.empty();
    }

    /**
     * Get current cached value if valid.
     *
     * @param key key to use
     * @return current value in the cache or empty if not present (or invalid)
     */
    default Optional get(K key) {
        return Optional.empty();
    }

    /**
     * Current size of the cache.
     * As this cache is using {@link ConcurrentHashMap} as backing store, be aware that this value is not
     * guaranteed to be consistent, as puts and removed may be happening in parallel.
     *
     * @return current size of the cache (including valid and invalid - not yet evicted - values)
     */
    default int size() {
        return 0;
    }

    /**
     * Either return a cached value or compute it and cache it.
     *
     * @param key           key to check/insert value for
     * @param valueSupplier supplier called if the value is not yet cached, or is invalid
     * @return current value from the cache, or computed value from the supplier
     */
    default Optional computeValue(K key, Supplier> valueSupplier) {
        return valueSupplier.get();
    }

    /**
     * Close this cache.
     * Carry out shutdown tasks (e.g. shutting down eviction thread).
     */
    default void close() {
    }

    /**
     * Builder to create instances of {@link EvictableCache}.
     *
     * @param  types of keys used in the cache
     * @param  types of values used in the cache
     */
    class Builder {
        private boolean cacheEnabled = true;
        private long cacheTimeout = CACHE_TIMEOUT_MINUTES;
        private long cacheMaxSize = CACHE_MAX_SIZE;
        private TimeUnit cacheTimeoutUnit = TimeUnit.MINUTES;
        private long cacheEvictDelay = CACHE_EVICT_DELAY_MINUTES;
        private long cacheEvictPeriod = CACHE_EVICT_PERIOD_MINUTES;
        private TimeUnit cacheEvictTimeUnit = TimeUnit.MINUTES;
        private long parallelismThreshold = EVICT_PARALLELISM_THRESHOLD;
        private BiFunction evictor = (key, value) -> false;

        /**
         * Build a new instance of the cache based on configuration of this builder.
         *
         * @param  key type
         * @param  value type
         * @return a new instance of the cache
         */
        @SuppressWarnings("unchecked")
        public  EvictableCache build() {
            if (cacheEnabled) {
                return new EvictableCacheImpl(this);
            } else {
                return noCache();
            }
        }

        /**
         * Configure record timeout since last modification.
         *
         * @param timeout     timeout value
         * @param timeoutUnit timeout unit
         * @return updated builder instance
         */
        public Builder timeout(long timeout, TimeUnit timeoutUnit) {
            this.cacheTimeout = timeout;
            this.cacheTimeoutUnit = timeoutUnit;
            return this;
        }

        /**
         * Configure maximal cache size.
         *
         * @param cacheMaxSize maximal number of records to store in the cache
         * @return updated builder instance
         */
        public Builder maxSize(long cacheMaxSize) {
            this.cacheMaxSize = cacheMaxSize;
            return this;
        }

        /**
         * Configure eviction scheduling.
         *
         * @param evictDelay    delay from the creation of the cache to first eviction
         * @param evictPeriod   how often to evict records
         * @param evictTimeUnit time unit to use for these values
         * @return updated builder instance
         */
        public Builder evictSchedule(long evictDelay, long evictPeriod, TimeUnit evictTimeUnit) {
            this.cacheEvictDelay = evictDelay;
            this.cacheEvictPeriod = evictPeriod;
            this.cacheEvictTimeUnit = evictTimeUnit;
            return this;
        }

        /**
         * Configure parallelism threshold.
         *
         * @param parallelismThreshold see {@link ConcurrentHashMap#forEachKey(long, Consumer)}
         * @return updated builder instance
         */
        public Builder parallelismThreshold(long parallelismThreshold) {
            this.parallelismThreshold = parallelismThreshold;
            return this;
        }

        /**
         * Configure evictor to check if a records is still valid.
         * This should be a fast way to check, as it is happening in a {@link ConcurrentHashMap#forEachKey(long, Consumer)}.
         * This is also called during all get and remove operations to only return valid records.
         *
         * @param evictor evictor to use, return {@code true} for records that should be evicted, {@code false} for records
         *                that should stay in cache
         * @return updated builder instance
         */
        public Builder evictor(BiFunction evictor) {
            this.evictor = evictor;
            return this;
        }

        /**
         * If the cacheEnabled is set to false, no caching will be done.
         * Otherwise (default behavior) evictable caching will be used.
         *
         * @param cacheEnabled whether to enable this cache or not (true - enabled by default)
         * @return updated builder instance
         */
        public Builder cacheEnabled(boolean cacheEnabled) {
            this.cacheEnabled = cacheEnabled;
            return this;
        }

        /**
         * Update this builder from configuration.
         *
         * Options expected under the current config node:
         * 
         * 
         * 
         * 
         * 
         * 
         * 
         * 
         * 
         * 
Configuration parameters
keydefault valuedescription
cache-enabledtrueSet to false to fully disable caching (and ignore other parameters) *
cache-timeout-millis{@value #CACHE_TIMEOUT_MINUTES} minutesTimeout of records in the cache * in milliseconds
cache-evict-delay-millis{@value #CACHE_EVICT_DELAY_MINUTES} minutesHow long to wait with * eviction after the cache is created in milliseconds
cache-evict-period-millis{@value #CACHE_EVICT_PERIOD_MINUTES} minutesHow often to evict * records from the cache in milliseconds
parallelism-treshold{@value #EVICT_PARALLELISM_THRESHOLD}see * {@link #parallelismThreshold(long)}
evictor-classA class that is instantiated and used as an evictor for this instance
* * @param config Config to use to load configuration options for this builder * @return updated builder instance */ public Builder fromConfig(Config config) { config.get("cache-enabled").asOptionalBoolean().ifPresent(this::cacheEnabled); if (cacheEnabled) { config.get("cache-timeout-millis").asOptionalLong().ifPresent(timeout -> timeout(timeout, TimeUnit.MILLISECONDS)); long evictDelay = config.get("cache-evict-delay-millis").asLong(cacheEvictTimeUnit.toMillis(cacheEvictDelay)); long evictPeriod = config.get("cache-evict-period-millis").asLong(cacheEvictTimeUnit.toMillis(cacheEvictPeriod)); evictSchedule(evictDelay, evictPeriod, TimeUnit.MILLISECONDS); config.get("parallelism-treshold").asOptionalLong().ifPresent(this::parallelismThreshold); config.get("evictor-class").asOptional(Class.class).ifPresent(this::evictorClass); } return this; } @SuppressWarnings("unchecked") private Builder evictorClass(Class aClass) { // attempt to create an instance try { aClass.getMethod("apply", Object.class, Object.class); Object anObject = aClass.getConstructor().newInstance(); evictor((BiFunction) anObject); } catch (ReflectiveOperationException e) { throw new SecurityException("Failed to create an evictor instance. Configured class: " + aClass.getName(), e); } return this; } long cacheTimeout() { return cacheTimeout; } long cacheMaxSize() { return cacheMaxSize; } TimeUnit cacheTimeoutUnit() { return cacheTimeoutUnit; } long cacheEvictDelay() { return cacheEvictDelay; } long cacheEvictPeriod() { return cacheEvictPeriod; } TimeUnit cacheEvictTimeUnit() { return cacheEvictTimeUnit; } long parallelismThreshold() { return parallelismThreshold; } BiFunction evictor() { return evictor; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy