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

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

small adaptations to query_input layout + other minors

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