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

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

changes in recordset display, query_detail; adding documenting

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