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

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