View Javadoc
1   /*
2    * This file is part of Waarp Project (named also Waarp or GG).
3    *
4    *  Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
5    *  tags. See the COPYRIGHT.txt in the distribution for a full listing of
6    * individual contributors.
7    *
8    *  All Waarp Project is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License, or (at your
11   * option) any later version.
12   *
13   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
14   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15   * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License along with
18   * Waarp . If not, see <http://www.gnu.org/licenses/>.
19   */
20  package org.waarp.common.lru;
21  
22  import java.util.concurrent.Callable;
23  
24  /**
25   * Base class for concrete implementations
26   *
27   * @author Damian Momot
28   */
29  public abstract class AbstractLruCache<K, V>
30      implements InterfaceLruCache<K, V> {
31    private long ttl;
32  
33    /**
34     * Constructs BaseLruCache
35     *
36     * @param ttl
37     *
38     * @throws IllegalArgumentException if ttl is not positive
39     */
40    protected AbstractLruCache(final long ttl) {
41      if (ttl <= 0) {
42        throw new IllegalArgumentException("ttl must be positive");
43      }
44  
45      this.ttl = ttl;
46    }
47  
48    @Override
49    public final boolean contains(final K key) {
50      // can't use contains because of expiration policy
51      final V value = get(key);
52  
53      return value != null;
54    }
55  
56    /**
57     * Creates new LruCacheEntry<V>.
58     * <p>
59     * It can be used to change implementation of LruCacheEntry
60     *
61     * @param value
62     * @param ttl
63     *
64     * @return LruCacheEntry<V>
65     */
66    protected InterfaceLruCacheEntry<V> createEntry(final V value,
67                                                    final long ttl) {
68      return new StrongReferenceCacheEntry<V>(value, ttl);
69    }
70  
71    @Override
72    public V get(final K key) {
73      return getValue(key);
74    }
75  
76    @Override
77    public final V get(final K key, final Callable<V> callback) throws Exception {
78      return get(key, callback, ttl);
79    }
80  
81    @Override
82    public final V get(final K key, final Callable<V> callback, final long ttl)
83        throws Exception {
84      V value = get(key);
85  
86      // if element doesn't exist create it using callback
87      if (value == null) {
88        value = callback.call();
89        put(key, value, ttl);
90      }
91  
92      return value;
93    }
94  
95    @Override
96    public final long getTtl() {
97      return ttl;
98    }
99  
100   @Override
101   public final void setNewTtl(final long ttl) {
102     if (ttl <= 0) {
103       throw new IllegalArgumentException("ttl must be positive");
104     }
105     this.ttl = ttl;
106   }
107 
108   /**
109    * Returns LruCacheEntry mapped by key or null if it does not exist
110    *
111    * @param key
112    *
113    * @return LruCacheEntry<V>
114    */
115   protected abstract InterfaceLruCacheEntry<V> getEntry(K key);
116 
117   @Override
118   public final void updateTtl(final K key) {
119     final InterfaceLruCacheEntry<V> cacheEntry = getEntry(key);
120     if (cacheEntry != null) {
121       cacheEntry.resetTime(ttl);
122     }
123   }
124 
125   /**
126    * Tries to retrieve value by it's key. Automatically removes entry if it's
127    * not valid
128    * (LruCacheEntry.getValue() returns null)
129    *
130    * @param key
131    *
132    * @return Value
133    */
134   protected final V getValue(final K key) {
135     V value = null;
136 
137     final InterfaceLruCacheEntry<V> cacheEntry = getEntry(key);
138 
139     if (cacheEntry != null) {
140       value = cacheEntry.getValue();
141 
142       // autoremove entry from cache if it's not valid
143       if (value == null) {
144         remove(key);
145       }
146     }
147 
148     return value;
149   }
150 
151   @Override
152   public final boolean isEmpty() {
153     return size() == 0;
154   }
155 
156   @Override
157   public final void put(final K key, final V value) {
158     put(key, value, ttl);
159   }
160 
161   @Override
162   public void put(final K key, final V value, final long ttl) {
163     if (value != null) {
164       putEntry(key, createEntry(value, ttl));
165     }
166   }
167 
168   /**
169    * Puts entry into cache
170    *
171    * @param key
172    * @param entry
173    */
174   protected abstract void putEntry(K key, InterfaceLruCacheEntry<V> entry);
175 }