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

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

ComRegistryProxyAction?, DCRAction derivation changed

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