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

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

javascript usage on format=htmljspage (MDService2/search)

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