package org.smartly.commons.io.jsondb;
import org.json.JSONArray;
import org.json.JSONObject;
import org.smartly.commons.Delegates;
import org.smartly.commons.lang.CharEncoding;
import org.smartly.commons.logging.Level;
import org.smartly.commons.logging.util.LoggingUtils;
import org.smartly.commons.util.FileUtils;
import org.smartly.commons.util.JsonWrapper;
import org.smartly.commons.util.PathUtils;
import java.io.File;
/**
*
*/
public class JsonDB {
public static final String CHARSET = CharEncoding.UTF_8;
// ------------------------------------------------------------------------
// e v e n t s
// ------------------------------------------------------------------------
private static final Class EVENT_ERROR = Delegates.ExceptionCallback.class;
// ------------------------------------------------------------------------
// c o n s t a n t s
// ------------------------------------------------------------------------
private static final String COLLECTIONS = "collections";
// ------------------------------------------------------------------------
// f i e l d s
// ------------------------------------------------------------------------
private final Delegates.Handlers _eventHandlers;
private final String _root;
private final Object _syncObj;
private String _db_root;
private String _file_metadata;
private JsonWrapper _matadata;
private boolean _open;
// ------------------------------------------------------------------------
// c o n s t r u c t o r
// ------------------------------------------------------------------------
public JsonDB(final String root) {
_eventHandlers = new Delegates.Handlers();
_root = root;
_syncObj = new Object();
}
public JsonDB open(final String name) {
if (!_open) {
try {
_db_root = PathUtils.concat(_root, name);
_file_metadata = PathUtils.concat(_db_root, "_metadata.json");
_matadata = this.init();
_open = true;
} catch (Throwable t) {
this.close();
this.handle(t);
}
}
return this;
}
public void close() {
_file_metadata = null;
_matadata = null;
_open = false;
}
public boolean isOpen() {
return _open;
}
public String getRoot() {
return _db_root;
}
public JsonDBCollection collection(final String name) {
this.collectionsMetadata(name, false);
return new JsonDBCollection(this, name);
}
public JsonDBCollection dropCollection(final String name) {
this.collectionsMetadata(name, true);
return new JsonDBCollection(this, name);
}
// ------------------------------------------------------------------------
// p u b l i c
// ------------------------------------------------------------------------
public void onError(final Delegates.ExceptionCallback handler) {
_eventHandlers.add(handler);
}
// ------------------------------------------------------------------------
// p a c k a g e
// ------------------------------------------------------------------------
void collectionsMetadata(final String collName, final boolean drop) {
synchronized (_syncObj) {
final JSONArray collections = _matadata.optJSONArray(COLLECTIONS);
if (null != collections) {
final int length = collections.length();
if (drop) {
// remove
JsonWrapper.removeAll(collections, collName);
} else {
// add
if (!JsonWrapper.contains(collections, collName)) {
collections.put(collName);
}
}
this.saveMetadata();
}
}
}
void handle(final Throwable t) {
if (_eventHandlers.contains(EVENT_ERROR)) {
_eventHandlers.triggerAsync(EVENT_ERROR, t);
} else {
LoggingUtils.getLogger(this).log(Level.SEVERE, null, t);
}
}
// ------------------------------------------------------------------------
// p r i v a t e
// ------------------------------------------------------------------------
private JsonWrapper init() {
JsonWrapper result = new JsonWrapper(new JSONObject());
try {
if (!FileUtils.exists(_file_metadata)) {
// create empty
result.put(COLLECTIONS, new JSONArray());
// save
FileUtils.mkdirs(_file_metadata);
this.saveMetadata();
} else {
result = new JsonWrapper(this.readMetadata());
}
} catch (Throwable t) {
this.handle(t);
}
return result;
}
private String readMetadata() {
try {
if (PathUtils.exists(_file_metadata)) {
return FileUtils.readFileToString(new File(_file_metadata), CHARSET);
}
} catch (Throwable ignored) {
}
return null;
}
private boolean saveMetadata() {
try {
FileUtils.copy(_matadata.toString().getBytes(CHARSET), new File(_file_metadata));
} catch (Throwable t) {
return false;
}
return true;
}
}