source: MDService2/branches/MDService_simple2/src/eu/clarin/cmdi/mdservice/internal/Cache.java @ 1511

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

brutal refactoring,
added new packages: proxies, internal,
very much restructured Action hierarchy.
Introduced division Action/Proxy?.
This is a first compiling version.
it's total mess.

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