package org.smartly.commons.io.temprepository;
import org.smartly.commons.io.FileObserver;
import org.smartly.commons.io.IFileObserverListener;
import org.smartly.commons.logging.Level;
import org.smartly.commons.logging.Logger;
import org.smartly.commons.logging.LoggingRepository;
import org.smartly.commons.logging.util.LoggingUtils;
import org.smartly.commons.util.FileUtils;
import org.smartly.commons.util.FormatUtils;
import org.smartly.commons.util.PathUtils;
import org.smartly.commons.util.StringUtils;
import java.io.IOException;
/**
* Repository with expiration time for its content.
* Expired files are removed
*/
public class TempRepository
implements IFileObserverListener {
private static final String REGISTRY_LOG = "_registry.log";
private static final String REGISTRY_SETTINGS = "_registry_settings.json";
private static final String REGISTRY_DATA = "_registry_data.json";
private static final String LOGGER_PREFIX = "[" + TempRepository.class.getName() + "] ";
private static final int MAX_ERRORS = 10;
private final String _root;
private final String _path_data;
private final String _path_settings;
private final String _path_log;
private final Registry _registry;
private FileObserver _dirObserver;
private int _countErrors;
private boolean _debugMode;
public TempRepository(final String root) throws IOException {
_root = root;
_path_data = PathUtils.concat(_root, REGISTRY_DATA);
_path_settings = PathUtils.concat(_root, REGISTRY_SETTINGS);
_path_log = PathUtils.concat(_root, REGISTRY_LOG);
LoggingRepository.getInstance().setAbsoluteLogFileName(REGISTRY_LOG, _path_log);
//-- ensure temp dir exists --//
FileUtils.mkdirs(root);
//-- load file registry (creates if any) --//
_registry = new Registry(_path_settings, _path_data);
_registry.save();
_countErrors = 0;
_debugMode = false;
this.startThreads();
}
@Override
protected void finalize() throws Throwable {
this.interrupt();
super.finalize();
}
@Override
public void onEvent(int event, final String path) {
this.handle(event, path);
}
public String getRoot() {
return _root;
}
public boolean isDebugMode() {
return _debugMode;
}
public void setDebugMode(final boolean value) {
_debugMode = value;
this.debug("Debug Mode: " + value);
}
public void setDuration(final long ms) {
_registry.interrupt();
_registry.setLife(ms);
_registry.start();
}
public void setCheckTime(final long ms) {
_registry.interrupt();
_registry.setCheck(ms);
_registry.start();
}
public void interrupt() {
this.stopThreads();
try {
_registry.save();
} catch (Throwable ignored) {
}
}
/**
* Created only for test purpose.
*/
public void join() throws InterruptedException {
_registry.join();
}
public void clear() {
//-- stop threads--//
this.stopThreads();
//-- clear root --//
try {
FileUtils.delete(_root);
FileUtils.mkdirs(_root);
} catch (Throwable ignored) {
}
//-- reset registry--//
try {
_registry.clear();
_registry.save();
} catch (Throwable ignored) {
}
//-- start --//
this.startThreads();
}
// ------------------------------------------------------------------------
// p r i v a t e
// ------------------------------------------------------------------------
private Logger getLogger() {
return LoggingUtils.getLogger(REGISTRY_LOG);
}
private void startThreads() {
try {
this.startDirObserver();
this.debug("Started Path Observer");
} catch (Throwable t) {
this.getLogger().log(Level.SEVERE, null, t);
}
try {
_registry.start();
this.debug("Started Registry");
} catch (Throwable t) {
this.getLogger().log(Level.SEVERE, null, t);
}
}
private void stopThreads() {
try {
_dirObserver.interrupt();
_dirObserver = null;
} catch (Throwable ignored) {
}
try {
_registry.interrupt();
} catch (Throwable ignored) {
}
}
private void startDirObserver() throws IOException {
//-- file observer initialization --//
if (null != _dirObserver) {
_dirObserver.interrupt();
_dirObserver = null;
}
_dirObserver = new FileObserver(_root, true, false, FileObserver.ALL_EVENTS, this);
_dirObserver.startWatching();
}
private void handle(final int event, final String path) {
if (!_path_log.equalsIgnoreCase(path)) {
String sevent = "UNDEFINED";
try {
if (event == FileObserver.EVENT_CREATE) {
sevent = "CREATE";
// CREATE
if (!_path_data.equalsIgnoreCase(path)
&& !_path_settings.equalsIgnoreCase(path)) {
if (_registry.addItem(path)) {
_registry.save();
this.debug(FormatUtils.format("Action '{0}' on '{1}'", sevent, path));
}
}
} else if (event == FileObserver.EVENT_MODIFY) {
sevent = "MODIFY";
// MODIFY
if (_path_settings.equalsIgnoreCase(path)) {
_registry.reloadSettings();
this.debug("Changed Settings: reload all settings from file.");
}
} else if (event == FileObserver.EVENT_DELETE) {
sevent = "DELETE";
if (!_path_data.equalsIgnoreCase(path)
&& !_path_settings.equalsIgnoreCase(path)) {
if (_registry.removeItem(path)) {
_registry.save();
this.debug(FormatUtils.format("Action '{0}' on '{1}'", sevent, path));
}
} else {
_registry.clear();
_registry.save();
this.debug("Removed DATA file: reset of registry.");
}
}
} catch (final Throwable t) {
final String msg = FormatUtils.format("Error on '{0}' path '{1}' to temp repository: {2}",
sevent, path, t);
this.handleError(msg, t);
}
}
}
public void handleError(final String message,
final Throwable t) {
if (_countErrors < MAX_ERRORS) {
_countErrors++;
if (StringUtils.hasText(message)) {
this.getLogger().log(Level.SEVERE, LOGGER_PREFIX.concat(message), t);
} else {
this.getLogger().log(Level.SEVERE,
LOGGER_PREFIX.concat(FormatUtils.format("{0}", t)),
t);
}
} else {
this.interrupt();
}
}
public void debug(final String message) {
if (_debugMode) {
this.getLogger().log(Level.INFO, LOGGER_PREFIX.concat(message));
}
}
}