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

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

various small changes, clean up code

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