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

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

simple changes, exception for CQL parse error added

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