1
2
3
4
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
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;
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
71 if (AxisDataServer.getMessageContextUrlStem() != null) {
72 setUrlStem(AxisDataServer.getMessageContextUrlStem());
73 return urlStem;
74 }
75
76 if (getRequestUrlStem() != null) {
77 setUrlStem(getRequestUrlStem());
78 return urlStem;
79 }
80
81
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
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
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
177 returnSpec.setTarget(null);
178 }
179 else {
180 String targetUri = request.getParameter("TargetURI");
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
195
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
217
218
219
220
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
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
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
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
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(">", ">").replaceAll("<", "<");
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 }