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

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

Utils.java in place of Helpers and Admin
Diagnostics changes in GenericAction?
code arrangement, comments

File size: 14.6 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         * Reads in all the parameters of the request into an internal structure.
283         * the Map is not Map&lt;String,String&gt;, but rather Map&lt;String,String[]&gt;,
284         * 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>
285         *
286         * This shall allow more flexibility in using the parameters in the subclasses (and less getter/setter stuff)
287         * at the cost of circumventing the Struts-way.
288         *
289         *
290         * The params are completed to fulfill sru params standard an also the params needed by XSL transformation
291         * are added.
292         *
293         *  SRU PARAMS:
294     * version
295     * operation
296     * query
297     * scanClause
298     * startRecord
299     * maximumRecords
300     * recordPacking
301     * recordSchema
302     * recordXPath
303     * resultSetTTL
304     * sortKeys
305     * stylesheet
306     * x-cmd-repository
307     * x-cmd-collections
308     * x-cmd-columns
309     * x-cmd-lang
310     * x-cmd-format
311     * x-cmd-cache
312     * x-cmd-maxdepth
313         */
314        @SuppressWarnings("unchecked")
315        protected void loadParams() {           
316                params = new HashMap(getServletRequest().getParameterMap());
317
318                if (getQ() != null) {
319                        addParam("q",getQ());
320                }       
321
322                // set defaults
323                if ( params.get("version") == null){
324                        addParam("version","1.2");
325                }
326                if ( params.get("operation") == null){
327                        addParam("operation","searchRetrieve");
328                }
329                if ( params.get("query") == null){
330                        addParam("query",getParam("q"));
331                }
332                if ( params.get("startRecord") == null){
333                        addParam("startRecord","1");
334                }
335                if ( params.get("maximumRecords") == null){
336                        addParam("maximumRecords","50");
337                }
338               
339                if ( params.get("x-cmd-maxdepth") == null){
340                        if (params.get("maxdepth") == null){
341                                addParam("maxdepth","2");
342                        } 
343                } else {
344                        addParam("maxdepth",params.get("x-cmd-maxdepth")[0]);
345                }
346               
347                if ( params.get("x-cmd-repository") == null){
348                        if (params.get("repository") == null){
349                                addParam("repository",WorkspaceProfile.getRepositoryByIndex(0));
350                        } 
351                } else {
352                        addParam("repository",params.get("x-cmd-repository")[0]);
353                }
354               
355                if ( params.get("x-cmd-cache") == null){
356                        if (params.get("cache") == null){
357                                addParam("cache",Cache.SKIP);
358                        } 
359                } else {
360                        addParam("cache",params.get("x-cmd-cache")[0]);
361                }
362               
363                if ( params.get("x-cmd-lang") == null){
364                        if (params.get("lang") == null){
365                                addParam("lang","en");
366                        } 
367                } else {
368                        addParam("lang",params.get("x-cmd-lang")[0]);
369                }
370               
371                if ( params.get("x-cmd-format") == null){
372                        if (params.get("format") == null){
373                                if (this.format == null) {
374                                        addParam("format","xml");
375                                } else if (this.format.equals("")){
376                                        addParam("format","xml");
377                                } else {
378                                        addParam("format",this.format);
379                                }
380                        } 
381                } else {
382                        addParam("format",params.get("x-cmd-format")[0]);
383                }
384
385                addParam("fullformat",getFullFormat());
386               
387        }
388       
389        /**
390         * Gets the local parameter map.
391         *
392         * @return
393         */
394        public Map<String,String[]> getParams() {               
395                return params;
396        }
397
398       
399        /**
400         * This is for simplified access to the the values of the request-parameters
401         * They are stored in the parameters-map as a String-array,
402         * but in most(?) situations, we expect just a simple string.
403         * @param key
404         * @return
405         */
406        public String getParam(String key) {
407                String v = "";
408                if (!(params.get(key)==null)) v=(String)params.get(key)[0];
409                return v;
410        }
411
412        public String[] getParamArray(String key) {
413                String[] a = null;
414                if (!(params.get(key)==null)) a=(String[])params.get(key);
415                return a;
416        }
417
418        /**
419         * Constructs an unambiguous key for the request (encoding all the parameters).
420         * This is used as identifier for caching .
421         *
422         * @return key unambiguously encoding the request
423         */
424       
425         public String getRequestKey() {
426                        String key="";
427                        if (getActionkey()!=null) {
428                                key += getActionkey() + "//-" ;
429                        }else {
430                                key +="//-" ;
431                        }
432                        if (getQuery()!=null) {
433                                key += getQuery() + "//-" ;
434                        } else {
435                                key +="//-" ;
436                        }
437                        if (getCollections()!=null) {
438                                key += getCollections() + "//-";
439                        } else {
440                                key +="//-" ;
441                        }
442                        if (this.getStartRecord()!=null) {
443                                key += getStartRecord() + "//-";
444                        }
445                                else{
446                                        key +="//-" ;
447                        }
448                        if (getMaximumRecords()!=null) {
449                                key += getMaximumRecords() + "//-";
450                        }
451                        else{
452                                key +="//-" ;
453                        }
454                       
455                        key += getRepository()  + "//-";
456                        key += getMaxdepth()  + "//-";
457                       
458                        if (getLang()!=null) {
459                                key += getLang() + "//-";
460                        }else{
461                                key +="//-" ;
462                        }                       
463
464                return key;
465        }
466       
467         
468        /**
469         * Adds the duration value of the action execution to the request key.
470         *
471         * @return
472         */
473        public String addDurationKey(){
474                String req_key = getRequestKey();
475       
476                Double duration_d;
477
478            duration_d = (double)duration; 
479            duration_d = duration_d/1000.0;
480                req_key += duration_d + "//-";
481                return req_key;
482        }
483       
484       
485        public String getTargetRequestParams(){
486                return "";
487        }
488       
489        public void setRequestProperties(URLConnection urlConnection){
490               
491        }
492
493        /**
494         * This is the work-horse function.
495         * It does more things:
496         * a) Loads the request parameters.
497         * b) Creates the concerned proxy object.
498         * c) Checks if the source data is already in cache (based on cache-key that is constructed from the request parameters).
499         * d) If diagnostics occurred  during function, the diagnostics data will be  added into source data.
500         * e) If format-parameter provided, invokes the transformation.
501         * 
502         *
503         * At the end the data to be returned as result is contained in the resultStream
504         * If format is xml, then the data from sourceStream is passed further as resultStream.
505         *
506         * If exception occurred within prepare function , it will be caught and written
507         * as diagnostics system error.
508         *   
509         */
510        public void prepare()  {
511                       
512                try{
513                        loadParams();
514                       
515                        setTargetProxy();
516                        if (getTargetProxy() == null) return;                   
517                        getTargetProxy().checkParams();
518                       
519                        // Do not continue if something is fatal.
520                        if (getDiagnostics().Exists()) return;
521                       
522                        String req_key = getRequestKey();
523                        log.debug("request_key: " +  req_key); 
524                        log.debug("params.size: " +  params.size());
525                        log.debug(getActionkey() + ".targetURL: " + getTargetProxy().getTargetRequest() + " .format:" + getFullFormat());
526                       
527                        //Caching
528               
529                        if (getCache().equals(Cache.SKIP)) {
530                               
531                                sourceStream = getSourceStream();
532                               
533                        } else { 
534                                if (getCache().equals(Cache.USE)) {
535                                                sourceStream = Cache.getCache().getFromCache(req_key);
536                                }
537                                if (sourceStream == null) { // either not in cache or cache_flag=refresh
538                                        long startMillis = System.currentTimeMillis();
539                                        sourceStream = getSourceStream();
540                                        duration = System.currentTimeMillis() - startMillis;
541                                        req_key = addDurationKey();
542                                        String xcid = Cache.getCache().putInCache(req_key,sourceStream);                       
543                                        log.debug("putting in cache: " + req_key + ", " + xcid);                       
544                                        sourceStream = Cache.getCache().getFromCache(req_key);
545                                } else {
546                                        log.debug("reading from cache: " + req_key);
547                                } 
548                        }
549                       
550                        // append diagnostics to sourcestream
551                        if (getDiagnostics().Exists()){
552                                if (sourceStream == null) return;
553                               
554                                Document doc = Utils.stream2Document(sourceStream);
555                                //TODO tagname by class
556                                doc = Utils.append2Document(doc, "searchRetrieveResponse",  getDiagnostics().buildXMLDocument());
557                                this.setSourceStream(Utils.document2Stream(doc));
558                        }
559                       
560                        log.debug("format: " + getFormat() );
561                        if (getFormat().equals("xml")) {                       
562                                resultStream = sourceStream;   
563                        }else {
564                                MDTransformer transformer = new MDTransformer();
565                                // set URL as srcFile (for MDTransformer to pass to xsl-scripts)
566                                // TODO: WHY??
567                                transformer.setSrcFile(getTargetProxy().getTargetRequest());
568                                transformer.setParams(getParams());
569                                // here the transformation is invoked
570                                resultStream = transformer.transformXML(sourceStream);
571                        }
572
573                }catch (Exception e){
574                        log.error(Utils.errorMessage(e));
575                        //TODO add exception to diagnostic ?
576                        getDiagnostics().Add(Diagnostic.SYSTEM_ERROR, Utils.errorMessage(e));
577                        return;
578                }
579               
580                log.debug(getActionkey() + " success:" + (resultStream!=null));
581        }
582
583        /**
584         *  Default Action method that gets called by Struts. Everything interesting happens in prepare()
585         *  In case an error occurred in prepare and the result stream is not returned, the diagnostics will be returned
586         *  as result.
587         * 
588         *  @throws Exception  This is handled by struts (is mapped to some result in struts.xml based on the Exception-Class).
589         */
590        public String execute() throws Exception {
591               
592        prepare();
593               
594                if (resultStream == null) {
595                        // diagnostics to resultstream
596                        if (getDiagnostics().Exists()){
597                                this.setResultStream( Utils.document2Stream(getDiagnostics().buildXMLDocument()));
598                                return SUCCESS;
599                        }
600                        return ERROR;   
601                } else {
602                        return SUCCESS;
603                }               
604        }
605
606
607}
Note: See TracBrowser for help on using the repository browser.