/*
* (C) Copyright 2015-2016 the original author or authors.
*
* 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.
*
* Contributors:
* ohun@live.cn (夜色)
*/
package com.mpush.test.spi;
import com.mpush.api.Constants;
import com.mpush.api.spi.common.CacheManager;
import com.mpush.tools.Jsons;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
/**
* Created by ohun on 2016/12/28.
*
* @author ohun@live.cn (夜色)
*/
@SuppressWarnings("unchecked")
public final class FileCacheManger implements CacheManager {
public static final FileCacheManger I = new FileCacheManger();
private Map<String, Object> cache = new ConcurrentHashMap<>();
private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
private long lastModified = 0;
private Path cacheFile;
@Override
public void init() {
try {
Path dir = Paths.get(this.getClass().getResource("/").toURI());
this.cacheFile = Paths.get(dir.toString(), "cache.dat");
if (!Files.exists(cacheFile)) {
Files.createFile(cacheFile);
}
} catch (Exception e) {
e.printStackTrace();
}
loadFormFile();
executor.scheduleAtFixedRate(this::loadFormFile, 0, 1, TimeUnit.SECONDS);
}
@Override
public void destroy() {
executor.shutdown();
}
@Override
public void del(String key) {
cache.remove(key);
writeToFile();
}
@Override
public long hincrBy(String key, String field, long value) {
Map fields = ((Map) cache.computeIfAbsent(key, k -> new ConcurrentHashMap<>()));
Number num = (Number) fields.get(field);
long result = num.longValue() + 1;
fields.put(field, result);
executor.execute(this::writeToFile);
return result;
}
@Override
public void set(String key, String value) {
cache.put(key, value);
executor.execute(this::writeToFile);
}
@Override
public void set(String key, String value, int expireTime) {
cache.put(key, value);
executor.execute(this::writeToFile);
}
@Override
public void set(String key, Object value, int expireTime) {
cache.put(key, value);
executor.execute(this::writeToFile);
}
@Override
public <T> T get(String key, Class<T> tClass) {
Object obj = cache.get(key);
if (obj == null) return null;
return Jsons.fromJson(obj.toString(), tClass);
}
@Override
public void hset(String key, String field, String value) {
((Map) cache.computeIfAbsent(key, k -> new ConcurrentHashMap<>())).put(field, value);
executor.execute(this::writeToFile);
}
@Override
public void hset(String key, String field, Object value) {
((Map) cache.computeIfAbsent(key, k -> new ConcurrentHashMap<>())).put(field, value);
executor.execute(this::writeToFile);
}
@Override
public <T> T hget(String key, String field, Class<T> tClass) {
Object obj = ((Map) cache.computeIfAbsent(key, k -> new ConcurrentHashMap<>())).get(field);
if (obj == null) return null;
return Jsons.fromJson(obj.toString(), tClass);
}
@Override
public void hdel(String key, String field) {
Object map = cache.get(key);
if (map != null) {
((Map) map).remove(field);
}
}
@Override
public <T> Map<String, T> hgetAll(String key, Class<T> clazz) {
Map<String, Object> m = (Map) cache.get(key);
if (m == null || m.isEmpty()) return Collections.emptyMap();
Map<String, T> result = new HashMap<>();
for (Map.Entry<String, Object> o : m.entrySet()) {
result.put(o.getKey(), Jsons.fromJson(String.valueOf(o.getValue()), clazz));
}
return result;
}
@Override
public void zAdd(String key, String value) {
}
@Override
public Long zCard(String key) {
return 0L;
}
@Override
public void zRem(String key, String value) {
}
@Override
public <T> List<T> zrange(String key, int start, int end, Class<T> clazz) {
return Collections.emptyList();
}
@Override
public void lpush(String key, String value) {
}
@Override
public <T> List<T> lrange(String key, int start, int end, Class<T> clazz) {
return Collections.emptyList();
}
private synchronized void loadFormFile() {
try {
long lastModified = Files.getLastModifiedTime(cacheFile).toMillis();
if (this.lastModified < lastModified) {
byte[] bytes = Files.readAllBytes(cacheFile);
if (bytes != null && bytes.length > 0) {
cache = Jsons.fromJson(bytes, ConcurrentHashMap.class);
}
this.lastModified = lastModified;
}
} catch (Exception e) {
e.printStackTrace();
}
}
private synchronized void writeToFile() {
try {
Files.write(cacheFile, Jsons.toJson(cache).getBytes(Constants.UTF_8));
this.lastModified = Files.getLastModifiedTime(cacheFile).toMillis();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
FileCacheManger cacheManger = new FileCacheManger();
cacheManger.init();
cacheManger.set("1", "1");
cacheManger.set("2", "2");
cacheManger.destroy();
}
}