001/**
002 * Copyright (c) 2015-2022, Michael Yang 杨福海 (fuhai999@gmail.com).
003 * <p>
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 * <p>
008 * http://www.apache.org/licenses/LICENSE-2.0
009 * <p>
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 io.jboot.components.cache.caffeine;
017
018import com.github.benmanes.caffeine.cache.Cache;
019import com.jfinal.plugin.ehcache.IDataLoader;
020import io.jboot.components.cache.JbootCacheBase;
021import io.jboot.components.cache.JbootCacheConfig;
022
023import java.util.ArrayList;
024import java.util.List;
025import java.util.Map;
026import java.util.concurrent.ConcurrentHashMap;
027
028
029public class CaffeineCacheImpl extends JbootCacheBase {
030
031    private Map<String, Cache> cacheMap = new ConcurrentHashMap<>();
032
033    public CaffeineCacheImpl(JbootCacheConfig config) {
034        super(config);
035    }
036
037    protected Cache getCacheOnly(String cacheName) {
038        cacheName = buildCacheName(cacheName);
039        return cacheMap.get(cacheName);
040    }
041
042    protected Cache getCache(String cacheName) {
043        cacheName = buildCacheName(cacheName);
044        Cache cache = cacheMap.get(cacheName);
045        if (cache == null) {
046            synchronized (CaffeineCacheImpl.class) {
047                cache = cacheMap.get(cacheName);
048                if (cache == null) {
049                    cache = createCacheBuilder().build(cacheName);
050                    cacheMap.put(cacheName,cache);
051                }
052            }
053        }
054        return cache;
055    }
056
057    protected CaffeineCacheBuilder createCacheBuilder() {
058        return new DefaultCaffeineCacheBuilder();
059    }
060
061
062    @Override
063    public <T> T get(String cacheName, Object key) {
064        Cache cache = getCache(cacheName);
065        CaffeineCacheObject data = (CaffeineCacheObject) cache.getIfPresent(key);
066        if (data == null) {
067            return null;
068        }
069
070        if (data.isDue()) {
071            cache.invalidate(key);
072            return null;
073        }
074
075        T cacheData = (T) data.getValue();
076        if (config.isDevMode()) {
077            println("CaffeineCache GET: cacheName[" + buildCacheName(cacheName) + "] cacheKey[" + key + "] value:" + cacheData);
078        }
079        return cacheData;
080    }
081
082    @Override
083    public void put(String cacheName, Object key, Object value) {
084        putData(getCache(cacheName), key, new CaffeineCacheObject(value));
085        if (config.isDevMode()) {
086            println("CaffeineCache PUT: cacheName[" + buildCacheName(cacheName) + "] cacheKey[" + key + "] value:" + value);
087        }
088    }
089
090    @Override
091    public void put(String cacheName, Object key, Object value, int liveSeconds) {
092        putData(getCache(cacheName), key, new CaffeineCacheObject(value, liveSeconds));
093        if (config.isDevMode()) {
094            println("CaffeineCache PUT: cacheName[" + buildCacheName(cacheName) + "] cacheKey[" + key + "] value:" + value);
095        }
096    }
097
098
099
100    @Override
101    public void remove(String cacheName, Object key) {
102        Cache cache = getCacheOnly(cacheName);
103        if (cache != null) {
104            cache.invalidate(key);
105        }
106        if (config.isDevMode()) {
107            println("CaffeineCache REMOVE: cacheName[" + buildCacheName(cacheName) + "] cacheKey[" + key + "]");
108        }
109    }
110
111    @Override
112    public void removeAll(String cacheName) {
113        Cache cache = getCacheOnly(cacheName);
114        if (cache != null) {
115            cache.invalidateAll();
116        }
117        cacheMap.remove(buildCacheName(cacheName));
118        if (config.isDevMode()) {
119            println("CaffeineCache REMOVEALL: cacheName[" + buildCacheName(cacheName) + "]");
120        }
121    }
122
123    @Override
124    public <T> T get(String cacheName, Object key, IDataLoader dataLoader) {
125        Cache cache = getCache(cacheName);
126        CaffeineCacheObject data = (CaffeineCacheObject) cache.getIfPresent(key);
127        if (data == null || data.isDue()) {
128            Object newValue = dataLoader.load();
129            if (newValue != null) {
130                data = new CaffeineCacheObject(newValue);
131                putData(cache, key, data);
132                if (config.isDevMode()) {
133                    println("CaffeineCache PUT: cacheName[" + buildCacheName(cacheName) + "] cacheKey[" + key + "] value:" + newValue);
134                }
135            }
136            return (T) newValue;
137        } else {
138            Object cacheData = data.getValue();
139            if (config.isDevMode()) {
140                println("CaffeineCache GET: cacheName[" + buildCacheName(cacheName) + "] cacheKey[" + key + "] value:" + cacheData);
141            }
142            return (T) cacheData;
143        }
144    }
145
146    @Override
147    public <T> T get(String cacheName, Object key, IDataLoader dataLoader, int liveSeconds) {
148        Cache cache = getCache(cacheName);
149        CaffeineCacheObject data = (CaffeineCacheObject) cache.getIfPresent(key);
150        if (data == null || data.isDue()) {
151            Object newValue = dataLoader.load();
152            if (newValue != null) {
153                data = new CaffeineCacheObject(newValue, liveSeconds);
154                putData(cache, key, data);
155                if (config.isDevMode()) {
156                    println("CaffeineCache PUT: cacheName[" +buildCacheName(cacheName)+ "] cacheKey["+key+"] value:" + newValue);
157                }
158            }
159            return (T) newValue;
160        } else {
161            Object cacheData = data.getValue();
162            if (config.isDevMode()) {
163                println("CaffeineCache GET: cacheName[" +buildCacheName(cacheName)+ "] cacheKey["+key+"] value:" + cacheData);
164            }
165            return (T) cacheData;
166        }
167    }
168
169    @Override
170    public Integer getTtl(String cacheName, Object key) {
171        Cache cache = getCacheOnly(cacheName);
172        if (cache == null) {
173            return null;
174        }
175
176        CaffeineCacheObject data = (CaffeineCacheObject) cache.getIfPresent(key);
177        if (data == null) {
178            return null;
179        }
180
181        return data.getTtl();
182    }
183
184    @Override
185    public void setTtl(String cacheName, Object key, int seconds) {
186        Cache cache = getCacheOnly(cacheName);
187        if (cache == null) {
188            return;
189        }
190
191        CaffeineCacheObject data = (CaffeineCacheObject) cache.getIfPresent(key);
192        if (data == null) {
193            return;
194        }
195
196        data.setLiveSeconds(seconds);
197        putData(cache, key, data);
198
199        if (config.isDevMode()) {
200            println("CaffeineCache SETTTL: cacheName[" +buildCacheName(cacheName)+ "] cacheKey["+key+"] seconds:" + seconds);
201        }
202    }
203
204
205    @Override
206    public List getNames() {
207        return new ArrayList(cacheMap.keySet());
208    }
209
210    @Override
211    public List getKeys(String cacheName) {
212        Cache cache = getCacheOnly(cacheName);
213        return cache == null ? null : new ArrayList(cache.asMap().keySet());
214    }
215
216
217    protected void putData(Cache cache, Object key, CaffeineCacheObject value) {
218        value.setCachetime(System.currentTimeMillis());
219        cache.put(key, value);
220    }
221}