View Javadoc

1   /*
2    * $Id: ServletHelper.java,v 1.5 2006/06/15 16:50:09 clq2 Exp $
3    *
4    * (C) Copyright Astrogrid...
5    */
6   
7   package org.astrogrid.dataservice.service;
8   
9   import java.io.IOException;
10  import java.io.PrintWriter;
11  import java.io.StringWriter;
12  import java.net.MalformedURLException;
13  import java.net.URISyntaxException;
14  import java.net.URL;
15  import java.security.Principal;
16  import javax.servlet.http.HttpServletRequest;
17  import org.apache.commons.logging.Log;
18  import org.apache.commons.logging.LogFactory;
19  import org.astrogrid.cfg.ConfigFactory;
20  import org.astrogrid.io.account.LoginAccount;
21  import org.astrogrid.io.mime.MimeNames;
22  import org.astrogrid.query.returns.ReturnTable;
23  import org.astrogrid.query.returns.ReturnImage;
24  import org.astrogrid.query.returns.ReturnSpec;
25  import org.astrogrid.query.Query;
26  import org.astrogrid.query.QueryException;
27  import org.astrogrid.slinger.sourcetargets.URISourceTargetMaker;
28  
29  /***
30   * A set of dataserver methods for helping serving data in HTML form, eg for servlets
31   * or JSPs
32   * <p>
33   * @author M Hill
34   */
35  
36  public class ServletHelper
37  {
38     
39     protected static Log log = LogFactory.getLog(ServletHelper.class);
40  
41     private static String urlStem = null;
42     
43     public static void setUrlStem(String aStem) {
44        if (!aStem.endsWith("/")) {
45           aStem = aStem+"/";
46        }
47        //check it's a valid URL and should be able to open a stream to it.
48        try {
49           new URL(aStem).openStream();
50        }
51        catch (IOException e) {
52           log.error("URL stem "+aStem+" is invalid or unreachable ("+e+")");
53           return; //don't set it
54        }
55        
56        log.info("Service Stem set to '"+aStem+"'");
57        if (urlStem == null) {
58           urlStem = aStem;
59        }
60        else if (!urlStem.equals(aStem)) {
61           log.error("Trying to set service URL stem to "+aStem+" when already "+urlStem+"; ignoring new stem");
62        }
63     }
64  
65     /*** Provides static access to the url stem (eg http://grendel12.roe.ac.uk/pal-6df)" target="alexandria_uri">http://grendel12.roe.ac.uk/pal-6df)  */
66     public static String getUrlStem() {
67        if (urlStem != null) {
68           return urlStem;
69        }
70        //see if we can get it from axis stuff
71        if (AxisDataServer.getMessageContextUrlStem() != null) {
72           setUrlStem(AxisDataServer.getMessageContextUrlStem());
73           return urlStem;
74        }
75        //see if we can get it from servlet stuff
76        if (getRequestUrlStem() != null) {
77           setUrlStem(getRequestUrlStem());
78           return urlStem;
79        }
80        
81        //if not, get it we can get it from config
82        String configStem = ConfigFactory.getCommonConfig().getString("datacenter.url");
83        if (configStem != null) {
84           if (!configStem.endsWith("/")) {
85              configStem = configStem+"/";
86           }
87        }
88        return configStem;
89     }
90  
91     public static String getRequestUrlStem() {
92        return null;
93     }
94     
95     public static String getUrlStem(HttpServletRequest request) {
96        return request.getScheme()+"://"+request.getServerName() +":" + request.getServerPort()+request.getContextPath();
97     }
98  
99     /***
100     * Gets the user details from the request */
101    public static Principal getUser(HttpServletRequest request)  {
102       if (request.getParameter("UserName") != null) {
103          //for information only
104          return new LoginAccount(request.getParameter("UserName"), "Unknown");
105       }
106       else {
107          return LoginAccount.ANONYMOUS;
108       }
109    }
110 
111    /***
112     * Convenience routine for JSPs; decides where target should be from
113     * the parameters in the given request.  The parameter names should match
114     * those assigned in resultsForm.xml 
115     * @TOFIX: LIMIT is currently being ignored, is this problematic? 
116     * Can have a getLimit() method and set limit in actual query instead? */
117    public static ReturnSpec makeReturnSpec(HttpServletRequest request)  {
118       
119       ReturnSpec returnSpec = null;
120       
121       String format = request.getParameter("Format");
122       if ( (format != null) && (format.trim().length()>0)) {
123          if (ReturnImage.isImageFormat(new String[] { format })) {
124             returnSpec = new ReturnImage(null);
125          }
126       }
127       if (returnSpec == null) {
128          returnSpec = new ReturnTable(null);
129       }
130 
131       // This is a dummy placeholder
132       fillReturnSpec(returnSpec, request);
133       
134       return returnSpec;
135    }
136 
137    /***
138     * Convenience routine for JSPs; extracts the limit value from a request
139     * if present. */
140    public static long getLimit(HttpServletRequest request) {
141       String limit = request.getParameter("Limit");
142       long limitVal;
143       if ( (limit != null) && (limit.trim().length()>0)) {
144          try {
145             limitVal = Long.parseLong(limit, 10);
146          }
147          catch(NumberFormatException e) {
148            throw new IllegalArgumentException("Bad value '" + limit + "' for limit, expected valid integer");
149          }
150          return limitVal;
151       }
152       return Query.LIMIT_NOLIMIT;
153    }
154 
155    /***
156     * Convenience routine for JSPs; returns true if this is an 'ask count' request
157     *  from the resultsForm.xml */
158    public static boolean isCountReq(HttpServletRequest request)  {
159       String format = request.getParameter("Format");
160       if ( (format != null) && (format.trim().length()>0) && (format.trim().toLowerCase().equals("count"))) {
161          return true;
162       }
163       else {
164          return false;
165       }
166    }
167 
168       /***
169     * Convenience routine for JSPs; decides where target should be from
170     * the parameters in the given request.  The parameter names should match
171     * those assigned in resultsForm.xml */
172    public static void fillReturnSpec(ReturnSpec returnSpec, HttpServletRequest request)  {
173 
174       String targetResponse = request.getParameter("TargetResponse");
175       if ((targetResponse != null) && targetResponse.trim().toLowerCase().equals("true")) {
176          //target is the http response
177          returnSpec.setTarget(null);
178       }
179       else {
180          String targetUri = request.getParameter("TargetURI");   //direction - eg URI
181          if ((targetUri != null) && (targetUri.trim().length()>0)) {
182 
183             try {
184                returnSpec.setTarget(URISourceTargetMaker.makeSourceTarget(targetUri));
185             }
186             catch (URISyntaxException e) {
187                throw new IllegalArgumentException("Invalid target: "+targetUri+" ("+e+")");
188             }
189             catch (MalformedURLException e) {
190                throw new IllegalArgumentException("Invalid target: "+targetUri+" ("+e+")");
191             }
192          }
193          else {
194             //throw new IllegalArgumentException("Bad Target; TargetResponse not 'true' and TargetURI not set");
195             //assume targetresponse true (for things like cone searches)
196             returnSpec.setTarget(null);
197          }
198       }
199       
200       String format = request.getParameter("Format");
201       if ( (format != null) && (format.trim().length()>0)) {
202          returnSpec.setFormat(format);
203       }
204       
205       String compression = request.getParameter("Compression");
206       if ( (compression != null) && (compression.trim().length()>0)) {
207          try {
208             returnSpec.setCompression(compression);
209          }
210          catch (QueryException e) {
211             throw new IllegalArgumentException("Invalid compression: "+
212                 compression+" ("+e+")");
213          }
214       }
215       /*
216       // Limit is no longer part of ReturnSpec, it's managed 
217       // directly by the Query class.
218       String limit = request.getParameter("Limit");
219       if ( (limit != null) && (limit.trim().length()>0)) {
220         throw new IllegalArgumentException("Limit is ignored!");
221       }
222       */
223    }
224    
225    /*** Creates a Circle function condition from parameters in the given request.
226     * Accepts POS=(ra,dec) and RA=ra&DEC=dec, and SIZE and SR for search radius.
227     * Accepts all-lower case as well as all-upper case
228     */
229    /*
230    public static CircleCondition makeCircleCondition(HttpServletRequest request) {
231       
232       String radiusparam = request.getParameter("SIZE");
233       if (radiusparam == null) { radiusparam = request.getParameter("size"); }
234       if (radiusparam == null) { radiusparam = request.getParameter("SR"); }
235       if (radiusparam == null) { radiusparam = request.getParameter("sr"); }
236       if (radiusparam == null) { radiusparam = request.getParameter("RADIUS"); }
237       if (radiusparam == null) { radiusparam = request.getParameter("radius"); }
238       if (radiusparam == null) {
239          throw new IllegalArgumentException("No Radius given as SIZE or SR or RADIUS");
240       }
241       double radius = Double.parseDouble(radiusparam);
242       
243       double ra;
244       double dec;
245 
246       String pos = request.getParameter("POS");
247       if (pos == null)     {  request.getParameter("pos"); }
248       if (pos != null) {
249          int comma = pos.indexOf(",");
250          ra = Double.parseDouble(pos.substring(0,comma));
251          dec = Double.parseDouble(pos.substring(comma+1));
252          return new CircleCondition(ra, dec, radius);
253       }
254 
255       String raparam = request.getParameter("RA");
256       if (raparam == null) {  raparam = request.getParameter("ra"); }
257       if (raparam == null) {  raparam = request.getParameter("Ra"); }
258       if (raparam == null) {
259          throw new IllegalArgumentException("No RA given");
260       }
261       
262       String decparam = request.getParameter("DEC");
263       if (decparam == null) { decparam = request.getParameter("dec"); }
264       if (decparam == null) { decparam = request.getParameter("Dec"); }
265       if (raparam == null) {
266          throw new IllegalArgumentException("No DEC given");
267       }
268       
269       ra = Double.parseDouble(raparam);
270       dec = Double.parseDouble(decparam);
271       
272       return new CircleCondition(ra, dec, radius);
273    }
274    */
275    
276    /*** Convenience routine for extracting the radius of a conesearch */
277    public static double getRadius(HttpServletRequest request)
278    {
279       String radiusparam = request.getParameter("SIZE");
280       if (radiusparam == null) { radiusparam = request.getParameter("size"); }
281       if (radiusparam == null) { radiusparam = request.getParameter("SR"); }
282       if (radiusparam == null) { radiusparam = request.getParameter("sr"); }
283       if (radiusparam == null) { radiusparam = request.getParameter("RADIUS"); }
284       if (radiusparam == null) { radiusparam = request.getParameter("radius"); }
285       if (radiusparam == null) {
286          throw new IllegalArgumentException("No Radius given as SIZE or SR or RADIUS");
287       }
288       try {
289          return Double.parseDouble(radiusparam);
290       }   
291       catch (NumberFormatException e) {
292          throw new IllegalArgumentException(
293              "Bad search radius '" + radiusparam + 
294              "' given, expected real number");
295       }
296    }
297 
298    /*** Convenience routine for extracting the RA of a conesearch */
299    public static double getRa(HttpServletRequest request)
300    {
301       String pos = request.getParameter("POS");
302       if (pos == null) {  
303         request.getParameter("pos"); 
304       }
305       if (pos != null) {
306          int comma = pos.indexOf(",");
307          try {
308             return Double.parseDouble(pos.substring(0,comma));
309          }
310          catch (Exception e) {
311             throw new IllegalArgumentException(
312               "Couldn't parse RA value from POS field");
313          }
314       }
315       String raparam = request.getParameter("RA");
316       if (raparam == null) {  
317          raparam = request.getParameter("ra"); 
318       }
319       if (raparam == null) {
320          raparam = request.getParameter("Ra"); 
321       }
322       if (raparam == null) {
323          throw new IllegalArgumentException("No RA given");
324       }
325       try {
326          return Double.parseDouble(raparam);
327       } 
328       catch (NumberFormatException e) {
329          throw new IllegalArgumentException(
330              "Bad RA '" + raparam + "' given, expected real number");
331       }
332 
333    }
334    /*** Convenience routine for extracting the RA of a conesearch */
335    public static double getDec(HttpServletRequest request)
336    {
337       String pos = request.getParameter("POS");
338       if (pos == null)     {  request.getParameter("pos"); }
339       if (pos != null) {
340          int comma = pos.indexOf(",");
341          try {
342             return Double.parseDouble(pos.substring(comma+1));
343          }
344          catch (Exception e) {
345             throw new IllegalArgumentException(
346                "Couldn't parse Dec value from POS field");
347          }
348       }
349       String decparam = request.getParameter("DEC");
350       if (decparam == null) { decparam = request.getParameter("dec"); }
351       if (decparam == null) { decparam = request.getParameter("Dec"); }
352       if (decparam == null) {
353          throw new IllegalArgumentException("No DEC given");
354       }
355       try {
356          return Double.parseDouble(decparam);
357       }
358       catch (NumberFormatException e) {
359          throw new IllegalArgumentException(
360              "Bad DEC '" + decparam + "' given, expected real number");
361       }
362    }
363    
364    /*** Convenience routine for returning the correct 'HTML' snippet that
365     * refreshes the page given by the URL - which should point to the same page
366     * that contains the snippet */
367    public static String makeRefreshSnippet(int secs, String url) {
368          return("(Refreshes every "+secs+" seconds)"+
369                 "<META HTTP-EQUIV='Refresh' CONTENT='"+secs+";URL="+url+"'>");
370    }
371 
372    /*** Returns the stylesheet to be used for the center's html pages in the form
373     * of a 'link' element.  Returns an empty string if none configured */
374    public static String getCssLink() {
375       String cssName = ConfigFactory.getCommonConfig().getString("datacenter.stylesheet",  "default.css");
376       if (cssName.length() == 0) {
377          return "";
378       }
379       else {
380          return "<LINK href='"+cssName+"' rel='stylesheet' type='text/css'>";
381       }
382    }
383 
384    /*** Convenience routine that returns the complete <HEAD> element for the
385     * standard datacenter page */
386    public static String getHeadElement(String title) {
387       return "<HEAD>\n"+
388              "  <TITLE>"+title+" ("+DataServer.getDatacenterName()+")</TITLE>\n"+
389              "  "+getCssLink()+"\n"+
390              "</HEAD>\n";
391    }
392 
393    
394    /*** Retruns the available formats as a list of <option>format</option>
395     * in a single string */
396    public static String getFormatOptions() throws IOException {
397       String f[] = DataServer.getFormats();
398       
399       String ops = "";
400       for (int i = 0; i < f.length; i++) {
401          ops = ops + "<option>"+MimeNames.humanFriendly(f[i])+"</option>";
402       }
403       return ops;
404    }
405    
406    /***
407     * Returns an error as string suitable for display in a browser as an html
408     * page
409     */
410    public static String exceptionAsHtmlPage(String title, Throwable th, String details) {
411      // Keep error title in sync with coneSearch test in InstallationSelfCheck
412       return
413          "<html>\n"+
414          "<head><title>ASTROGRID DSA ERROR: "+makeSafeForHtml(title)+"</title></head>\n"+
415          "<body>\n"+
416          exceptionAsHtml(title, th, details)+
417          "</body>\n"+
418          "</html>\n";
419    }
420 
421    /*** Returns exception suitable for a paragraph in an hmtl page */
422    public static String exceptionAsHtml(String title, Throwable th, String details) {
423 
424      // Keep error title in sync with coneSearch test in InstallationSelfCheck
425       String s =
426          "<h1>ASTROGRID DSA ERROR REPORT</h1>\n";
427       
428       if (th != null) {
429          s=s+
430             "<h2>"+makeSafeForHtml(th.getMessage())+"</h2>\n";
431       }
432       s =s + "<p>"+title+"</p>\n";
433 
434       if (th != null) {
435          StringWriter sw = new StringWriter();
436          th.printStackTrace(new PrintWriter(sw));
437          String stack = sw.toString();
438 
439          s = s +
440          "<p><b>"+makeSafeForHtml(th.toString())+"</b></p>\n"+
441          "<p>\n"+
442          "<pre>"+makeSafeForHtml(stack)+"</pre>\n"+
443          "</p>\n"+
444          "<p>\n";
445       }
446       
447       s=s+
448          "<pre>"+makeSafeForHtml(details)+"</pre>\n"+
449          "</p>\n";
450 
451       return s;
452    }
453 
454    /***
455     * Deals with special characters */
456    public static String makeSafeForHtml(String s) {
457       if (s==null) {
458          return "";
459       }
460       s = s.replaceAll(">", "&gt;").replaceAll("<", "&lt;");
461       return s.replaceAll("\n","<br/>");
462    }
463    
464    /*** Convenience routine for exceptionAsHtml(String, Exception, String)   */
465    public static String exceptionAsHtmlPage(String title, Throwable th) {
466       return exceptionAsHtmlPage(title, th, "");
467    }
468    
469    /*** For quick tests/debugging */
470    public static void main(String[] args) throws IOException
471    {
472       String t = getFormatOptions();
473       System.out.println(t);
474    }
475 }