source: MDService2/branches/MDService_simple3/src/eu/clarin/cmdi/mdservice/action/GenericAction.java @ 1526

Last change on this file since 1526 was 1526, checked in by gaba, 13 years ago

repository default

File size: 14.9 KB
Line 
1package eu.clarin.cmdi.mdservice.action;
2
3import java.io.IOException;
4import java.io.InputStream;
5import java.io.StringWriter;
6import java.util.ArrayList;
7import java.util.Collections;
8import java.util.HashMap;
9import java.util.Iterator;
10import java.util.Map;
11import java.util.Set;
12import java.util.Map.Entry;
13import org.w3c.dom.Document;
14import org.w3c.dom.Node;
15import javax.xml.transform.TransformerFactory;
16import javax.xml.transform.dom.DOMSource;
17import javax.xml.transform.stream.StreamResult;
18import java.io.ByteArrayInputStream;
19
20import javax.servlet.http.HttpServletRequest;
21
22import org.apache.log4j.Logger;
23import org.apache.struts2.interceptor.ServletRequestAware;
24
25import com.opensymphony.xwork2.ActionSupport;
26
27import eu.clarin.cmdi.mdservice.internal.Cache;
28import eu.clarin.cmdi.mdservice.internal.Helpers;
29import eu.clarin.cmdi.mdservice.internal.MDTransformer;
30import eu.clarin.cmdi.mdservice.internal.NoStylesheetException;
31import eu.clarin.cmdi.mdservice.model.Diagnostic;
32import eu.clarin.cmdi.mdservice.model.Diagnostics;
33import eu.clarin.cmdi.mdservice.model.WorkspaceProfile;
34import eu.clarin.cmdi.mdservice.proxy.ProxyInterface;
35
36
37
38/**
39 * main Struts2 controller (ie implemenets the struts' execute()-method), all other Actions are derived from.   
40 * Defines the methods used for retrieving the data
41 * and provides basic implementation where possible.
42 * Also responsible for caching and transformation of the result.
43 * 
44 * @author vronk
45 */
46public class GenericAction extends ActionSupport
47implements ServletRequestAware
48{
49        public static Logger log = Logger.getLogger("GenericAction");
50        private static final long serialVersionUID = 1L;
51       
52       
53        private Diagnostics diagnostics;
54        /**
55         * Properties to be filled by Struts with according request-parameters
56         */
57        private String actionkey = "generic";
58        private String q;
59       
60        private String actionContentType;
61        private String userMsg;
62        private HttpServletRequest request; 
63        private long duration = 0;
64        private InputStream resultStream;
65        private InputStream sourceStream;
66       
67        private Map<String,String[]> params;
68       
69        private ProxyInterface target_proxy;
70               
71                               
72        public ProxyInterface getTargetProxy() {
73                return target_proxy;
74        }
75
76        public void setTargetProxy(ProxyInterface proxy) {
77                target_proxy = proxy;
78                target_proxy.setSourceAction(this);
79        }
80
81/**
82 * Empty implementation, subclasses have to decide themselves, which proxy to take.
83 */     
84        public void setTargetProxy() {
85        }
86
87         public Diagnostics getDiagnostics(){
88                 if (diagnostics == null){
89                         diagnostics  = new Diagnostics();
90                 }
91                 return this.diagnostics;
92         }
93         
94         public void setDiagnostics(Diagnostics diagnostics){
95                 this.diagnostics = diagnostics;
96         }
97         
98         public String getQ() {
99                        /*
100                        if  (q == null) {
101                                return "";
102                        } else {
103                                return q;
104                        }       
105                        */
106                        return q;
107         }
108
109         public void setQ(String q) {
110                        //if (q == null) q="";
111                        this.q = q;
112         }
113         
114         public String getActionkey() {
115                        return actionkey;
116                }
117
118        public void setActionkey(String actionKey) {
119                        actionkey = actionKey;
120                }
121               
122         public String getRecordPacking() {
123                 return getParam("recordPacking");
124         }
125         public String getFormat() {
126                        return getParam("x-cmd-format");
127         }
128         public String getCache() {
129                        return getParam("x-cmd-cache");
130         }
131         public String getRepository() {
132                        return getParam("x-cmd-repository");
133         }
134         public String getLang() {
135                        return getParam("x-cmd-lang");
136         }
137         public String getCollections() {
138                        return getParam("x-cmd-collections");
139         }
140         public String getColumns() {
141                        return getParam("x-cmd-columns");
142         }
143         public String getQuery() {
144                 return getParam("query");
145         }
146         public String getStartRecord() {
147                 return getParam("startRecord");
148         }
149         public String getMaximumRecords() {
150                 return getParam("maximumRecords");
151         }
152         public String getMaxdepth() {
153                 return getParam("x-cmd-maxdepth");
154         }
155         
156       
157        /**
158         * is used in struts.xml to dynamically set the mime-type of the result, depending on the format-parameter
159         * @return
160         */
161        public String getActionContentType() {
162                if (this.getFormat().toLowerCase().startsWith("html")) {
163                        this.actionContentType = "text/html";           
164                        //this.actionContentType = "application/xhtml+xml";
165                } else {
166                        this.actionContentType = "text/xml";
167                }
168               
169                return actionContentType;
170        }
171
172        public void setActionContentType(String actionContentType) {
173                this.actionContentType = actionContentType;
174        }
175
176
177        public String getFullFormat() {         
178                return actionkey + "2" + getFormat();
179        }
180
181
182        /**
183         * TODO: this should be replaced by the diagnostics-mechanism
184         * @return
185         */
186        public String getUserMsg() {
187                return userMsg;
188        }
189
190        public void setUserMsg(String userMsg) {
191                this.userMsg = this.userMsg + "\n" + userMsg;
192        }
193       
194        /**
195         * TODO: check what this does, where it is used?
196         * @return
197         */
198        @Override
199        public void setServletRequest(HttpServletRequest arg0) {
200                request = arg0;
201        }
202
203        public HttpServletRequest getServletRequest() {
204                return request; 
205        }
206
207        /**
208         * The stream holding the resulting data to be sent back to the user as response
209         * @return
210         */
211        public InputStream getResultStream() {
212                return resultStream;
213    }
214        public void setResultStream(InputStream _resultStream){
215                resultStream = _resultStream;
216        }
217        public void setSourceStream(InputStream _sourceStream){
218                sourceStream = _sourceStream;
219        }
220       
221         
222        /**
223         * Get the sourceStream from the target proxy   
224         * @return
225         * @throws IOException
226         * @throws NoStylesheetException
227         */
228                public InputStream getSourceStream() throws IOException, NoStylesheetException {               
229                        return getTargetProxy().getSourceStream(); 
230                }
231               
232        /**
233         * Reads in all the parameters of the request into an internal structure.
234         * the Map is not Map<String,String>, but rather Map<String,String[]>,
235         * ie the value is an array of Strings!
236         * http://download.oracle.com/docs/cd/E17802_01/webservices/webservices/docs/1.5/api/javax/servlet/ServletRequest.html#getParameterMap%28%29
237         *
238         * This shall allow more flexibility in using the parameters in the subclasses (and less getter/setter stuff)
239         * at the cost of circumventing the Struts-way.
240         */
241        public void addParam(String key, String value){
242                        String[] sarr = new String[1];
243                        sarr[0] = value;
244                        params.put(key, sarr); 
245        }
246       
247        /*
248         * sru params
249         *  /*
250     * version
251     * operation
252     * query
253     * scanClause
254     * startRecord
255     * maximumRecords
256     * recordPacking
257     * recordSchema
258     * recordXPath
259     * resultSetTTL
260     * sortKeys
261     * stylesheet
262     * x-cmd-repository
263     * x-cmd-collections
264     * x-cmd-columns
265     * x-cmd-lang
266     * x-cmd-format
267     * x-cmd-cache
268     * x-cmd-maxdepth
269         */
270        @SuppressWarnings("unchecked")
271        protected void loadParams() {           
272                params = new HashMap(getServletRequest().getParameterMap());
273
274                if (getQ() != null) {
275                        addParam("q",getQ());
276                }       
277
278                // set defaults
279                if ( params.get("version") == null){
280                        addParam("version","1.2");
281                }
282                if ( params.get("operation") == null){
283                        addParam("operation","searchRetrieve");
284                }
285                if ( params.get("query") == null){
286                        addParam("query",getParam("q"));
287                }
288                if ( params.get("startRecord") == null){
289                        addParam("startRecord","1");
290                }
291                if ( params.get("maximumRecords") == null){
292                        addParam("maximumRecords","50");
293                }
294                if ( params.get("x-cmd-maxdepth") == null){
295                        addParam("x-cmd-maxdepth","2");
296                }
297                if ( params.get("x-cmd-repository") == null){
298                        addParam("x-cmd-repository", WorkspaceProfile.getRepositoryByIndex(0));
299                }
300                if ( params.get("x-cmd-cache") == null){
301                        addParam("x-cmd-cache",Cache.SKIP);
302                }
303                if ( params.get("x-cmd-lang") == null){
304                        addParam("x-cmd-lang","en");
305                }
306                if ( params.get("x-cmd-format") == null){
307                        addParam("x-cmd-format","xml");
308                }
309        }
310       
311        public Map<String,String[]> getParams() {               
312                return params;
313        }
314
315       
316        /**
317         * This is for simplified access to the the values of the request-parameters
318         * They are stored in the parameters-map as a String-array,
319         * but in most(?) situations, we expect just a simple string.
320         * @param key
321         * @return
322         */
323        public String getParam(String key) {
324                String v = "";
325                if (!(params.get(key)==null)) v=(String)params.get(key)[0];
326                return v;
327        }
328
329        public String[] getParamArray(String key) {
330                String[] a = null;
331                if (!(params.get(key)==null)) a=(String[])params.get(key);
332                return a;
333        }
334
335        /**
336         * Constructs an unambiguous key for the request (encoding all the parameters).
337         * This is used as identifier for caching
338         * @return key unambiguously encoding the request
339         */
340       
341         public String getRequestKey() {
342                        String key="";
343                        if (getActionkey()!=null) {
344                                key += getActionkey() + "//-" ;
345                        }else {
346                                key +="//-" ;
347                        }
348                        if (getQuery()!=null) {
349                                key += getQuery() + "//-" ;
350                        } else {
351                                key +="//-" ;
352                        }
353                        if (getCollections()!=null) {
354                                key += getCollections() + "//-";
355                        } else {
356                                key +="//-" ;
357                        }
358                        if (this.getStartRecord()!=null) {
359                                key += getStartRecord() + "//-";
360                        }
361                                else{
362                                        key +="//-" ;
363                        }
364                        if (getMaximumRecords()!=null) {
365                                key += getMaximumRecords() + "//-";
366                        }
367                        else{
368                                key +="//-" ;
369                        }
370                       
371                        key += getRepository()  + "//-";
372                        key += getMaxdepth()  + "//-";
373                       
374                        if (getLang()!=null) {
375                                key += getLang() + "//-";
376                        }else{
377                                key +="//-" ;
378                        }                       
379
380                return key;
381        }
382       
383         
384        public String addDurationKey(){
385                String req_key = getRequestKey();
386       
387                Double duration_d;
388
389            duration_d = (double)duration; 
390            duration_d = duration_d/1000.0;
391                req_key += duration_d + "//-";
392                return req_key;
393        }
394       
395        /*
396        private static final Map<String, String> xsl_map;
397    static {
398        Map<String, String> aMap = new HashMap<String,String>();
399        aMap.put("fullformat","format");
400        //aMap.put("format","fullformat");
401        aMap.put("columns", "cols");
402        aMap.put("maximumItems","maximumItems");
403        aMap.put("startItem", "startItem");
404        aMap.put("lang","lang");
405        aMap.put("q", "q");
406        aMap.put("repository","repository_name");
407        //aMap.put("repository_type", "repository_type");
408        xsl_map = Collections.unmodifiableMap(aMap);
409    }
410   
411        public Map<String,String> createTransformerParams(){
412               
413                Map<String, String> map = new HashMap<String, String>();
414
415                Set<Entry<String, String[]>> set = getParams().entrySet();
416                Iterator<Entry<String, String[]>> i = set.iterator();
417
418            while(i.hasNext()){
419              Map.Entry<String,String[]> e = (Map.Entry<String,String[]>)i.next();
420              if (xsl_map.containsKey((String)e.getKey())) {
421                  map.put(xsl_map.get((String)e.getKey()), (String)e.getValue()[0]);
422              }
423             
424            }
425            return map;
426        }
427       
428        public Map<String,String> createTransformerParams(){
429               
430                HashMap<String,String> hm = new HashMap<String,String>();
431               
432            if (getFullFormat() != null){
433                        hm.put("format", getFullFormat());
434            }
435           
436                if (getColumns() != null){
437                        hm.put("cols", getColumns());
438                } else {
439                        hm.put("cols", "");
440                }
441                if (getStartItem() != null){
442                        hm.put("startItem", getStartItem());
443                }
444                if (getMaximumItems() != null){
445                        hm.put("maximumItems", getMaximumItems());     
446                }
447                if (getLang() != null){
448                        hm.put("lang", getLang());
449                }
450                if (getQ() != null){
451                        hm.put("q", getQ());
452                }
453                //if (getRepository() != null){
454                hm.put("repository_name", String.valueOf(getRepository()));
455                hm.put("repository_type", WorkspaceProfile.getRepositoryType(this.getRepository()));
456                //}
457     
458                return hm;             
459        }
460          */
461       
462        /**
463         * This is the work-horse function.
464         * It does two things:
465         * a) check if the source data is already in cache (based on cache-key that is constructed from the request parameters)
466         * b) if format-parameter provided, invokes the transformation.
467         * at the end the data to be returned as result is contained in the resultStream
468         * If format is xml, then the data from sourceStream is passed further as resultStream.
469         *   
470         * @throws Exception  This is handled by struts (is mapped to some result in struts.xml based on the Exception-Class)
471         */
472       
473        public void prepare() throws Exception {
474                       
475                loadParams();
476                setTargetProxy();
477                getTargetProxy().checkParams();
478               
479                String req_key = getRequestKey();
480                log.debug("request_key: " +  req_key); 
481                log.debug("params.size: " +  params.size());
482                log.debug(getActionkey() + ".targetURL: " + getTargetProxy().getTargetRequest() + " .format:" + getFullFormat());
483               
484                // Caching
485                String xcid;
486       
487                if (getCache().equals(Cache.SKIP)) {
488                       
489                        sourceStream = getSourceStream();
490                       
491                } else { 
492                        if (getCache().equals(Cache.USE)) {
493                                        sourceStream = Cache.getCache().getFromCache(req_key);
494                        }
495                        if (sourceStream == null) { // either not in cache or cache_flag=refresh
496                                //sourceStream = getTargetRequest().openStream();
497                                long startMillis = System.currentTimeMillis();
498                                sourceStream = getSourceStream();
499                                duration = System.currentTimeMillis() - startMillis;
500                                req_key = addDurationKey();
501                               
502                                long now = System.currentTimeMillis();
503                                xcid = Cache.getCache().putInCache(req_key,sourceStream);                       
504                                //Admin.notifyUser("putting in cache: " + req_key);                     
505                                sourceStream = Cache.getCache().getFromCache(req_key);
506                        } /* else {
507                                Admin.notifyUser("reading from cache: " + req_key);
508                        } */
509                }
510               
511                // add diagnostics
512                if (getDiagnostics().Exists()){
513                        Document doc ;
514                        Node r_element;
515                        // fatal error
516                        //TODO getDiagnostics().Exists("fatal");
517                        if (sourceStream == null){
518                                //TODO rootelemname ???
519                                doc = Helpers.createDocument("rootelemname");
520                                r_element = doc.getFirstChild();
521                        } else {
522                                doc = Helpers.getDocument(sourceStream);
523                                //TODO tagname by class
524                                r_element=  doc.getElementsByTagName("searchRetrieveResponse").item(0);
525                        }
526                       
527                        Document ddoc = getDiagnostics().buildXMLDocument();
528                        Node d_element=  ddoc.getElementsByTagName("diagnostics").item(0);
529                        doc.adoptNode(d_element);
530                        r_element.appendChild(d_element);
531                        DOMSource source = new DOMSource(doc);   
532                        StringWriter xmlAsWriter = new StringWriter();   
533                        StreamResult result = new StreamResult(xmlAsWriter);   
534                        TransformerFactory.newInstance().newTransformer().transform(source, result);
535                        this.setSourceStream(new ByteArrayInputStream(xmlAsWriter.toString().getBytes("UTF-8")));
536                }
537               
538               
539                if (getFormat().equals("xml")) {                       
540                        resultStream = sourceStream;   
541                }else {
542                        MDTransformer transformer = new MDTransformer();
543                        // set URL as srcFile (for MDTransformer to pass to xsl-scripts)
544                        // TODO: WHY??
545                        transformer.setSrcFile(getTargetProxy().getTargetRequest());
546                        //transformer.setParams(createTransformerParams());
547                        transformer.setParams(getParams());
548                        // here the transformation is invoked
549                        resultStream = transformer.transformXML(sourceStream);
550                }
551               
552                log.debug(getActionkey() + " success:" + (resultStream!=null));
553        }
554
555        /**
556         * default Action method that gets called by Struts. Everything interesting happens in prepare()
557         */
558        public String execute() throws Exception {
559//              HttpServletRequest request = ServletActionContext.getRequest();
560                //Admin.notifyUser("session-attrs:");
561        //Admin.notifyUser(getServletRequest().getRemoteUser() );
562        //Admin.notifyUser(String.valueOf(getSession()));
563       
564        long now = System.currentTimeMillis();
565
566                prepare();
567                long duration = (System.currentTimeMillis() - now);
568                //duration
569
570                if (resultStream == null) {
571                        return ERROR;   
572                } else {
573                        return SUCCESS;
574                }               
575        }
576
577
578}
Note: See TracBrowser for help on using the repository browser.