/*
* This file is part of DeskBin.
*
* Copyright (c) 2012, alta189 <http://github.com/alta189/DeskBin/>
* DeskBin is licensed under the GNU Lesser General Public License.
*
* DeskBin is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* DeskBin is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.alta189.deskbin.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.concurrent.ConcurrentHashMap;
import com.alta189.commons.util.CastUtil;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.SerializationUtils;
import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
public class KeyStore {
private static final KeyStore instance;
private final ConcurrentHashMap<String, String> map = new ConcurrentHashMap<String, String>();
private final File saveFile = new File(PlatformUtils.getWorkingDirectory(), "data" + File.separator + "store.ser");
private final Object key = new Object();
static {
instance = new KeyStore();
// Ensure CryptUtils key is loaded
CryptUtils.getSecretKey();
// Load
load();
// Add shutdown hook to save the store
Runtime.getRuntime().addShutdownHook(new Thread(new SafeSaveRunnable()));
}
public static void store(String key, Object o) {
if (key == null || key.isEmpty()) {
throw new IllegalAccessError();
}
instance.storeImpl(key, o);
}
public static <T> T get(String key) {
if (key == null || key.isEmpty()) {
throw new IllegalAccessError();
}
return instance.getImpl(key);
}
public static boolean contains(String key) {
return !(key == null || key.isEmpty()) && instance.map.containsKey(key);
}
public static void remove(String key) {
if (key != null && !key.isEmpty()) {
instance.map.remove(key);
}
}
public static void load() {
ConcurrentHashMap<String, String> loadedMap = instance.loadImpl();
instance.map.clear();
instance.map.putAll(loadedMap);
}
public static void save() {
instance.saveImpl();
}
private void storeImpl(String key, Object o) {
if (o == null) {
o = new NullObject();
}
String data = toString(CastUtil.safeCast(o, Serializable.class));
String encryptedData = CryptUtils.encrypt(data);
map.put(key, encryptedData);
}
private <T> T getImpl(String key) {
String data = map.get(key);
if (data == null || data.isEmpty()) {
return null;
}
String decryptedData = CryptUtils.decrypt(data);
Object o = fromString(decryptedData);
if (o instanceof NullObject) {
return null;
}
return CastUtil.safeCast(o);
}
private ConcurrentHashMap<String, String> loadImpl() {
synchronized (key) {
String data = null;
if (saveFile.exists()) {
try {
data = FileUtils.readFileToString(saveFile);
} catch (IOException e) {
e.printStackTrace();
}
}
if (data == null || data.isEmpty()) {
return new ConcurrentHashMap<String, String>();
} else {
return CastUtil.safeCast(fromString(data));
}
}
}
private void saveImpl() {
synchronized (key) {
if (!map.isEmpty()) {
String data = toString(map);
try {
FileUtils.write(saveFile, data);
} catch (IOException e) {
e.printStackTrace();
}
} else {
saveFile.delete();
}
}
}
private Object fromString(String s) {
ObjectInputStream ois = null;
try {
byte[] data = Base64Coder.decode(s);
ois = new ObjectInputStream(new ByteArrayInputStream(data));
return SerializationUtils.deserialize(ois);
} catch (IOException e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(ois);
}
return null;
}
private String toString(Serializable o) {
ByteArrayOutputStream baos = null;
ObjectOutputStream oos = null;
try {
baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
SerializationUtils.serialize(o, oos);
return new String(Base64Coder.encode(baos.toByteArray()));
} catch (IOException e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(oos);
IOUtils.closeQuietly(baos);
}
return null;
}
static class NullObject implements Serializable {
private static final long serialVersionUID = 6437740969004810019L;
}
static class SafeSaveRunnable implements Runnable {
@Override
public void run() {
save();
}
}
}