package eu.clarin.cmdi.mdservice.action; import java.io.*; import java.net.MalformedURLException; import java.net.URL; /*import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.Writer; */ import java.util.Date; import java.util.HashMap; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Calendar; import javax.xml.*; import javax.xml.parsers.*; import javax.xml.transform.*; import javax.xml.transform.sax.*; import javax.xml.transform.stream.*;import javax.xml.transform.dom.*; import javax.xml.xpath.*; import org.w3c.dom.*; import org.xml.sax.SAXException; import org.xml.sax.InputSource; import org.apache.commons.lang.StringEscapeUtils; import eu.clarin.cmdi.mdservice.action.Admin; import eu.clarin.cmdi.mdservice.model.Query; /** * This is a rudimentary caching mechanism. * It serializes the inputstream to a file (identifier => filename) (putInCache()) * or returns the inputstream based on the identifier (getFromCache()) * *
It maintains the cache_index (persisted as xml-file in the cache-folder) * mapping the request parameters to the indexed files.
* * This is an internal object, direct user access to cache-data via interface is only possible viaAdminAction
* @author master
*
*/
public class Cache {
public static String PREFIX = "xc_";
public static String USE = "use";
public static String REFRESH = "refresh";
public static String SKIP= "skip";
private static Cache singleton;
private String cachepath;
private String cacheindex_path;
private static Integer cachecounter;
private static final Integer start_cache = 1;
private static Document cacheindex_doc;
public Cache () {
cachepath = Admin.getConfig().getProperty("cache.path");
cacheindex_path = cachepath + Admin.getConfig().getProperty("cacheindex.file");
cachecounter = initCachecounter();
}
public static Cache getCache() {
if (singleton == null) {
singleton = new Cache();
}
return singleton;
}
public String getCacheIndexPath() {
return getCache().cacheindex_path;
}
protected void finalize() throws Throwable {
try {
updateCachecounter();
} catch(Exception e) {
}
finally {
super.finalize();
//more code can be written here as per need of application
}
}
/**
* Here the external key for the data gets cache-internal counter-id assigned
* which is also returned back.
*
* The external key gets parsed and put as individual attributes in the
*
*
*
* @param key_info a complex string carrying all relevant parameters
* @param instream data to be stored
* @return
*/
public String putInCache(String key_info, InputStream instream) {
Admin.notifyUser("CACHE.putInCache:"+key_info);
Integer c = getCounter();
String xc;
//update xml_structure
Element e = cacheindex_doc.createElement("f");
//Attr attr = cacheindex_doc.createAttribute("id");
//attr.setValue(c.toString());
//e.setNamedItem(attr);
e.setAttribute("id", c.toString());
String[] key_array = key_info.split("//-");
e.setAttribute("type", key_array[0]);
if (key_array.length > 1){
String query_str;
if (key_array[0].equals("recordset")){
query_str = transformQuery(key_array[1]);
} else {
query_str = key_array[1];
}
e.setAttribute("query", query_str);
}else{
e.setAttribute("query", "");
}
if (key_array.length > 2){
e.setAttribute("collection", key_array[2]);
}else{
e.setAttribute("collection", "");
}
if (key_array.length > 3){
e.setAttribute("squery", key_array[3]);
}else{
e.setAttribute("squery", "");
}
if (key_array.length > 4){
e.setAttribute("startItem", key_array[4]);
}else{
e.setAttribute("startItem", "");
}
if (key_array.length > 5){
e.setAttribute("maximumItems", key_array[5]);
}else{
e.setAttribute("maximumItems", "");
}
if (key_array.length > 6){
e.setAttribute("repository", key_array[6]);
}else{
e.setAttribute("repository", "");
}
if (key_array.length > 7){
e.setAttribute("maxDepth", key_array[7]);
}else{
e.setAttribute("maxDepth", "");
}
if (key_array.length > 8){
e.setAttribute("lang", key_array[8]);
}else{
e.setAttribute("lang", "");
}
if (key_array.length > 9){
e.setAttribute("duration", key_array[9]);
}else{
e.setAttribute("duration", "");
}
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
e.setAttribute("date", dateFormat.format(new Date()).toString());
cacheindex_doc.getFirstChild().appendChild(e);
// update XML-counter
//Admin.writeToFile(formPath(id + xc),instream);
updateCachecounter();
xc = PREFIX + key_array[0] + "_" + c.toString();
Admin.notifyUser("CACHE.putInCache.filename:" + xc + ".xml");
Admin.writeToFile(cachepath + xc + ".xml",instream);
return xc;
}
public InputStream getFromCache(String key_info) {
File f = new File (formPath(key_info));
//Admin.notifyUser("CACHE.getFromCache:"+key_info);
if (f.exists()) { // read from file to InputStream;
Admin.notifyUser("CACHE.getFromCache.fromfile:"+f.getName() + "[#" + key_info + "]");
InputStream instream;
try {
instream = new FileInputStream(f);
return instream;
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
} else { //not cached, my dear
Admin.notifyUser("CACHE.getFromCache: NOT CACHED" + "[#" + key_info + "]");
return null;
}
}
private String transformQuery (String str) {
String transformed;
Query query;
if (str == null) return "";
if (str.trim().length() == 0) return "";
// provisional hack, setting simple string to ""
query = new Query("", str,"recordset","");
if (query.isStatus(Query.PARSEERROR)) {
Admin.notifyUser("Cache.transformQuery.PARSEERROR:" + query.getMsg());
// pass this bad news to the client
//setUserMsg(query.getMsg());
transformed = "";
} else {
transformed = Query.getSimpleQueryString(str);
transformed = StringEscapeUtils.escapeXml(transformed);
//Admin.notifyUser("CACHE.transformQuery:"+transformed);
}
return transformed;
}
//TODO: sanitize-key
public String formPath (String key_info) {
String id="";
String path="";
String xpath_expr="";
String[] key_array = key_info.split("//-");
String query_str;
if(key_array.length > 1){
// Admin.notifyUser("formPATH- querystring:" + key_array[1]);
if (key_array[0].equals("recordset")){
query_str = this.transformQuery(key_array[1]);
// Admin.notifyUser("formPATH- querystring-transformed:" + query_str);
}
else {
query_str = key_array[1];
}
} else {
query_str = "";
}
xpath_expr = "//index/f[@type='" + key_array[0] + "'";
xpath_expr = xpath_expr + " and @query='"+query_str+"'";
if (key_array.length > 2){
xpath_expr = xpath_expr + "and @collection='"+key_array[2]+"'";
}else{
xpath_expr = xpath_expr + " and @collection=''";
}
if (key_array.length > 3){
xpath_expr = xpath_expr + "and @squery='"+key_array[3]+"'";
}else{
xpath_expr = xpath_expr + " and @squery=''";
}
if (key_array.length > 4){
xpath_expr = xpath_expr + "and @startItem='"+key_array[4]+"'";
}else{
xpath_expr = xpath_expr + " and @startItem=''";
}
if (key_array.length > 5){
xpath_expr = xpath_expr + "and @maximumItems='"+key_array[5]+"'";
}else{
xpath_expr = xpath_expr + " and @maximumItems=''";
}
if (key_array.length > 6){
xpath_expr = xpath_expr + "and @repository='"+key_array[6]+"'";
}else{
xpath_expr = xpath_expr + " and @repository=''";
}
if (key_array.length > 7){
xpath_expr = xpath_expr + "and @maxDepth='"+key_array[7]+"'";
}else{
xpath_expr = xpath_expr + " and @maxDepth=''";
}
if (key_array.length > 8){
xpath_expr = xpath_expr + "and @lang='"+key_array[8]+"']";
}else{
xpath_expr = xpath_expr + " and @lang='']";
}
//Admin.notifyUser("formPath:xpath:"+xpath_expr);
//creating an XPathFactory:
XPathFactory factory = XPathFactory.newInstance();
//using this factory to create an XPath object:
XPath xpath = factory.newXPath();
//XPath object created compiles the XPath expression:
XPathExpression expr;
try {
expr = xpath.compile(xpath_expr);
//expression is evaluated with respect to a certain context node which is doc.
Object result = expr.evaluate(cacheindex_doc, XPathConstants.NODESET);
NodeList list = (NodeList) result;
if (list.getLength() > 0) {
id = list.item(0).getAttributes().getNamedItem("id").getNodeValue();
path = cachepath + PREFIX + key_array[0] + "_"+id + ".xml";
} else if (list.getLength() > 1){
Admin.notifyUser("formPath ERROR:!!!:multiple paths:"+key_info);
}
} catch (XPathExpressionException e) {
// TODO Auto-generated catch block
Admin.notifyUser("ERROR Cache.formPath: "+xpath_expr);
}
return path;
}
public Integer getCounter () {
cachecounter = cachecounter +1 ;
return cachecounter;
}
/**
* read counter-integer from file in cache
* or start that file
* @return The current maximum cache counter
*/
public Integer initCachecounter() {
Integer counter = start_cache;
boolean init=false;
String fname = cacheindex_path;
File f = new File (fname);
//Admin.notifyUser("initCacheCounter");
if (!f.exists()) {
// create new counter document
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder;
try {
docBuilder = docFactory.newDocumentBuilder();
cacheindex_doc = docBuilder.newDocument();
// append root tag