package org.smartly.commons.io.temprepository;
import org.json.JSONArray;
import org.json.JSONObject;
import org.smartly.Smartly;
import org.smartly.commons.cryptograph.MD5;
import org.smartly.commons.util.CollectionUtils;
import org.smartly.commons.util.FileUtils;
import org.smartly.commons.util.JsonWrapper;
import org.smartly.commons.util.PathUtils;
import java.io.File;
import java.io.IOException;
import java.util.Set;
/**
*
*/
public class Registry {
private static final long DEFAULT_LIFE = 60 * 1000; // 1 minute
private static final String LIFE_MS = "life_ms";
private static final String CHECK_MS = "check_ms";
private static final String ITEMS = "items";
private final String _path_settings;
private final String _path_data;
private final JsonWrapper _data;
private final JsonWrapper _settings;
private Thread _registryThread;
public Registry(final String path_settings,
final String path_data) {
_path_settings = path_settings;
_path_data = path_data;
_data = new JsonWrapper(this.loadData(_path_data));
_settings = new JsonWrapper(this.loadSettings(_path_settings));
}
public void start() {
this.startRegistryThread();
}
public void interrupt() {
if (null != _registryThread) {
_registryThread.interrupt();
_registryThread = null;
}
}
public void join() {
if (null != _registryThread) {
try {
_registryThread.join();
} catch (InterruptedException ignored) {
}
}
}
public void clear() {
this.reloadSettings();
synchronized (_data) {
_data.putSilent(ITEMS, new JSONObject());
}
}
public void reloadSettings() {
_settings.parse(this.loadSettings(_path_settings));
}
public long getLife() {
final long result = _settings.optLong(LIFE_MS);
return result > 0 ? result : DEFAULT_LIFE;
}
public void setLife(final long value) {
_settings.putSilent(LIFE_MS, value);
if (_settings.optLong(CHECK_MS) < value) {
_settings.putSilent(CHECK_MS, value);
}
try {
this.saveSettings();
} catch (Throwable ignored) {
}
}
public long getCheck() {
final long result = _settings.optLong(CHECK_MS);
return result > getLife() ? result : getLife();
}
public void setCheck(final long value) {
_settings.putSilent(CHECK_MS, value);
try {
this.saveSettings();
} catch (Throwable ignored) {
}
}
public void save() throws IOException {
this.saveData();
}
public boolean addItem(final String path) {
synchronized (_data) {
final String key = getId(path);
final JSONObject items = _data.optJSONObject(ITEMS);
if (!items.has(key)) {
JsonWrapper.put(items, key, (new RegistryItem(path)).getData());
_data.putOpt(ITEMS, items);
return true;
}
return false;
}
}
public boolean removeItem(final String path) {
synchronized (_data) {
final String key = getId(path);
return this.removeItemByKey(key);
}
}
public int removeExpired() {
synchronized (_data) {
int count = 0;
final long life = this.getLife();
final JsonWrapper items = new JsonWrapper(_data.optJSONObject(ITEMS));
final Set<String> keys = items.keys();
for (final String key : keys) {
final RegistryItem item = new RegistryItem(items.optJSONObject(key));
if (item.expired(life)) {
items.remove(key);
// remove file
this.removeFile(item.getPath());
count++;
}
}
return count;
}
}
// --------------------------------------------------------------------
// p r i v a t e
// --------------------------------------------------------------------
private String loadData(final String fileName) {
try {
return FileUtils.readFileToString(new File(fileName));
} catch (Throwable t) {
return "{'items':{}}";
}
}
private String loadSettings(final String fileName) {
try {
return FileUtils.readFileToString(new File(fileName));
} catch (Throwable t) {
return "{'" + LIFE_MS + "':" + DEFAULT_LIFE + ", '" +
CHECK_MS + "':" + DEFAULT_LIFE +
"}";
}
}
private void saveData() throws IOException {
FileUtils.writeStringToFile(new File(_path_data),
_data.toString(1),
Smartly.getCharset());
}
private void saveSettings() throws IOException {
FileUtils.writeStringToFile(new File(_path_settings),
_settings.toString(1),
Smartly.getCharset());
}
private void removeFile(final String file) {
try {
FileUtils.delete(file);
} catch (Throwable ignored) {
}
}
public boolean removeItemByKey(final String key) {
final JSONObject items = _data.optJSONObject(ITEMS);
return null != JsonWrapper.remove(items, key);
}
private void startRegistryThread() {
// creates thread that check for expired items
_registryThread = new Thread(new Runnable() {
boolean _interrupted = false;
@Override
public void run() {
while (!_interrupted) {
try {
final long sleep = getCheck();
Thread.sleep(sleep);
//-- check registry items --//
if (removeExpired() > 0) {
try {
save();
} catch (Throwable ignored) {
}
}
} catch (InterruptedException ignored) {
_interrupted = true;
}
}
}
});
_registryThread.setDaemon(true);
_registryThread.setPriority(Thread.NORM_PRIORITY);
_registryThread.start();
}
// --------------------------------------------------------------------
// S T A T I C
// --------------------------------------------------------------------
public static String getId(final String path) {
return MD5.encode(PathUtils.toUnixPath(path));
}
}