source: MDService2/trunk/MDService2/src/eu/clarin/cmdi/mdservice/action/Cache.java

Last change on this file was 1495, checked in by vronk, 13 years ago

started cleaning up code, adding inline-documentation;
also changes to output method in xsl (xhtml)

File size: 18.6 KB
RevLine 
[466]1package eu.clarin.cmdi.mdservice.action;
2
[635]3import java.io.*;
4import java.net.MalformedURLException;
5import java.net.URL;
6/*import java.io.BufferedWriter;
[466]7import java.io.File;
8import java.io.FileInputStream;
9import java.io.FileNotFoundException;
10import java.io.FileReader;
11import java.io.FileWriter;
12import java.io.IOException;
13import java.io.InputStream;
14import java.io.Writer;
[635]15*/
16import java.util.Date;
[980]17import java.util.HashMap;
[635]18import java.text.DateFormat;
19import java.text.SimpleDateFormat;
20import java.util.Calendar;
21 
22import javax.xml.*;
23import javax.xml.parsers.*;
24import javax.xml.transform.*;
25import javax.xml.transform.sax.*;
[655]26import javax.xml.transform.stream.*;import javax.xml.transform.dom.*;
[635]27import javax.xml.xpath.*;
[466]28
[635]29import org.w3c.dom.*;
30import org.xml.sax.SAXException;
31import org.xml.sax.InputSource;
[704]32import org.apache.commons.lang.StringEscapeUtils; 
[635]33
34
35import eu.clarin.cmdi.mdservice.action.Admin;
36import eu.clarin.cmdi.mdservice.model.Query;
37
[466]38/**
39 * This is a rudimentary caching mechanism.
[1495]40 * It serializes the inputstream to a file (identifier => filename) (putInCache())
41 * or returns the inputstream based on the identifier (getFromCache())
[1234]42 *
[1495]43 * <p>It maintains the cache_index (persisted as xml-file in the cache-folder)
44 * mapping the request parameters to the indexed files.</p>
[1234]45 *
46 * This is an internal object, direct user access to cache-data via interface is only possible via <code>AdminAction</code>
[466]47 * @author master
48 *
49 */
50
51public class Cache {
[635]52        public static String PREFIX = "xc_";
[466]53       
[689]54        public static String USE = "use";
55        public static String REFRESH = "refresh";
56        public static String SKIP= "skip";     
57       
[466]58        private static Cache singleton;
59        private String cachepath; 
[655]60        private String cacheindex_path;
[651]61        private static Integer cachecounter;
[466]62        private static final Integer start_cache = 1;
63       
[655]64        private static Document cacheindex_doc;
[466]65       
[676]66       
[466]67        public Cache () {               
68                cachepath = Admin.getConfig().getProperty("cache.path");
[655]69                cacheindex_path = cachepath + Admin.getConfig().getProperty("cacheindex.file");
[466]70                cachecounter = initCachecounter();
[890]71               
[466]72        }
73       
74        public static Cache getCache() {
75                if (singleton == null) {
76                        singleton = new Cache();
77                } 
78                return singleton;
79        }
80
[890]81        public String getCacheIndexPath() {
82                return getCache().cacheindex_path;
83               
84        }
85
[466]86        protected void finalize() throws Throwable {       
87            try {               
88                updateCachecounter();
89            } catch(Exception e) {
90            }       
91            finally {           
92                super.finalize();
93                //more code can be written here as per need of application             
94            }
95        }
96       
97        /**
[1234]98         * Here the external key for the data gets cache-internal counter-id assigned
99         * which is also returned back.
100         *
101         * The external key gets parsed and put as individual attributes in the <f>-element:
102         *
103         * <code>
104         * <f collection="" date="2011-04-20 01:06:50" duration="0.227" id="3" lang="en"
105     *   maxDepth="1"
106     *   maximumItems=""
107     *   query=""
108     *   repository="localhost-mirror"
109     *   squery=""
110     *   startItem=""
111     *   type="collections"/>
112      </code>
113         * 
114         *
115         * @param key_info a complex string carrying all relevant parameters
116         * @param instream data to be stored
[466]117         * @return
118         */
[635]119        public String putInCache(String key_info, InputStream instream) {
[466]120
[635]121                Admin.notifyUser("CACHE.putInCache:"+key_info);
[466]122                Integer c = getCounter();
[635]123                String xc;
124               
125               
126                //update xml_structure
[655]127                Element e = cacheindex_doc.createElement("f");
128                //Attr attr = cacheindex_doc.createAttribute("id");
[635]129                //attr.setValue(c.toString());
130                //e.setNamedItem(attr);
131                e.setAttribute("id", c.toString());
[704]132                String[] key_array = key_info.split("//-");
[635]133               
134                e.setAttribute("type", key_array[0]);
135                if (key_array.length > 1){
136                        String query_str;
137                        if (key_array[0].equals("recordset")){
138                                query_str = transformQuery(key_array[1]);
139                        } else {
140                                query_str = key_array[1];
141                        }
142                        e.setAttribute("query", query_str);
143                }else{
144                        e.setAttribute("query", "");
145                }
146                if (key_array.length > 2){
147                        e.setAttribute("collection", key_array[2]);
148                }else{
149                        e.setAttribute("collection", "");
150                }
[713]151                if (key_array.length > 3){
[745]152                        e.setAttribute("squery", key_array[3]);
[713]153                }else{
[745]154                        e.setAttribute("squery", "");
[713]155                }
156                if (key_array.length > 4){
[1069]157                        e.setAttribute("startItem", key_array[4]);
[713]158                }else{
[1069]159                        e.setAttribute("startItem", "");
[745]160                }
161                if (key_array.length > 5){
[1069]162                        e.setAttribute("maximumItems", key_array[5]);
[745]163                }else{
[1069]164                        e.setAttribute("maximumItems", "");
[713]165                }
[832]166               
167                if (key_array.length > 6){
168                        e.setAttribute("repository", key_array[6]);
169                }else{
170                        e.setAttribute("repository", "");
171                }
172                if (key_array.length > 7){
173                        e.setAttribute("maxDepth", key_array[7]);
174                }else{
175                        e.setAttribute("maxDepth", "");
176                }
177                if (key_array.length > 8){
178                        e.setAttribute("lang", key_array[8]);
179                }else{
180                        e.setAttribute("lang", "");
181                }
[870]182                if (key_array.length > 9){
183                        e.setAttribute("duration", key_array[9]);
184                }else{
185                        e.setAttribute("duration", "");
186                }
[832]187               
[1029]188                DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
[635]189                e.setAttribute("date", dateFormat.format(new Date()).toString());
[655]190                cacheindex_doc.getFirstChild().appendChild(e);
[635]191               
192                // update XML-counter
[521]193            //Admin.writeToFile(formPath(id + xc),instream);
[651]194               
[635]195                updateCachecounter();
196               
197                xc = PREFIX + key_array[0] + "_" + c.toString();
[655]198                Admin.notifyUser("CACHE.putInCache.filename:" + xc + ".xml");
[635]199                Admin.writeToFile(cachepath + xc + ".xml",instream);
200               
[466]201            return xc;
202        }
203       
204       
[635]205        public InputStream getFromCache(String key_info) {
[655]206                   
[635]207               
208                   File f = new File (formPath(key_info));
[1076]209                   //Admin.notifyUser("CACHE.getFromCache:"+key_info);
[655]210                   
[676]211                   
[466]212                    if (f.exists()) { // read from file to InputStream;
[1076]213                        Admin.notifyUser("CACHE.getFromCache.fromfile:"+f.getName() + "[#" + key_info + "]");
[466]214                        InputStream instream;
215                                try {
[582]216                                        instream = new FileInputStream(f); 
217
[466]218                                        return instream;
219                                } catch (FileNotFoundException e) {
220                                        // TODO Auto-generated catch block
221                                        e.printStackTrace();
222                                        return null;
223                                }
224                       
225                    } else { //not cached, my dear
[1076]226                        Admin.notifyUser("CACHE.getFromCache: NOT CACHED" + "[#" + key_info + "]");
[466]227                        return null;
228                    }       
229        }
230 
[635]231        private String transformQuery (String str) {
232                String transformed;
233                Query query;
234               
[745]235                if (str == null) return "";
236                if (str.trim().length() == 0) return "";
237               
[764]238                // provisional hack, setting simple string to ""
239                query = new Query("", str,"recordset","");
[635]240                if (query.isStatus(Query.PARSEERROR)) {
241                        Admin.notifyUser("Cache.transformQuery.PARSEERROR:" + query.getMsg());
242                        // pass this bad news to the client
243                        //setUserMsg(query.getMsg());
244                        transformed = "";
245                } else {
[774]246                        transformed =  Query.getSimpleQueryString(str);
[704]247                        transformed = StringEscapeUtils.escapeXml(transformed);
248                        //Admin.notifyUser("CACHE.transformQuery:"+transformed);
[635]249                }
250                return transformed;
251        }
252       
[980]253       
[466]254         //TODO: sanitize-key
[635]255        public String formPath (String key_info) {
256                String id="";
257                String path="";
258                String xpath_expr="";
259               
[704]260                String[] key_array = key_info.split("//-");
[745]261                String query_str;               
[635]262               
263                if(key_array.length > 1){
[1076]264                //      Admin.notifyUser("formPATH- querystring:" + key_array[1]);
[635]265                        if (key_array[0].equals("recordset")){
[745]266                                query_str = this.transformQuery(key_array[1]); 
[1076]267                        //      Admin.notifyUser("formPATH- querystring-transformed:" + query_str);
[635]268                        }
269                        else {
270                                query_str = key_array[1];
271                        }
272                } else {
273                        query_str = "";
274                }
275                xpath_expr = "//index/f[@type='" + key_array[0] + "'";
276                xpath_expr = xpath_expr + " and @query='"+query_str+"'";
277               
278                if (key_array.length > 2){
[713]279                        xpath_expr = xpath_expr + "and @collection='"+key_array[2]+"'";
[635]280                }else{
[713]281                        xpath_expr = xpath_expr + " and @collection=''";
[635]282                }
[713]283                if (key_array.length > 3){
[745]284                        xpath_expr = xpath_expr + "and @squery='"+key_array[3]+"'";
[713]285                }else{
[745]286                        xpath_expr = xpath_expr + " and @squery=''";
[713]287                }
288                if (key_array.length > 4){
[1069]289                        xpath_expr = xpath_expr + "and @startItem='"+key_array[4]+"'";
[713]290                }else{
[1069]291                        xpath_expr = xpath_expr + " and @startItem=''";
[745]292                }
293                if (key_array.length > 5){
[1069]294                        xpath_expr = xpath_expr + "and @maximumItems='"+key_array[5]+"'";
[745]295                }else{
[1069]296                        xpath_expr = xpath_expr + " and @maximumItems=''";
[713]297                }
[635]298               
[832]299                if (key_array.length > 6){
300                        xpath_expr = xpath_expr + "and @repository='"+key_array[6]+"'";
301                }else{
302                        xpath_expr = xpath_expr + " and @repository=''";
303                }
304                if (key_array.length > 7){
305                        xpath_expr = xpath_expr + "and @maxDepth='"+key_array[7]+"'";
306                }else{
307                        xpath_expr = xpath_expr + " and @maxDepth=''";
308                }
309                if (key_array.length > 8){
310                        xpath_expr = xpath_expr + "and @lang='"+key_array[8]+"']";
311                }else{
312                        xpath_expr = xpath_expr + " and @lang='']";
313                }
314               
[635]315                //Admin.notifyUser("formPath:xpath:"+xpath_expr);
316                //creating an XPathFactory:
317        XPathFactory factory = XPathFactory.newInstance();
318        //using this factory to create an XPath object:
319        XPath xpath = factory.newXPath();
320        //XPath object created compiles the XPath expression:
321        XPathExpression expr;
322                try {
323                        expr = xpath.compile(xpath_expr);
324                        //expression is evaluated with respect to a certain context node which is doc.
[655]325                Object result = expr.evaluate(cacheindex_doc, XPathConstants.NODESET);
[635]326                NodeList list = (NodeList) result;
327                if (list.getLength() > 0) {
328                        id = list.item(0).getAttributes().getNamedItem("id").getNodeValue();
329                        path = cachepath + PREFIX + key_array[0] + "_"+id + ".xml";
330                }  else if (list.getLength() > 1){
[745]331                        Admin.notifyUser("formPath ERROR:!!!:multiple paths:"+key_info);
[635]332                       
333                }
334               
335                } catch (XPathExpressionException e) {
336                        // TODO Auto-generated catch block
[1155]337                        Admin.notifyUser("ERROR Cache.formPath: "+xpath_expr);
[635]338                }
339               
[466]340            return path;
341        }
342       
343        public Integer getCounter () {
344                cachecounter = cachecounter +1 ;
345                return cachecounter;
346        }
347       
348        /**
349         * read counter-integer from file in cache
350         * or start that file
[1495]351         * @return The current maximum cache counter
[466]352         */
353        public Integer initCachecounter() {
[635]354               
355                Integer counter = start_cache;
[466]356                boolean init=false;
[655]357                String fname = cacheindex_path;
[635]358                File f = new File (fname);
359               
360                //Admin.notifyUser("initCacheCounter");
361                if (!f.exists()) {
362                                // create new  counter document
363                                DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
364                        DocumentBuilder docBuilder;
365                                try {
366                                        docBuilder = docFactory.newDocumentBuilder();
[655]367                                        cacheindex_doc = docBuilder.newDocument();
[635]368                                        // append root tag <index >
[655]369                                        Element root = (Element) cacheindex_doc.createElement("index");
[635]370                                        root.setAttribute("idcounter", "1");
[655]371                                        cacheindex_doc.appendChild(root);
[635]372                                        writeCachecounter(counter);
373                                       
374                                        //Admin.notifyUser("new document");
375                                } catch (ParserConfigurationException e) {
376                                        // TODO Auto-generated catch block
377                                        e.printStackTrace();
378                                }
379                               
380                        //} catch (IOException e2) {
381                        //      Admin.notifyUser("ERROR creating cache counter");
382                        //      e2.printStackTrace();
383                        //}
384            }
385                else {
[466]386                        try {
[635]387                               
388                        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
389                        DocumentBuilder docBuilder;
390                                try {
391                                        docBuilder = docFactory.newDocumentBuilder();               
392                                        try {
[655]393                                                        cacheindex_doc = docBuilder.parse(fname);
[635]394                                        } catch (SAXException e) {
395                                                        // TODO Auto-generated catch block
396                                                       
397                                                        e.printStackTrace();
398                                        }
399                                } catch (ParserConfigurationException e) {
400                                                // TODO Auto-generated catch block
401                                                e.printStackTrace();
402                                }
403                               
404                         //read counter
[655]405                         counter = new Integer(cacheindex_doc.getFirstChild().getAttributes().getNamedItem("idcounter").getNodeValue());
[635]406                         init = true;
407                    }  catch (IOException ex){
408                        //Admin.notifyUser("initCacheCounter:" + ex.toString());
409                        ex.printStackTrace();
410                    }
411                }
412               
413            return counter;
414            /*
[466]415              //use buffering, reading one line at a time
416              //FileReader always assumes default encoding is OK!
417                BufferedReader input =  new BufferedReader(new FileReader(f));
418                        try {
419                                String line = null; //not declared within while loop
420                        /*
421                        * readLine is a bit quirky :
422                        * it returns the content of a line MINUS the newline.
423                        * it returns null only for the END of the stream.
424                        * it returns an empty String if two newlines appear in a row.
[635]425                        *
[466]426                        try {
427                                        if (( line = input.readLine()) != null){
428                                                try {
429                                                        counter = new Integer(line);
430                                                } catch (NumberFormatException e) {
431                                                // if not a number, write a number
432                                                        init=true;     
433                                                } 
434                                        } else {
435                                                init=true;
436                                        }
437                                } catch (IOException e) {
438                                        init=true;
439                                }
440                       
441                        if (init) {                                                     
442                            writeCachecounter( start_cache);                                   
443                        }
444                       
445                } finally {
446                input.close();
[635]447             }   
448             */         
[466]449        }
450
451        public void updateCachecounter () {
[656]452                //Admin.notifyUser("CACHEcounter:" + cachecounter);
[466]453            writeCachecounter( cachecounter);
454        }
[655]455        public void writeCachecounter (Integer i) {             
[635]456               
457                // first update <index idcounter>
[655]458                cacheindex_doc.getFirstChild().getAttributes().getNamedItem("idcounter").setNodeValue(i.toString());
[635]459               
460                //Admin.notifyUser("writeCacheCounter:" + i.toString());
461                // write xml
462                Transformer transformer;
463                try {
464                        transformer = TransformerFactory.newInstance().newTransformer();
465                        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
466
467                        //initialize StreamResult with File object to save to file
468                        StreamResult result = new StreamResult(new StringWriter());
[655]469                        DOMSource source = new DOMSource(cacheindex_doc);
[635]470                        try {
471                                transformer.transform(source, result);
472                        } catch (TransformerException e1) {
473                                // TODO Auto-generated catch block
474                                e1.printStackTrace();
475                        }
476
477                        String xmlString = result.getWriter().toString();
478                        //Admin.notifyUser("writeCacheCounter:" + xmlString);
479                        //Admin.writeToFile("", result);
480
481
[655]482                        File f = new File (cacheindex_path);
[635]483                        FileWriter fw;
484                        try {
485                                fw = new FileWriter(f);
486                                try {
487                                        fw.write(xmlString);
488                                        fw.close();
489                                } catch (IOException e) {
490                                        // TODO Auto-generated catch block
491                                        e.printStackTrace();
492                                }       
493                        } catch (IOException e) {
494                                // TODO Auto-generated catch block
495                                e.printStackTrace();
496                        }
497                } catch (TransformerConfigurationException e2) {
498                        // TODO Auto-generated catch block
499                        e2.printStackTrace();
500                } catch (TransformerFactoryConfigurationError e2) {
501                        // TODO Auto-generated catch block
502                        e2.printStackTrace();
503                }
504               
505                       
506
507                /*
[466]508                File f = new File (Admin.getConfig().getProperty("cache.path") + "counter.txt");
509           
510                try {
511                        Writer output = new BufferedWriter(new FileWriter(f));         
512              //FileWriter always assumes default encoding is OK!
513                        try {
514                                output.write( i);
515                        } finally {
516                                output.close();
517                        }       
518                } catch (IOException e) {
519                        // TODO Auto-generated catch block
520                        e.printStackTrace();
521                }
[635]522                */
[466]523        }
[980]524       
525        public InputStream clear(HashMap<String,String> clear_params) throws ParserConfigurationException, TransformerConfigurationException, TransformerException, TransformerFactoryConfigurationError {
526                String xpath_expr = "";
527                Integer removed = 0;
528                InputStream is = null;
529               
530                if (clear_params.size() > 0 ) {
531                        if (clear_params.containsKey("repository")){
532                                xpath_expr = xpath_expr + " and @repository='" + clear_params.get("repository") + "'";
533                        }
534                        if (clear_params.containsKey("type")){
535                                xpath_expr = xpath_expr + " and @type='" + clear_params.get("type") + "'";
536                        }
537                        if (clear_params.containsKey("date")){
538                                xpath_expr = xpath_expr + " and @date='" + clear_params.get("date") + "'";
539                        }
540                        if (clear_params.containsKey("datefrom")){
541                                xpath_expr = xpath_expr + " and @date >= '" + clear_params.get("datefrom") + "'";
542                        }
543                        if (clear_params.containsKey("dateto")){
544                                xpath_expr = xpath_expr + " and @date <= '" + clear_params.get("dateto") + "'";
545                        }
546                        if (xpath_expr.length()>0){
547                                xpath_expr = xpath_expr.substring(5);
548                        }
549                        xpath_expr = "//index/f[" + xpath_expr + "]";
550                } else {
551                        xpath_expr = "//index/f";
552                }
553       
554                ////////// remove index_lines  + files
555                String id,type,path;
556                File f;
557                //creating an XPathFactory:
558                XPathFactory factory = XPathFactory.newInstance();
559                //using this factory to create an XPath object:
560                XPath xpath = factory.newXPath();
561                //XPath object created compiles the XPath expression:
562                XPathExpression expr;
563                try {
564                        expr = xpath.compile(xpath_expr);
565                        //expression is evaluated with respect to a certain context node which is doc.
566                Object result = expr.evaluate(cacheindex_doc, XPathConstants.NODESET);
567                NodeList list = (NodeList) result;
568               
569                //create deleted_doc
570                DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
571                DocumentBuilder docBuilder;
572                        docBuilder = docFactory.newDocumentBuilder();
573                        Document deleted_doc = docBuilder.newDocument();
574                        Element root = (Element) deleted_doc.createElement("index");
575                        root.setAttribute("count_deleted", String.valueOf(list.getLength()) );
576                        deleted_doc.appendChild(root);
577                       
578                        // delete items
579                        for(int i = 0;i< list.getLength();i++){
580                               
581                                id = list.item(i).getAttributes().getNamedItem("id").getNodeValue();
582                        type = list.item(i).getAttributes().getNamedItem("type").getNodeValue();
583                        path = cachepath + PREFIX + type + "_"+id + ".xml";
584                        f = new File (path);
585                       
586                        f.delete();
587                        cacheindex_doc.getFirstChild().removeChild(list.item(i));
588                       
589                        Element e = deleted_doc.createElement("f");
590                        e.setAttribute("filename", path);
591                        e.setAttribute("id", id);
592                        deleted_doc.getFirstChild().appendChild(e);
593                        } 
594                       
595                        //create resultstream
596                        ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 
597                        Source xmlSource = new DOMSource(deleted_doc); 
598                        Result outputTarget = new StreamResult(outputStream); 
599                        TransformerFactory.newInstance().newTransformer().transform(xmlSource, outputTarget); 
600                        is = new ByteArrayInputStream(outputStream.toByteArray()); 
601
602                        removed = list.getLength();
603               
604                } catch (XPathExpressionException e) {
605                        // TODO Auto-generated catch block
606                        e.printStackTrace();
607                }
608               
609                //////// set the index value
610                NodeList nl = cacheindex_doc.getElementsByTagName("f");
611                if (nl.getLength() < 1){
612                        cachecounter = 1;
613                }else {
614                        cachecounter = Integer.parseInt(nl.item(nl.getLength()-1).getAttributes().getNamedItem("id").getNodeValue());
615                }
616                this.updateCachecounter();
617                return is;
618        }
619
[466]620}
Note: See TracBrowser for help on using the repository browser.