package com.meidusa.amoeba.config.loader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.log4j.Logger;
import org.apache.log4j.helpers.LogLog;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import com.meidusa.amoeba.config.BeanObjectEntityConfig;
import com.meidusa.amoeba.config.loader.util.ConfigLoaderUtil;
import com.meidusa.amoeba.exception.ConfigurationException;
import com.meidusa.amoeba.exception.InitialisationException;
import com.meidusa.amoeba.route.AbstractQueryRouter;
/**
*
* @author struct
*
* @param <K>
* @param <V>
*/
public abstract class FunctionFileLoader<K, V> {
private static Logger logger = Logger.getLogger(FunctionFileLoader.class);
private String dtdPath = "/com/meidusa/amoeba/xml/function.dtd";
private String dtdSystemID = "function.dtd";
private String funcFile;
private long lastFuncFileModified;
public void setFuncFile(String funcFile) {
try {
this.funcFile = new File(funcFile).getCanonicalPath();
} catch (IOException e) {
throw new ConfigurationException(e);
}
}
public void loadFunctionMap(Map funMap) {
DocumentBuilder db;
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setValidating(true);
dbf.setNamespaceAware(false);
db = dbf.newDocumentBuilder();
db.setEntityResolver(new EntityResolver() {
public InputSource resolveEntity(String publicId, String systemId) {
if (systemId.endsWith(dtdSystemID)) {
InputStream in = this.getClass().getResourceAsStream(dtdPath);
if (in == null) {
LogLog.error("Could not find [" + dtdSystemID + "]. Used ["
+ AbstractQueryRouter.class.getClassLoader() + "] class loader in the search.");
return null;
} else {
return new InputSource(in);
}
} else {
return null;
}
}
});
db.setErrorHandler(new ErrorHandler() {
public void warning(SAXParseException exception) {}
public void error(SAXParseException exception) throws SAXException {
logger.error(exception.getMessage() + " at (" + exception.getLineNumber() + ":"
+ exception.getColumnNumber() + ")");
throw exception;
}
public void fatalError(SAXParseException exception) throws SAXException {
logger.fatal(exception.getMessage() + " at (" + exception.getLineNumber() + ":"
+ exception.getColumnNumber() + ")");
throw exception;
}
});
loadFunctionFile(funcFile, db, funMap);
} catch (Exception e) {
logger.fatal("Could not load configuration file, failing", e);
throw new ConfigurationException("Error loading configuration file " + funcFile, e);
} finally {
lastFuncFileModified = new File(funcFile).lastModified();
}
}
private void loadFunctionFile(String fileName, DocumentBuilder db, Map<K, V> funMap)
throws InitialisationException {
Document doc = null;
InputStream is = null;
try {
is = new FileInputStream(new File(fileName));
if (is == null) {
throw new Exception("Could not open file " + fileName);
}
doc = db.parse(is);
} catch (Exception e) {
final String s = "Caught exception while loading file " + fileName;
logger.error(s, e);
throw new ConfigurationException(s, e);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
logger.error("Unable to close input stream", e);
}
}
}
Element rootElement = doc.getDocumentElement();
NodeList children = rootElement.getChildNodes();
int childSize = children.getLength();
for (int i = 0; i < childSize; i++) {
Node childNode = children.item(i);
if (childNode instanceof Element) {
Element child = (Element) childNode;
final String nodeName = child.getNodeName();
if (nodeName.equals("function")) {
V function = loadFunction(child);
putToMap(funMap, function);
}
}
}
if (logger.isInfoEnabled()) {
logger.info("Loaded function configuration from: " + fileName);
}
}
public abstract void putToMap(Map<K, V> map, V value);
public abstract void initBeanObject(BeanObjectEntityConfig config, V bean);
@SuppressWarnings("unchecked")
protected V loadFunction(Element current) {
BeanObjectEntityConfig config = ConfigLoaderUtil.loadBeanConfig(current);
V function = (V) config.createBeanObject(true);
initBeanObject(config, function);
return function;
}
public boolean needLoad() {
if (new File(funcFile).lastModified() != lastFuncFileModified) {
return true;
}
return false;
}
}