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
Line 
1package eu.clarin.cmdi.mdservice.action;
2
3import java.io.*;
4import java.net.MalformedURLException;
5import java.net.URL;
6/*import java.io.BufferedWriter;
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;
15*/
16import java.util.Date;
17import java.util.HashMap;
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.*;
26import javax.xml.transform.stream.*;import javax.xml.transform.dom.*;
27import javax.xml.xpath.*;
28
29import org.w3c.dom.*;
30import org.xml.sax.SAXException;
31import org.xml.sax.InputSource;
32import org.apache.commons.lang.StringEscapeUtils; 
33
34
35import eu.clarin.cmdi.mdservice.action.Admin;
36import eu.clarin.cmdi.mdservice.model.Query;
37
38/**
39 * This is a rudimentary caching mechanism.
40 * It serializes the inputstream to a file (identifier => filename) (putInCache())
41 * or returns the inputstream based on the identifier (getFromCache())
42 *
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>
45 *
46 * This is an internal object, direct user access to cache-data via interface is only possible via <code>AdminAction</code>
47 * @author master
48 *
49 */
50
51public class Cache {
52        public static String PREFIX = "xc_";
53       
54        public static String USE = "use";
55        public static String REFRESH = "refresh";
56        public static String SKIP= "skip";     
57       
58        private static Cache singleton;
59        private String cachepath; 
60        private String cacheindex_path;
61        private static Integer cachecounter;
62        private static final Integer start_cache = 1;
63       
64        private static Document cacheindex_doc;
65       
66       
67        public Cache () {               
68                cachepath = Admin.getConfig().getProperty("cache.path");
69                cacheindex_path = cachepath + Admin.getConfig().getProperty("cacheindex.file");
70                cachecounter = initCachecounter();
71               
72        }
73       
74        public static Cache getCache() {
75                if (singleton == null) {
76                        singleton = new Cache();
77                } 
78                return singleton;
79        }
80
81        public String getCacheIndexPath() {
82                return getCache().cacheindex_path;
83               
84        }
85
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        /**
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
117         * @return
118         */
119        public String putInCache(String key_info, InputStream instream) {
120
121                Admin.notifyUser("CACHE.putInCache:"+key_info);
122                Integer c = getCounter();
123                String xc;
124               
125               
126                //update xml_structure
127                Element e = cacheindex_doc.createElement("f");
128                //Attr attr = cacheindex_doc.createAttribute("id");
129                //attr.setValue(c.toString());
130                //e.setNamedItem(attr);
131                e.setAttribute("id", c.toString());
132                String[] key_array = key_info.split("//-");
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                }
151                if (key_array.length > 3){
152                        e.setAttribute("squery", key_array[3]);
153                }else{
154                        e.setAttribute("squery", "");
155                }
156                if (key_array.length > 4){
157                        e.setAttribute("startItem", key_array[4]);
158                }else{
159                        e.setAttribute("startItem", "");
160                }
161                if (key_array.length > 5){
162                        e.setAttribute("maximumItems", key_array[5]);
163                }else{
164                        e.setAttribute("maximumItems", "");
165                }
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                }
182                if (key_array.length > 9){
183                        e.setAttribute("duration", key_array[9]);
184                }else{
185                        e.setAttribute("duration", "");
186                }
187               
188                DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
189                e.setAttribute("date", dateFormat.format(new Date()).toString());
190                cacheindex_doc.getFirstChild().appendChild(e);
191               
192                // update XML-counter
193            //Admin.writeToFile(formPath(id + xc),instream);
194               
195                updateCachecounter();
196               
197                xc = PREFIX + key_array[0] + "_" + c.toString();
198                Admin.notifyUser("CACHE.putInCache.filename:" + xc + ".xml");
199                Admin.writeToFile(cachepath + xc + ".xml",instream);
200               
201            return xc;
202        }
203       
204       
205        public InputStream getFromCache(String key_info) {
206                   
207               
208                   File f = new File (formPath(key_info));
209                   //Admin.notifyUser("CACHE.getFromCache:"+key_info);
210                   
211                   
212                    if (f.exists()) { // read from file to InputStream;
213                        Admin.notifyUser("CACHE.getFromCache.fromfile:"+f.getName() + "[#" + key_info + "]");
214                        InputStream instream;
215                                try {
216                                        instream = new FileInputStream(f); 
217
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
226                        Admin.notifyUser("CACHE.getFromCache: NOT CACHED" + "[#" + key_info + "]");
227                        return null;
228                    }       
229        }
230 
231        private String transformQuery (String str) {
232                String transformed;
233                Query query;
234               
235                if (str == null) return "";
236                if (str.trim().length() == 0) return "";
237               
238                // provisional hack, setting simple string to ""
239                query = new Query("", str,"recordset","");
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 {
246                        transformed =  Query.getSimpleQueryString(str);
247                        transformed = StringEscapeUtils.escapeXml(transformed);
248                        //Admin.notifyUser("CACHE.transformQuery:"+transformed);
249                }
250                return transformed;
251        }
252       
253       
254         //TODO: sanitize-key
255        public String formPath (String key_info) {
256                String id="";
257                String path="";
258                String xpath_expr="";
259               
260                String[] key_array = key_info.split("//-");
261                String query_str;               
262               
263                if(key_array.length > 1){
264                //      Admin.notifyUser("formPATH- querystring:" + key_array[1]);
265                        if (key_array[0].equals("recordset")){
266                                query_str = this.transformQuery(key_array[1]); 
267                        //      Admin.notifyUser("formPATH- querystring-transformed:" + query_str);
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){
279                        xpath_expr = xpath_expr + "and @collection='"+key_array[2]+"'";
280                }else{
281                        xpath_expr = xpath_expr + " and @collection=''";
282                }
283                if (key_array.length > 3){
284                        xpath_expr = xpath_expr + "and @squery='"+key_array[3]+"'";
285                }else{
286                        xpath_expr = xpath_expr + " and @squery=''";
287                }
288                if (key_array.length > 4){
289                        xpath_expr = xpath_expr + "and @startItem='"+key_array[4]+"'";
290                }else{
291                        xpath_expr = xpath_expr + " and @startItem=''";
292                }
293                if (key_array.length > 5){
294                        xpath_expr = xpath_expr + "and @maximumItems='"+key_array[5]+"'";
295                }else{
296                        xpath_expr = xpath_expr + " and @maximumItems=''";
297                }
298               
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               
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.
325                Object result = expr.evaluate(cacheindex_doc, XPathConstants.NODESET);
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){
331                        Admin.notifyUser("formPath ERROR:!!!:multiple paths:"+key_info);
332                       
333                }
334               
335                } catch (XPathExpressionException e) {
336                        // TODO Auto-generated catch block
337                        Admin.notifyUser("ERROR Cache.formPath: "+xpath_expr);
338                }
339               
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
351         * @return The current maximum cache counter
352         */
353        public Integer initCachecounter() {
354               
355                Integer counter = start_cache;
356                boolean init=false;
357                String fname = cacheindex_path;
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();
367                                        cacheindex_doc = docBuilder.newDocument();
368                                        // append root tag <index >
369                                        Element root = (Element) cacheindex_doc.createElement("index");
370                                        root.setAttribute("idcounter", "1");
371                                        cacheindex_doc.appendChild(root);
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 {
386                        try {
387                               
388                        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
389                        DocumentBuilder docBuilder;
390                                try {
391                                        docBuilder = docFactory.newDocumentBuilder();               
392                                        try {
393                                                        cacheindex_doc = docBuilder.parse(fname);
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
405                         counter = new Integer(cacheindex_doc.getFirstChild().getAttributes().getNamedItem("idcounter").getNodeValue());
406                         init = true;
407                    }  catch (IOException ex){
408                        //Admin.notifyUser("initCacheCounter:" + ex.toString());
409                        ex.printStackTrace();
410                    }
411                }
412               
413            return counter;
414            /*
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.
425                        *
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();
447             }   
448             */         
449        }
450
451        public void updateCachecounter () {
452                //Admin.notifyUser("CACHEcounter:" + cachecounter);
453            writeCachecounter( cachecounter);
454        }
455        public void writeCachecounter (Integer i) {             
456               
457                // first update <index idcounter>
458                cacheindex_doc.getFirstChild().getAttributes().getNamedItem("idcounter").setNodeValue(i.toString());
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());
469                        DOMSource source = new DOMSource(cacheindex_doc);
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
482                        File f = new File (cacheindex_path);
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                /*
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                }
522                */
523        }
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
620}
Note: See TracBrowser for help on using the repository browser.