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
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 * serializes the inputstream to a file (identifier => filename)
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>
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 {
56        public static String PREFIX = "xc_";
57       
58        public static String USE = "use";
59        public static String REFRESH = "refresh";
60        public static String SKIP= "skip";     
61       
62        private static Cache singleton;
63        private String cachepath; 
64        private String cacheindex_path;
65        private static Integer cachecounter;
66        private static final Integer start_cache = 1;
67       
68        private static Document cacheindex_doc;
69       
70       
71        public Cache () {               
72                cachepath = Admin.getConfig().getProperty("cache.path");
73                cacheindex_path = cachepath + Admin.getConfig().getProperty("cacheindex.file");
74                cachecounter = initCachecounter();
75               
76        }
77       
78        public static Cache getCache() {
79                if (singleton == null) {
80                        singleton = new Cache();
81                } 
82                return singleton;
83        }
84
85        public String getCacheIndexPath() {
86                return getCache().cacheindex_path;
87               
88        }
89
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        /**
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
121         * @return
122         */
123        public String putInCache(String key_info, InputStream instream) {
124
125                Admin.notifyUser("CACHE.putInCache:"+key_info);
126                Integer c = getCounter();
127                String xc;
128               
129               
130                //update xml_structure
131                Element e = cacheindex_doc.createElement("f");
132                //Attr attr = cacheindex_doc.createAttribute("id");
133                //attr.setValue(c.toString());
134                //e.setNamedItem(attr);
135                e.setAttribute("id", c.toString());
136                String[] key_array = key_info.split("//-");
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                }
155                if (key_array.length > 3){
156                        e.setAttribute("squery", key_array[3]);
157                }else{
158                        e.setAttribute("squery", "");
159                }
160                if (key_array.length > 4){
161                        e.setAttribute("startItem", key_array[4]);
162                }else{
163                        e.setAttribute("startItem", "");
164                }
165                if (key_array.length > 5){
166                        e.setAttribute("maximumItems", key_array[5]);
167                }else{
168                        e.setAttribute("maximumItems", "");
169                }
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                }
186                if (key_array.length > 9){
187                        e.setAttribute("duration", key_array[9]);
188                }else{
189                        e.setAttribute("duration", "");
190                }
191               
192                DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
193                e.setAttribute("date", dateFormat.format(new Date()).toString());
194                cacheindex_doc.getFirstChild().appendChild(e);
195               
196                // update XML-counter
197            //Admin.writeToFile(formPath(id + xc),instream);
198               
199                updateCachecounter();
200               
201                xc = PREFIX + key_array[0] + "_" + c.toString();
202                Admin.notifyUser("CACHE.putInCache.filename:" + xc + ".xml");
203                Admin.writeToFile(cachepath + xc + ".xml",instream);
204               
205            return xc;
206        }
207       
208       
209        public InputStream getFromCache(String key_info) {
210                   
211               
212                   File f = new File (formPath(key_info));
213                   //Admin.notifyUser("CACHE.getFromCache:"+key_info);
214                   
215                   
216                    if (f.exists()) { // read from file to InputStream;
217                        Admin.notifyUser("CACHE.getFromCache.fromfile:"+f.getName() + "[#" + key_info + "]");
218                        InputStream instream;
219                                try {
220                                        instream = new FileInputStream(f); 
221
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
230                        Admin.notifyUser("CACHE.getFromCache: NOT CACHED" + "[#" + key_info + "]");
231                        return null;
232                    }       
233        }
234 
235        private String transformQuery (String str) {
236                String transformed;
237                Query query;
238               
239                if (str == null) return "";
240                if (str.trim().length() == 0) return "";
241               
242                // provisional hack, setting simple string to ""
243                query = new Query("", str,"recordset","");
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 {
250                        transformed =  Query.getSimpleQueryString(str);
251                        transformed = StringEscapeUtils.escapeXml(transformed);
252                        //Admin.notifyUser("CACHE.transformQuery:"+transformed);
253                }
254                return transformed;
255        }
256       
257       
258         //TODO: sanitize-key
259        public String formPath (String key_info) {
260                String id="";
261                String path="";
262                String xpath_expr="";
263               
264                String[] key_array = key_info.split("//-");
265                String query_str;               
266               
267                if(key_array.length > 1){
268                //      Admin.notifyUser("formPATH- querystring:" + key_array[1]);
269                        if (key_array[0].equals("recordset")){
270                                query_str = this.transformQuery(key_array[1]); 
271                        //      Admin.notifyUser("formPATH- querystring-transformed:" + query_str);
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){
283                        xpath_expr = xpath_expr + "and @collection='"+key_array[2]+"'";
284                }else{
285                        xpath_expr = xpath_expr + " and @collection=''";
286                }
287                if (key_array.length > 3){
288                        xpath_expr = xpath_expr + "and @squery='"+key_array[3]+"'";
289                }else{
290                        xpath_expr = xpath_expr + " and @squery=''";
291                }
292                if (key_array.length > 4){
293                        xpath_expr = xpath_expr + "and @startItem='"+key_array[4]+"'";
294                }else{
295                        xpath_expr = xpath_expr + " and @startItem=''";
296                }
297                if (key_array.length > 5){
298                        xpath_expr = xpath_expr + "and @maximumItems='"+key_array[5]+"'";
299                }else{
300                        xpath_expr = xpath_expr + " and @maximumItems=''";
301                }
302               
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               
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.
329                Object result = expr.evaluate(cacheindex_doc, XPathConstants.NODESET);
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){
335                        Admin.notifyUser("formPath ERROR:!!!:multiple paths:"+key_info);
336                       
337                }
338               
339                } catch (XPathExpressionException e) {
340                        // TODO Auto-generated catch block
341                        Admin.notifyUser("ERROR Cache.formPath: "+xpath_expr);
342                }
343               
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() {
358               
359                Integer counter = start_cache;
360                boolean init=false;
361                String fname = cacheindex_path;
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();
371                                        cacheindex_doc = docBuilder.newDocument();
372                                        // append root tag <index >
373                                        Element root = (Element) cacheindex_doc.createElement("index");
374                                        root.setAttribute("idcounter", "1");
375                                        cacheindex_doc.appendChild(root);
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 {
390                        try {
391                               
392                        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
393                        DocumentBuilder docBuilder;
394                                try {
395                                        docBuilder = docFactory.newDocumentBuilder();               
396                                        try {
397                                                        cacheindex_doc = docBuilder.parse(fname);
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
409                         counter = new Integer(cacheindex_doc.getFirstChild().getAttributes().getNamedItem("idcounter").getNodeValue());
410                         init = true;
411                    }  catch (IOException ex){
412                        //Admin.notifyUser("initCacheCounter:" + ex.toString());
413                        ex.printStackTrace();
414                    }
415                }
416               
417            return counter;
418            /*
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.
429                        *
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();
451             }   
452             */         
453        }
454
455        public void updateCachecounter () {
456                //Admin.notifyUser("CACHEcounter:" + cachecounter);
457            writeCachecounter( cachecounter);
458        }
459        public void writeCachecounter (Integer i) {             
460               
461                // first update <index idcounter>
462                cacheindex_doc.getFirstChild().getAttributes().getNamedItem("idcounter").setNodeValue(i.toString());
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());
473                        DOMSource source = new DOMSource(cacheindex_doc);
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
486                        File f = new File (cacheindex_path);
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                /*
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                }
526                */
527        }
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
624}
Note: See TracBrowser for help on using the repository browser.