package org.krakenapps.logdb.impl;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.felix.ipojo.annotations.Component;
import org.apache.felix.ipojo.annotations.Invalidate;
import org.apache.felix.ipojo.annotations.Provides;
import org.apache.felix.ipojo.annotations.Requires;
import org.apache.felix.ipojo.annotations.Validate;
import org.krakenapps.confdb.Config;
import org.krakenapps.confdb.ConfigCollection;
import org.krakenapps.confdb.ConfigDatabase;
import org.krakenapps.confdb.ConfigService;
import org.krakenapps.confdb.Predicates;
import org.krakenapps.logdb.CsvLookupRegistry;
import org.krakenapps.logdb.LookupHandler;
import org.krakenapps.logdb.LookupHandlerRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import au.com.bytecode.opencsv.CSVReader;
/**
* If you need per-user csv lookup management, implement or use other service
* component. This csv lookup service provides only global configuration.
*
* @author xeraph
*
*/
@Component(name = "logdb-csv-lookup-registry")
@Provides
public class CsvLookupRegistryImpl implements CsvLookupRegistry {
private final Logger logger = LoggerFactory.getLogger(CsvLookupRegistryImpl.class);
@Requires
private ConfigService conf;
@Requires
private LookupHandlerRegistry lookup;
@Validate
public void start() {
for (File f : getCsvFiles()) {
String name = getLookupName(f);
try {
logger.debug("kraken logdb: adding csv lookup handler [{}]", name);
lookup.addLookupHandler(name, new CsvLookupHandler(f));
} catch (Throwable t) {
logger.error("kraken logdb: cannot add csv lookup handler - " + name, t);
}
}
}
@Invalidate
public void stop() {
for (File f : getCsvFiles()) {
String name = getLookupName(f);
try {
logger.debug("kraken logdb: removing csv lookup handler [{}]", name);
lookup.removeLookupHandler(name);
} catch (Throwable t) {
logger.error("kraken logdb: cannot remove csv lookup handler - " + name, t);
}
}
}
@Override
public Set<File> getCsvFiles() {
ConfigDatabase db = conf.ensureDatabase("kraken-logdb");
ConfigCollection col = db.ensureCollection("csv_lookups");
Set<File> files = new HashSet<File>();
for (Object o : col.findAll().getDocuments()) {
@SuppressWarnings("unchecked")
Map<String, Object> m = (Map<String, Object>) o;
files.add(new File((String) m.get("path")));
}
return files;
}
@Override
public void loadCsvFile(File f) throws IOException {
if (f == null)
throw new IllegalArgumentException("csv path should not be null");
if (!f.exists())
throw new IllegalStateException("csv path doesn't exist: " + f.getAbsolutePath());
if (!f.isFile())
throw new IllegalStateException("csv path is not file: " + f.getAbsolutePath());
if (!f.canRead())
throw new IllegalStateException("cannot read csv file, check read permission: " + f.getAbsolutePath());
ConfigDatabase db = conf.ensureDatabase("kraken-logdb");
ConfigCollection col = db.ensureCollection("csv_lookups");
// check duplicate
Config c = col.findOne(Predicates.field("path", f.getAbsolutePath()));
if (c != null)
throw new IllegalStateException("csv path already exists: " + f.getAbsolutePath());
// add to lookup handler service
lookup.addLookupHandler(getLookupName(f), new CsvLookupHandler(f));
// add
Map<String, Object> doc = new HashMap<String, Object>();
doc.put("path", f.getAbsolutePath());
col.add(doc);
}
@Override
public void unloadCsvFile(File f) {
if (f == null)
throw new IllegalArgumentException("csv path should not be null");
ConfigDatabase db = conf.ensureDatabase("kraken-logdb");
ConfigCollection col = db.ensureCollection("csv_lookups");
// check existence
Config c = col.findOne(Predicates.field("path", f.getAbsolutePath()));
if (c == null)
throw new IllegalStateException("not registered path: " + f.getAbsolutePath());
c.remove();
// remove from lookup handler service
lookup.removeLookupHandler(getLookupName(f));
}
private String getLookupName(File f) {
return "csv$" + f.getName();
}
private class CsvLookupHandler implements LookupHandler {
private String keyFieldName;
private ArrayList<String> valueFieldNames;
private Map<String, Map<String, String>> mappings = new HashMap<String, Map<String, String>>();
public CsvLookupHandler(File f) throws IOException {
CSVReader reader = new CSVReader(new FileReader(f));
String[] nextLine = reader.readNext();
if (nextLine == null)
throw new IllegalStateException("header columns not found");
if (nextLine.length < 2)
throw new IllegalStateException("not enough columns (should be 2 or more)");
keyFieldName = nextLine[0];
valueFieldNames = new ArrayList<String>(nextLine.length - 1);
for (int i = 1; i < nextLine.length; i++)
valueFieldNames.add(nextLine[i]);
while ((nextLine = reader.readNext()) != null) {
Map<String, String> values = new HashMap<String, String>();
for (int i = 1; i < nextLine.length; i++) {
String valueFieldName = valueFieldNames.get(i - 1);
String value = nextLine[i];
values.put(valueFieldName, value);
}
mappings.put(nextLine[0], values);
}
}
@Override
public Object lookup(String srcField, String dstField, Object srcValue) {
if (!srcField.equals(keyFieldName))
return null;
if (!valueFieldNames.contains(dstField))
return null;
Map<String, String> valueMappings = mappings.get(srcValue.toString());
if (valueMappings == null)
return null;
return valueMappings.get(dstField);
}
}
}