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

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

FCS first version

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