package ddth.dasp.common.config.impl;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import ddth.dasp.common.config.IConfigDao;
import ddth.dasp.common.utils.JsonUtils;
import ddth.dasp.common.utils.RegExpUtils;
/**
* File-based {@link IConfigDao}.
*
* @author NBThanh <btnguyen2k@gmail.com>
*/
public class JsonFileBasedConfigDao extends AbstractConfigDao {
public final static String OSGI_PROP_STORAGE = "osgi.dasp.config.dao.file.storage";
private Logger LOGGER = LoggerFactory.getLogger(JsonFileBasedConfigDao.class);
private File _storageDir;
private Cache<String, Object> cache;
/**
* {@inheritDoc}
*/
public void destroy(BundleContext bundleContext) {
if (cache != null) {
cache.cleanUp();
cache = null;
}
}
/**
* {@inheritDoc}
*/
public void init(BundleContext bundleContext) {
String storageDir = bundleContext.getProperty(OSGI_PROP_STORAGE);
if (LOGGER.isDebugEnabled()) {
String msg = "Storage directory configuration: " + storageDir;
LOGGER.debug(msg);
}
if (StringUtils.isBlank(storageDir)) {
throw new RuntimeException("Storage directory is not set!");
}
Pattern PATTERN = Pattern.compile("\\$\\{([^}]+)\\}");
Matcher m = PATTERN.matcher(storageDir);
StringBuffer sb = new StringBuffer();
while (m.find()) {
String replacement = System.getProperty(m.group(1), "");
m.appendReplacement(sb, RegExpUtils.regexpReplacementEscape(replacement));
}
m.appendTail(sb);
_storageDir = new File(sb.toString());
if (LOGGER.isDebugEnabled()) {
String msg = "Storage directory: " + _storageDir.getAbsolutePath();
LOGGER.debug(msg);
}
if (!_storageDir.isDirectory()) {
_storageDir.mkdirs();
}
if (!_storageDir.isDirectory()) {
throw new RuntimeException("[" + _storageDir.getAbsolutePath()
+ "] is not a directory or not writable!");
}
int numProcessores = Runtime.getRuntime().availableProcessors();
CacheBuilder<Object, Object> cacheBuider = CacheBuilder.newBuilder();
cacheBuider.concurrencyLevel(Math.max(numProcessores / 2, 2));
long capacity = 100;
long expireAfterAccess = 3600;
long expireAfterWrite = 3600;
if (expireAfterAccess > 0) {
cacheBuider.expireAfterAccess(expireAfterAccess, TimeUnit.SECONDS);
} else if (expireAfterWrite > 0) {
cacheBuider.expireAfterWrite(expireAfterWrite, TimeUnit.SECONDS);
}
cacheBuider.maximumSize(capacity);
cache = cacheBuider.build();
}
protected boolean validateModule(String module) {
return !StringUtils.isBlank(module) && StringUtils.isAlphanumeric(module);
}
protected File moduleNameToFile(String module) {
return new File(_storageDir, module.toLowerCase() + ".json");
}
@SuppressWarnings("unchecked")
synchronized protected Map<String, Object> loadModuleConfig(String module) {
if (!validateModule(module)) {
throw new RuntimeException("Module [" + module + "] is invalid!");
}
File file = moduleNameToFile(module);
try {
String fileContent = FileUtils.readFileToString(file, "UTF-8");
try {
return JsonUtils.fromJson(fileContent, Map.class);
} catch (Exception e) {
return new HashMap<String, Object>();
}
} catch (IOException e) {
return new HashMap<String, Object>();
}
}
synchronized protected void storeModuleConfig(String module, Map<String, Object> moduleConfig) {
if (!validateModule(module)) {
throw new RuntimeException("Module [" + module + "] is invalid!");
}
if (moduleConfig != null) {
File file = moduleNameToFile(module);
try {
String fileContent = JsonUtils.toJson(moduleConfig);
FileUtils.write(file, fileContent, "UTF-8");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
/**
* {@inheritDoc}
*/
@Override
public void setConfig(String module, String key, Object value) {
Map<String, Object> moduleConfig = loadModuleConfig(module);
moduleConfig.put(key, value);
storeModuleConfig(module, moduleConfig);
}
/**
* {@inheritDoc}
*/
@Override
public Object getConfig(String module, String key) {
Map<String, Object> moduleConfig = loadModuleConfig(module);
return moduleConfig.get(key);
}
}