001/*
002 *  Copyright 2019 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.core.cache;
017
018import java.util.HashMap;
019import java.util.Map;
020import java.util.function.Function;
021
022import org.slf4j.Logger;
023
024import org.ametys.runtime.i18n.I18nizableText;
025
026/**
027 * A cache represents a store of objects indexed with a key
028 * @param <K> the type of the keys in cache
029 * @param <V> the type of the values in cache
030 */
031public interface Cache<K, V>
032{
033    /**
034     * Returns the value associated with {@code key} in this cache if it exist,
035     * obtaining that value from given function if necessary and store it.
036     * @param key the key to get the element
037     * @param function the function to compute the value if key is not present
038     * @return V the value associated with key
039     * @throws CacheException throw CacheException if the key is null or invalid, or if failed to compute the new value
040     */
041    public V get(K key, Function<K, V> function) throws CacheException;
042
043    /**
044     * Returns the value associated with {@code key} in this cache if it exist
045     * @param key the key to get the element
046     * @return V the value linked to key
047     */
048    public V get(K key);
049    
050    /**
051     * Associates {@code value} with {@code key} in this cache. If the cache
052     * previously contained a value associated with {@code key}, the old value
053     * is replaced by {@code value}. The {@code key} can not be null.
054     * @param key the key to get the element
055     * @param value the value associated with key
056     */
057    public void put(K key, V value);
058
059    /**
060     * Copies all of the mappings from the specified map to the cache.
061     * @param map map of key/values to be stored in the cache
062     */
063    public void putAll(Map<K, V> map);
064
065    /**
066     * return true if key is present in cache
067     * @param key the key to be checked
068     * @return true if key is present in cache
069     */
070    public boolean hasKey(K key);
071
072    /**
073     * Discards any cached value for key {@code key}.
074     * @param key the key to invalidate
075     */
076    public void invalidate(K key);
077
078    /**
079     * Discards all entries in the cache, without reseting statistics
080     */
081    public void invalidateAll();
082
083    /**
084     * Create or reset the whole cache (including statistics)
085     */
086    public void resetCache();
087
088    /**
089     * Get all statistics about cache
090     * @return statistic about the cache (hit, miss, evictions...)
091     */
092    public CacheStats getCacheStats();
093
094    /**
095     * Get the size the cache take in bytes
096     * @return the size of the cache if it's computable, return 0 otherwise
097     * @throws CacheException throw CacheException if memory size can not be computed
098     */
099    public long getMemorySize() throws CacheException;
100
101    /**
102     * Get the max size allocated to the cache, in bytes. 
103     * This value can be set to Long.MAX_VALUE for infinite cache
104     * @return the max size allocated to the cache
105     */
106    public long getMaxSize();
107
108    /**
109     * Get the number of values in cache
110     * @return the number of values in cache
111     */
112    public long getNumberOfElements();
113
114    /**
115     * Get the label of cache
116     * @return the label of cache
117     */
118    public I18nizableText getLabel();
119
120    /**
121     * Get the description of cache
122     * @return the description of cache
123     */
124    public I18nizableText getDescription();
125
126    /**
127     * Get the id of cache
128     * @return the id of cache
129     */
130    public String getId();
131
132    /**
133     * Is this cache size computable
134     * @return true if the cache size is computable
135     */
136    public boolean isComputableSize();
137
138    /**
139     * Get the cache as a simple Map
140     * @return the Map&lt;K, V&gt; representing the cache
141     */
142    public Map<K, V> asMap();
143    
144    /**
145     * Get the definition in JSON Map
146     * @param logger Logger to log an error when the size cannot be computed
147     * @return the JSON for the cache
148     */
149    public default Map<String, Object> toJSONMap(Logger logger)
150    {
151        Map<String, Object> properties = new HashMap<>();
152        properties.put("id", this.getId());
153        properties.put("label", this.getLabel());
154        properties.put("description", this.getDescription());
155        properties.put("computableSize", this.isComputableSize());
156        properties.put("access", this.getCacheStats().requestCount());
157        properties.put("hit", this.getCacheStats().hitCount());
158        properties.put("hitRate", this.getCacheStats().hitRate());
159        properties.put("miss", this.getCacheStats().missCount());
160        properties.put("missRate", this.getCacheStats().missRate());
161        properties.put("nbElement", this.getNumberOfElements());
162        properties.put("nbEviction", this.getCacheStats().evictionCount());
163        try
164        {
165            properties.put("currentSize", this.getMemorySize());
166        }
167        catch (CacheException e)
168        {
169            logger.error("Unable to compute size of cache: {} - {}", this.getId(), this.getLabel(), e);
170            properties.put("currentSize", -1);
171        }
172        properties.put("maxSize", this.getMaxSize());
173        return properties;
174    }
175
176}