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

Last change on this file since 1907 was 1907, checked in by gaba, 12 years ago

x-context replaced $repository, fcs/xsl's used

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