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.j2cache;
017
018import com.jfinal.log.Log;
019import com.jfinal.plugin.ehcache.IDataLoader;
020import io.jboot.components.cache.JbootCacheBase;
021import io.jboot.components.cache.JbootCacheConfig;
022import io.jboot.exception.JbootException;
023import net.oschina.j2cache.CacheChannel;
024import net.oschina.j2cache.CacheObject;
025import net.oschina.j2cache.J2Cache;
026
027import java.lang.reflect.Method;
028import java.util.ArrayList;
029import java.util.Collection;
030import java.util.List;
031import java.util.stream.Collectors;
032
033/**
034 * @author Michael Yang 杨福海 (fuhai999@gmail.com)
035 * @version V1.0
036 */
037public class J2cacheImpl extends JbootCacheBase {
038
039    private static final Log LOG = Log.getLog(J2cacheImpl.class);
040
041    public J2cacheImpl(JbootCacheConfig config) {
042        super(config);
043    }
044
045    @Override
046    public <T> T get(String cacheName, Object key) {
047        cacheName = buildCacheName(cacheName);
048        CacheObject cacheObject = J2Cache.getChannel().get(cacheName, key.toString(), false);
049        if (cacheObject != null) {
050            Object value = cacheObject.getValue();
051            if (config.isDevMode()) {
052                println("J2cache GET: cacheName[" +cacheName+ "] cacheKey["+key+"] value:" + value);
053            }
054            return (T) value;
055        } else {
056            return null;
057        }
058    }
059
060    @Override
061    public void put(String cacheName, Object key, Object value) {
062        cacheName = buildCacheName(cacheName);
063        J2Cache.getChannel().set(cacheName, key.toString(), value);
064
065        if (config.isDevMode()) {
066            println("J2cache PUT: cacheName[" +cacheName+ "] cacheKey["+key+"] value:" + value);
067        }
068    }
069
070    @Override
071    public void put(String cacheName, Object key, Object value, int liveSeconds) {
072        cacheName = buildCacheName(cacheName);
073        J2Cache.getChannel().set(cacheName, key.toString(), value, liveSeconds);
074
075        if (config.isDevMode()) {
076            println("J2cache PUT: cacheName[" +cacheName+ "] cacheKey["+key+"] value:" + value);
077        }
078    }
079
080
081    @Override
082    public void remove(String cacheName, Object key) {
083        cacheName = buildCacheName(cacheName);
084        J2Cache.getChannel().evict(cacheName, key.toString());
085
086        if (config.isDevMode()) {
087            println("J2cache REMOVE: cacheName[" +cacheName+ "] cacheKey["+key+"]");
088        }
089    }
090
091    @Override
092    public void removeAll(String cacheName) {
093        cacheName = buildCacheName(cacheName);
094        J2Cache.getChannel().clear(cacheName);
095
096        if (config.isDevMode()) {
097            println("J2cache REMOVEALL: cacheName[" +cacheName+ "]");
098        }
099    }
100
101    @Override
102    public <T> T get(String cacheName, Object key, IDataLoader dataLoader) {
103        Object value = get(cacheName, key);
104        if (value == null) {
105            value = dataLoader.load();
106            if (value != null) {
107                put(cacheName, key, value);
108            }
109        }
110
111        if (config.isDevMode()) {
112            println("J2cache GET: cacheName[" + buildCacheName(cacheName) + "] cacheKey[" + key + "] value:" + value);
113        }
114
115        return (T) value;
116    }
117
118    @Override
119    public <T> T get(String cacheName, Object key, IDataLoader dataLoader, int liveSeconds) {
120        if (liveSeconds <= 0) {
121            return get(cacheName, key, dataLoader);
122        }
123
124        Object data = get(cacheName, key);
125        if (data == null) {
126            data = dataLoader.load();
127            put(cacheName, key, data, liveSeconds);
128        }
129
130        if (config.isDevMode()) {
131            println("J2cache GET: cacheName[" +buildCacheName(cacheName)+ "] cacheKey["+key+"] value:" + data);
132        }
133        return (T) data;
134    }
135
136    private Method sendEvictCmdMethod;
137
138    @Override
139    public synchronized void refresh(String cacheName, Object key) {
140        cacheName = buildCacheName(cacheName);
141        if (sendEvictCmdMethod == null) {
142            sendEvictCmdMethod = getSendEvictCmdMethod();
143        }
144        try {
145            if (sendEvictCmdMethod != null) {
146                sendEvictCmdMethod.invoke(J2Cache.getChannel(), cacheName, key);
147            }
148        } catch (Exception e) {
149            LOG.error("refresh error!", e);
150        }
151    }
152
153
154    private Method sendClearCmdMethod;
155
156    @Override
157    public synchronized void refresh(String cacheName) {
158        cacheName = buildCacheName(cacheName);
159        if (sendClearCmdMethod == null) {
160            sendClearCmdMethod = getSendClearCmdMethod();
161        }
162        try {
163            if (sendClearCmdMethod != null) {
164                sendClearCmdMethod.invoke(J2Cache.getChannel(), cacheName);
165            }
166        } catch (Exception e) {
167            LOG.error("refresh error!", e);
168        }
169    }
170
171    @Override
172    public List getNames() {
173        Collection<CacheChannel.Region> regions = J2Cache.getChannel().getL1Provider().regions();
174        return regions != null && !regions.isEmpty()
175                ? regions.stream().map(CacheChannel.Region::getName).collect(Collectors.toList())
176                : null;
177    }
178
179
180    @Override
181    public List getKeys(String cacheName) {
182        cacheName = buildCacheName(cacheName);
183        Collection keys = J2Cache.getChannel().keys(cacheName);
184        return keys != null ? new ArrayList(keys) : null;
185    }
186
187
188    private Method getSendEvictCmdMethod() {
189        try {
190            Method method = CacheChannel.class.getDeclaredMethod("sendEvictCmd", String.class, String[].class);
191            method.setAccessible(true);
192            return method;
193        } catch (Exception e) {
194            e.printStackTrace();
195        }
196        return null;
197    }
198
199
200    private Method getSendClearCmdMethod() {
201        try {
202            Method method = CacheChannel.class.getDeclaredMethod("sendClearCmd", String.class);
203            method.setAccessible(true);
204            return method;
205        } catch (Exception e) {
206            e.printStackTrace();
207        }
208        return null;
209    }
210
211
212    @Override
213    public Integer getTtl(String cacheName, Object key) {
214        throw new JbootException("getTtl not support in j2cache");
215    }
216
217    @Override
218    public void setTtl(String cacheName, Object key, int seconds) {
219        throw new JbootException("setTtl not support in j2cache");
220    }
221}