source: MDService2/branches/MDService_simple3/src/eu/clarin/cmdi/mdservice/internal/Cache.java @ 1654

Last change on this file since 1654 was 1654, checked in by gaba, 12 years ago

Utils.getConfig corrections

File size: 16.2 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.apache.log4j.Logger;
38import org.w3c.dom.Document;
39import org.w3c.dom.Element;
40import org.w3c.dom.NodeList;
41import org.xml.sax.SAXException;
42
43import eu.clarin.cmdi.mdservice.model.Query;
44
45/**
46 * This is a rudimentary caching mechanism.
47 * It serializes the inputstream to a file (identifier => filename) (putInCache())
48 * or returns the inputstream based on the identifier (getFromCache())
49 *
50 * <p>It maintains the cache_index (persisted as xml-file in the cache-folder)
51 * mapping the request parameters to the indexed files.</p>
52 *
53 * This is an internal object, direct user access to cache-data via interface is only possible via <code>...Action</code>
54 * @author master
55 *
56 */
57
58public class Cache {
59       
60        private static Logger log = Logger.getLogger("Cache");
61       
62        public static String PREFIX = "xc_";
63       
64        public static String USE = "use";
65        public static String REFRESH = "refresh";
66        public static String SKIP= "skip";     
67       
68        private static Cache singleton;
69        private String cachepath; 
70        private String cacheindex_path;
71        private static Integer cachecounter;
72        private static final Integer start_cache = 1;
73       
74        private static Document cacheindex_doc;
75       
76       
77        public Cache () {               
78                cachepath = Utils.getConfig("cache.path");
79                cacheindex_path = cachepath + Utils.getConfig("cacheindex.file");
80                cachecounter = initCachecounter();
81               
82        }
83       
84        public static Cache getCache() {
85                if (singleton == null) {
86                        singleton = new Cache();
87                } 
88                return singleton;
89        }
90
91        public String getCacheIndexPath() {
92                return getCache().cacheindex_path;
93               
94        }
95
96        protected void finalize() throws Throwable {       
97            try {               
98                updateCachecounter();
99            } catch(Exception e) {
100            }       
101            finally {           
102                super.finalize();
103                //more code can be written here as per need of application             
104            }
105        }
106       
107        /**
108         * Here the external key for the data gets cache-internal counter-id assigned
109         * which is also returned back.
110         *
111         * The external key gets parsed and put as individual attributes in the <f>-element:
112         *
113         * <code>
114         * <f collection="" date="2011-04-20 01:06:50" duration="0.227" id="3" lang="en"
115     *   maxDepth="1"
116     *   maximumItems=""
117     *   query=""
118     *   repository="localhost-mirror"
119     *   startItem=""
120     *   type="collections"/>
121      </code>
122         * 
123         *
124         * @param key_info a complex string carrying all relevant parameters
125         * @param instream data to be stored
126         * @return
127         */
128        public String putInCache(String key_info, InputStream instream) {
129
130                log.debug("CACHE.putInCache:"+key_info);
131                Integer c = getCounter();
132                String xc;
133               
134                //update xml_structure
135                Element e = cacheindex_doc.createElement("f");
136                e.setAttribute("id", c.toString());
137                String[] key_array = key_info.split("//-");
138               
139                e.setAttribute("type", key_array[0]);
140                if (key_array.length > 1){
141                        String query_str;
142                        if (key_array[0].equals("recordset")){
143                                query_str = transformQuery(key_array[1]);
144                        } else {
145                                query_str = key_array[1];
146                        }
147                        e.setAttribute("query", query_str);
148                }else{
149                        e.setAttribute("query", "");
150                }
151                if (key_array.length > 2){
152                        e.setAttribute("collection", key_array[2]);
153                }else{
154                        e.setAttribute("collection", "");
155                }
156                if (key_array.length > 3){
157                        e.setAttribute("startItem", key_array[3]);
158                }else{
159                        e.setAttribute("startItem", "");
160                }
161                if (key_array.length > 4){
162                        e.setAttribute("maximumItems", key_array[4]);
163                }else{
164                        e.setAttribute("maximumItems", "");
165                }
166               
167                if (key_array.length > 5){
168                        e.setAttribute("repository", key_array[5]);
169                }else{
170                        e.setAttribute("repository", "");
171                }
172                if (key_array.length > 6){
173                        e.setAttribute("maxDepth", key_array[6]);
174                }else{
175                        e.setAttribute("maxDepth", "");
176                }
177                if (key_array.length > 7){
178                        e.setAttribute("lang", key_array[7]);
179                }else{
180                        e.setAttribute("lang", "");
181                }
182                if (key_array.length > 8){
183                        e.setAttribute("duration", key_array[8]);
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                updateCachecounter();
194               
195                xc = PREFIX + key_array[0] + "_" + c.toString();
196                log.debug("CACHE.putInCache.filename:" + xc + ".xml");
197                Utils.write2File(cachepath + xc + ".xml",instream);
198               
199            return xc;
200        }
201       
202       
203        public InputStream getFromCache(String key_info) {
204                   
205               
206                   File f = new File (formPath(key_info));
207                   
208                    if (f.exists()) { // read from file to InputStream;
209                        log.debug("CACHE.getFromCache.fromfile:"+f.getName() + "[#" + key_info + "]");
210                        InputStream instream;
211                                try {
212                                        instream = new FileInputStream(f); 
213
214                                        return instream;
215                                } catch (FileNotFoundException e) {
216                                        Utils.errorMessage(e);
217                                        return null;
218                                }
219                       
220                    } else { //not cached, my dear
221                        log.debug("CACHE.getFromCache: NOT CACHED" + "[#" + key_info + "]");
222                        return null;
223                    }       
224        }
225 
226        private String transformQuery (String str) {
227                String transformed;
228                Query query;
229               
230                if (str == null) return "";
231                if (str.trim().length() == 0) return "";
232               
233                query = new Query(str,"recordset","");
234                if (query.isStatus(Query.PARSEERROR)) {
235                        log.debug("Cache.transformQuery.PARSEERROR:" + query.getMsg());
236                        // pass this bad news to the client
237                        transformed = "";
238                } else {
239                        transformed =  Query.getSimpleQueryString(str);
240                        transformed = StringEscapeUtils.escapeXml(transformed);
241                        //log.debug("CACHE.transformQuery:"+transformed);
242                }
243                return transformed;
244        }
245       
246       
247         //TODO: sanitize-key
248        public String formPath (String key_info) {
249                String id="";
250                String path="";
251                String xpath_expr="";
252               
253                String[] key_array = key_info.split("//-");
254                String query_str;               
255               
256                if(key_array.length > 1){
257                //      log.debug("formPATH- querystring:" + key_array[1]);
258                        if (key_array[0].equals("recordset")){
259                                query_str = this.transformQuery(key_array[1]); 
260                        //      log.debug("formPATH- querystring-transformed:" + query_str);
261                        }
262                        else {
263                                query_str = key_array[1];
264                        }
265                } else {
266                        query_str = "";
267                }
268                xpath_expr = "//index/f[@type='" + key_array[0] + "'";
269                xpath_expr = xpath_expr + " and @query='"+query_str+"'";
270               
271                if (key_array.length > 2){
272                        xpath_expr = xpath_expr + "and @collection='"+key_array[2]+"'";
273                }else{
274                        xpath_expr = xpath_expr + " and @collection=''";
275                }
276                if (key_array.length > 3){
277                        xpath_expr = xpath_expr + "and @startItem='"+key_array[3]+"'";
278                }else{
279                        xpath_expr = xpath_expr + " and @startItem=''";
280                }
281                if (key_array.length > 4){
282                        xpath_expr = xpath_expr + "and @maximumItems='"+key_array[4]+"'";
283                }else{
284                        xpath_expr = xpath_expr + " and @maximumItems=''";
285                }
286               
287                if (key_array.length > 5){
288                        xpath_expr = xpath_expr + "and @repository='"+key_array[5]+"'";
289                }else{
290                        xpath_expr = xpath_expr + " and @repository=''";
291                }
292                if (key_array.length > 6){
293                        xpath_expr = xpath_expr + "and @maxDepth='"+key_array[6]+"'";
294                }else{
295                        xpath_expr = xpath_expr + " and @maxDepth=''";
296                }
297                if (key_array.length > 7){
298                        xpath_expr = xpath_expr + "and @lang='"+key_array[7]+"']";
299                }else{
300                        xpath_expr = xpath_expr + " and @lang='']";
301                }
302               
303                //log.debug("formPath:xpath:"+xpath_expr);
304                //creating an XPathFactory:
305        XPathFactory factory = XPathFactory.newInstance();
306        //using this factory to create an XPath object:
307        XPath xpath = factory.newXPath();
308        //XPath object created compiles the XPath expression:
309        XPathExpression expr;
310                try {
311                        expr = xpath.compile(xpath_expr);
312                        //expression is evaluated with respect to a certain context node which is doc.
313                Object result = expr.evaluate(cacheindex_doc, XPathConstants.NODESET);
314                NodeList list = (NodeList) result;
315                if (list.getLength() > 0) {
316                        id = list.item(0).getAttributes().getNamedItem("id").getNodeValue();
317                        path = cachepath + PREFIX + key_array[0] + "_"+id + ".xml";
318                }  else if (list.getLength() > 1){
319                        log.debug("formPath ERROR:!!!:multiple paths:"+key_info);
320                       
321                }
322               
323                } catch (XPathExpressionException e) {
324                        log.debug("ERROR Cache.formPath: "+xpath_expr);
325                        log.error(Utils.errorMessage(e));
326                }
327               
328            return path;
329        }
330       
331        public Integer getCounter () {
332                cachecounter = cachecounter +1 ;
333                return cachecounter;
334        }
335       
336        /**
337         * Read counter-integer from file in cache
338         * or start that file
339         * @return The current maximum cache counter
340         */
341        public Integer initCachecounter() {
342               
343                Integer counter = start_cache;
344                String fname = cacheindex_path;
345                File f = new File (fname);
346               
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                                } catch (ParserConfigurationException e) {
361                                        log.error(Utils.errorMessage(e));
362                                }
363            }
364                else {
365                        try {
366                               
367                        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
368                        DocumentBuilder docBuilder;
369                                try {
370                                        docBuilder = docFactory.newDocumentBuilder();               
371                                        try {
372                                                        cacheindex_doc = docBuilder.parse(fname);
373                                        } catch (SAXException e) {
374                                                log.error(Utils.errorMessage(e));
375                                        }
376                                } catch (ParserConfigurationException e) {
377                                        log.error(Utils.errorMessage(e));
378                                }
379                               
380                         //read counter
381                         counter = new Integer(cacheindex_doc.getFirstChild().getAttributes().getNamedItem("idcounter").getNodeValue());
382                    }  catch (IOException e){
383                        log.error(Utils.errorMessage(e));
384                    }
385                }
386               
387            return counter;
388        }
389
390        public void updateCachecounter () {
391            writeCachecounter( cachecounter);
392        }
393        public void writeCachecounter (Integer i) {             
394               
395                // first update <index idcounter>
396                cacheindex_doc.getFirstChild().getAttributes().getNamedItem("idcounter").setNodeValue(i.toString());
397               
398                // write xml
399                Transformer transformer;
400                try {
401                        transformer = TransformerFactory.newInstance().newTransformer();
402                        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
403
404                        //initialize StreamResult with File object to save to file
405                        StreamResult result = new StreamResult(new StringWriter());
406                        DOMSource source = new DOMSource(cacheindex_doc);
407                        try {
408                                transformer.transform(source, result);
409                        } catch (TransformerException e) {
410                                log.error(Utils.errorMessage(e));
411                        }
412
413                        String xmlString = result.getWriter().toString();
414
415                        File f = new File (cacheindex_path);
416                        FileWriter fw;
417                        try {
418                                fw = new FileWriter(f);
419                                try {
420                                        fw.write(xmlString);
421                                        fw.close();
422                                } catch (IOException e) {
423                                        log.error(Utils.errorMessage(e));
424                                }       
425                        } catch (IOException e) {
426                                log.error(Utils.errorMessage(e));
427                        }
428                } catch (TransformerConfigurationException e) {
429                        log.error(Utils.errorMessage(e));
430                } catch (TransformerFactoryConfigurationError e) {
431                        log.error(Utils.errorMessage(e));
432                }
433               
434        }
435       
436        public InputStream clear(HashMap<String,String> clear_params) throws ParserConfigurationException, TransformerConfigurationException, TransformerException, TransformerFactoryConfigurationError {
437                String xpath_expr = "";
438                InputStream is = null;
439               
440                if (clear_params.size() > 0 ) {
441                        if (clear_params.containsKey("repository")){
442                                xpath_expr = xpath_expr + " and @repository='" + clear_params.get("repository") + "'";
443                        }
444                        if (clear_params.containsKey("type")){
445                                xpath_expr = xpath_expr + " and @type='" + clear_params.get("type") + "'";
446                        }
447                        if (clear_params.containsKey("date")){
448                                xpath_expr = xpath_expr + " and @date='" + clear_params.get("date") + "'";
449                        }
450                        if (clear_params.containsKey("datefrom")){
451                                xpath_expr = xpath_expr + " and @date >= '" + clear_params.get("datefrom") + "'";
452                        }
453                        if (clear_params.containsKey("dateto")){
454                                xpath_expr = xpath_expr + " and @date <= '" + clear_params.get("dateto") + "'";
455                        }
456                        if (xpath_expr.length()>0){
457                                xpath_expr = xpath_expr.substring(5);
458                        }
459                        xpath_expr = "//index/f[" + xpath_expr + "]";
460                } else {
461                        xpath_expr = "//index/f";
462                }
463       
464                ////////// remove index_lines  + files
465                String id,type,path;
466                File f;
467                //creating an XPathFactory:
468                XPathFactory factory = XPathFactory.newInstance();
469                //using this factory to create an XPath object:
470                XPath xpath = factory.newXPath();
471                //XPath object created compiles the XPath expression:
472                XPathExpression expr;
473                try {
474                        expr = xpath.compile(xpath_expr);
475                        //expression is evaluated with respect to a certain context node which is doc.
476                Object result = expr.evaluate(cacheindex_doc, XPathConstants.NODESET);
477                NodeList list = (NodeList) result;
478               
479                //create deleted_doc
480                DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
481                DocumentBuilder docBuilder;
482                        docBuilder = docFactory.newDocumentBuilder();
483                        Document deleted_doc = docBuilder.newDocument();
484                        Element root = (Element) deleted_doc.createElement("index");
485                        root.setAttribute("count_deleted", String.valueOf(list.getLength()) );
486                        deleted_doc.appendChild(root);
487                       
488                        // delete items
489                        for(int i = 0;i< list.getLength();i++){
490                               
491                                id = list.item(i).getAttributes().getNamedItem("id").getNodeValue();
492                        type = list.item(i).getAttributes().getNamedItem("type").getNodeValue();
493                        path = cachepath + PREFIX + type + "_"+id + ".xml";
494                        f = new File (path);
495                       
496                        f.delete();
497                        cacheindex_doc.getFirstChild().removeChild(list.item(i));
498                       
499                        Element e = deleted_doc.createElement("f");
500                        e.setAttribute("filename", path);
501                        e.setAttribute("id", id);
502                        deleted_doc.getFirstChild().appendChild(e);
503                        } 
504                       
505                        //create resultstream
506                        ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 
507                        Source xmlSource = new DOMSource(deleted_doc); 
508                        Result outputTarget = new StreamResult(outputStream); 
509                        TransformerFactory.newInstance().newTransformer().transform(xmlSource, outputTarget); 
510                        is = new ByteArrayInputStream(outputStream.toByteArray());
511               
512                } catch (XPathExpressionException e) {
513                        log.error(Utils.errorMessage(e));
514                }
515               
516                //////// set the index value
517                NodeList nl = cacheindex_doc.getElementsByTagName("f");
518                if (nl.getLength() < 1){
519                        cachecounter = 1;
520                }else {
521                        cachecounter = Integer.parseInt(nl.item(nl.getLength()-1).getAttributes().getNamedItem("id").getNodeValue());
522                }
523                this.updateCachecounter();
524                return is;
525        }
526
527}
Note: See TracBrowser for help on using the repository browser.