1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 package org.utgenome.gwt.utgb.server;
26
27 import java.io.BufferedInputStream;
28 import java.io.File;
29 import java.io.FileInputStream;
30 import java.io.IOException;
31 import java.io.OutputStream;
32 import java.text.DateFormat;
33 import java.text.SimpleDateFormat;
34 import java.util.Calendar;
35 import java.util.Date;
36 import java.util.Enumeration;
37 import java.util.HashMap;
38 import java.util.LinkedList;
39 import java.util.Locale;
40 import java.util.Properties;
41 import java.util.regex.Matcher;
42 import java.util.regex.Pattern;
43
44 import javax.servlet.Filter;
45 import javax.servlet.FilterChain;
46 import javax.servlet.FilterConfig;
47 import javax.servlet.ServletException;
48 import javax.servlet.ServletRequest;
49 import javax.servlet.ServletResponse;
50 import javax.servlet.http.HttpServletRequest;
51 import javax.servlet.http.HttpServletResponse;
52
53 import org.utgenome.UTGBException;
54 import org.xerial.core.XerialException;
55 import org.xerial.lens.Lens;
56 import org.xerial.util.bean.BeanUtil;
57 import org.xerial.util.log.Logger;
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147 public class RequestDispatcher implements Filter {
148
149
150
151 private static final long serialVersionUID = 1L;
152 private static Logger _logger = Logger.getLogger(RequestDispatcher.class);
153
154 private LinkedList<RequestMap> requestMapList = new LinkedList<RequestMap>();
155 private boolean isInGWTHostedMode = false;
156 private static HashMap<String, String> mimeTypes = new HashMap<String, String>();
157
158 private void initMimeTypes() {
159 if (!isInGWTHostedMode)
160 return;
161
162
163 mimeTypes.put("abs", "audio/x-mpeg");
164 mimeTypes.put("ai", "application/postscript");
165 mimeTypes.put("aif", "audio/x-aiff");
166 mimeTypes.put("aifc", "audio/x-aiff");
167 mimeTypes.put("aiff", "audio/x-aiff");
168 mimeTypes.put("aim", "application/x-aim");
169 mimeTypes.put("art", "image/x-jg");
170 mimeTypes.put("asf", "video/x-ms-asf");
171 mimeTypes.put("asx", "video/x-ms-asf");
172 mimeTypes.put("au", "audio/basic");
173 mimeTypes.put("avi", "video/x-msvideo");
174 mimeTypes.put("avx", "video/x-rad-screenplay");
175 mimeTypes.put("bcpio", "application/x-bcpio");
176 mimeTypes.put("bin", "application/octet-stream");
177 mimeTypes.put("bmp", "image/bmp");
178 mimeTypes.put("body", "text/html");
179 mimeTypes.put("cdf", "application/x-cdf");
180 mimeTypes.put("cer", "application/x-x509-ca-cert");
181 mimeTypes.put("class", "application/java");
182 mimeTypes.put("cpio", "application/x-cpio");
183 mimeTypes.put("csh", "application/x-csh");
184 mimeTypes.put("css", "text/css");
185 mimeTypes.put("dib", "image/bmp");
186 mimeTypes.put("doc", "application/msword");
187 mimeTypes.put("dtd", "text/plain");
188 mimeTypes.put("dv", "video/x-dv");
189 mimeTypes.put("dvi", "application/x-dvi");
190 mimeTypes.put("eps", "application/postscript");
191 mimeTypes.put("etx", "text/x-setext");
192 mimeTypes.put("exe", "application/octet-stream");
193 mimeTypes.put("gif", "image/gif");
194 mimeTypes.put("gtar", "application/x-gtar");
195 mimeTypes.put("gz", "application/x-gzip");
196 mimeTypes.put("hdf", "application/x-hdf");
197 mimeTypes.put("hqx", "application/mac-binhex40");
198 mimeTypes.put("htc", "text/x-component");
199 mimeTypes.put("htm", "text/html");
200 mimeTypes.put("html", "text/html");
201 mimeTypes.put("hqx", "application/mac-binhex40");
202 mimeTypes.put("ief", "image/ief");
203 mimeTypes.put("jad", "text/vnd.sun.j2me.app-descriptor");
204 mimeTypes.put("jar", "application/java-archive");
205 mimeTypes.put("java", "text/plain");
206 mimeTypes.put("jnlp", "application/x-java-jnlp-file");
207 mimeTypes.put("jpe", "image/jpeg");
208 mimeTypes.put("jpeg", "image/jpeg");
209 mimeTypes.put("jpg", "image/jpeg");
210 mimeTypes.put("js", "text/javascript");
211 mimeTypes.put("jsf", "text/plain");
212 mimeTypes.put("jspf", "text/plain");
213 mimeTypes.put("kar", "audio/x-midi");
214 mimeTypes.put("latex", "application/x-latex");
215 mimeTypes.put("m3u", "audio/x-mpegurl");
216 mimeTypes.put("mac", "image/x-macpaint");
217 mimeTypes.put("man", "application/x-troff-man");
218 mimeTypes.put("me", "application/x-troff-me");
219 mimeTypes.put("mid", "audio/x-midi");
220 mimeTypes.put("midi", "audio/x-midi");
221 mimeTypes.put("mif", "application/x-mif");
222 mimeTypes.put("mov", "video/quicktime");
223 mimeTypes.put("movie", "video/x-sgi-movie");
224 mimeTypes.put("mp1", "audio/x-mpeg");
225 mimeTypes.put("mp2", "audio/x-mpeg");
226 mimeTypes.put("mp3", "audio/x-mpeg");
227 mimeTypes.put("mpa", "audio/x-mpeg");
228 mimeTypes.put("mpe", "video/mpeg");
229 mimeTypes.put("mpeg", "video/mpeg");
230 mimeTypes.put("mpega", "audio/x-mpeg");
231 mimeTypes.put("mpg", "video/mpeg");
232 mimeTypes.put("mpv2", "video/mpeg2");
233 mimeTypes.put("ms", "application/x-wais-source");
234 mimeTypes.put("nc", "application/x-netcdf");
235 mimeTypes.put("oda", "application/oda");
236 mimeTypes.put("pbm", "image/x-portable-bitmap");
237 mimeTypes.put("pct", "image/pict");
238 mimeTypes.put("pdf", "application/pdf");
239 mimeTypes.put("pgm", "image/x-portable-graymap");
240 mimeTypes.put("pic", "image/pict");
241 mimeTypes.put("pict", "image/pict");
242 mimeTypes.put("pls", "audio/x-scpls");
243 mimeTypes.put("png", "image/png");
244 mimeTypes.put("pnm", "image/x-portable-anymap");
245 mimeTypes.put("pnt", "image/x-macpaint");
246 mimeTypes.put("ppm", "image/x-portable-pixmap");
247 mimeTypes.put("ppt", "application/powerpoint");
248 mimeTypes.put("ps", "application/postscript");
249 mimeTypes.put("psd", "image/x-photoshop");
250 mimeTypes.put("qt", "video/quicktime");
251 mimeTypes.put("qti", "image/x-quicktime");
252 mimeTypes.put("qtif", "image/x-quicktime");
253 mimeTypes.put("ras", "image/x-cmu-raster");
254 mimeTypes.put("rgb", "image/x-rgb");
255 mimeTypes.put("rm", "application/vnd.rn-realmedia");
256 mimeTypes.put("roff", "application/x-troff");
257 mimeTypes.put("rtf", "application/rtf");
258 mimeTypes.put("rtx", "text/richtext");
259 mimeTypes.put("sh", "application/x-sh");
260 mimeTypes.put("shar", "application/x-shar");
261 mimeTypes.put("smf", "audio/x-midi");
262 mimeTypes.put("sit", "application/x-stuffit");
263 mimeTypes.put("snd", "audio/basic");
264 mimeTypes.put("src", "application/x-wais-source");
265 mimeTypes.put("sv4cpio", "application/x-sv4cpio");
266 mimeTypes.put("sv4crc", "application/x-sv4crc");
267 mimeTypes.put("swf", "application/x-shockwave-flash");
268 mimeTypes.put("t", "application/x-troff");
269 mimeTypes.put("tar", "application/x-tar");
270 mimeTypes.put("tcl", "application/x-tcl");
271 mimeTypes.put("tex", "application/x-tex");
272 mimeTypes.put("texi", "application/x-texinfo");
273 mimeTypes.put("texinfo", "application/x-texinfo");
274 mimeTypes.put("tif", "image/tiff");
275 mimeTypes.put("tiff", "image/tiff");
276 mimeTypes.put("tr", "application/x-troff");
277 mimeTypes.put("tsv", "text/tab-separated-values");
278 mimeTypes.put("txt", "text/plain");
279 mimeTypes.put("ulw", "audio/basic");
280 mimeTypes.put("ustar", "application/x-ustar");
281 mimeTypes.put("xbm", "image/x-xbitmap");
282 mimeTypes.put("xht", "application/xhtml+xml");
283 mimeTypes.put("xhtml", "application/xhtml+xml");
284 mimeTypes.put("xml", "text/xml");
285 mimeTypes.put("xpm", "image/x-xpixmap");
286 mimeTypes.put("xsl", "text/xml");
287 mimeTypes.put("xwd", "image/x-xwindowdump");
288 mimeTypes.put("wav", "audio/x-wav");
289 mimeTypes.put("svg", "image/svg+xml");
290 mimeTypes.put("svgz", "image/svg+xml");
291 mimeTypes.put("vsd", "application/x-visio");
292 mimeTypes.put("wbmp", "image/vnd.wap.wbmp");
293 mimeTypes.put("wml", "text/vnd.wap.wml");
294 mimeTypes.put("wmlc", "application/vnd.wap.wmlc");
295 mimeTypes.put("wmls", "text/vnd.wap.wmlscript");
296 mimeTypes.put("wmlscriptc", "application/vnd.wap.wmlscriptc");
297 mimeTypes.put("wrl", "x-world/x-vrml");
298 mimeTypes.put("Z", "application/x-compress");
299 mimeTypes.put("z", "application/x-compress");
300 mimeTypes.put("zip", "application/zip");
301 }
302
303 private String removeFirstSlash(String requestURI) {
304 if (requestURI.startsWith("/"))
305 return requestURI.substring(1);
306 else
307 return requestURI;
308 }
309
310 public static String removeGWTModuleNamePart(String requestURI) {
311 return requestURI.replaceFirst("\\/\\w+(\\.\\w+)*\\/", "");
312 }
313
314 private static Pattern invalidCharInParamKey = Pattern.compile("[.-]");
315
316 public static void setRequestParametersToHandler(RequestHandler handler, HttpServletRequest req) {
317 assert (handler != null);
318
319
320 try {
321 Properties prop = new Properties();
322 for (Enumeration e = req.getParameterNames(); e.hasMoreElements();) {
323 String key = e.nextElement().toString();
324 Matcher m = invalidCharInParamKey.matcher(key);
325 String sanitizedKey = m.replaceAll("");
326 prop.put(sanitizedKey, req.getParameter(key));
327 }
328 if (_logger.isTraceEnabled())
329 _logger.trace(prop.toString());
330 Lens.loadMap(handler, prop);
331 }
332 catch (XerialException e) {
333 _logger.error(e);
334 }
335
336 }
337
338 public void destroy() {
339 _logger.info("destroy RequestDispatcher");
340 }
341
342 public static String getExtension(String path) {
343 int dotIndex = path.lastIndexOf(".");
344 if (dotIndex > 0) {
345 return path.substring(dotIndex + 1);
346 }
347 else
348 return "";
349 }
350
351 public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
352
353 HttpServletRequest req = (HttpServletRequest) request;
354 HttpServletResponse resp = (HttpServletResponse) response;
355
356
357 String requestURI = null;
358 if (isInGWTHostedMode) {
359
360
361 requestURI = req.getRequestURI();
362 requestURI = removeGWTModuleNamePart(requestURI);
363 }
364 else
365 requestURI = removeFirstSlash(req.getServletPath());
366 _logger.trace("request URI: " + requestURI);
367
368 dispatchRequest(new RequestURI(requestURI), req, resp, filterChain);
369 }
370
371 public void dispatchRequest(RequestURI requestURI, HttpServletRequest req, HttpServletResponse resp, FilterChain filterChain) throws IOException,
372 ServletException {
373
374 for (RequestMap map : requestMapList) {
375 RequestHandler handler = map.map(requestURI, req, resp);
376 if (handler != null) {
377 req.setAttribute("actionPrefix", requestURI.getPrefix());
378 req.setAttribute("actionSuffix", requestURI.getSuffix());
379 setRequestParametersToHandler(handler, req);
380
381
382 try {
383 handler.validate(req, resp);
384 }
385 catch (UTGBException e) {
386 _logger.error(e);
387 return;
388 }
389
390
391 handler.handle(req, resp);
392
393
394 return;
395 }
396 }
397
398
399
400
401 if (doGetFromSrcMainWebApp(requestURI.getURI(), req, resp))
402 return;
403
404
405
406 filterChain.doFilter(req, resp);
407 }
408
409 private static DateFormat sHttpDateFormat = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss", Locale.US);
410
411
412
413
414 public static String toInternetDateFormat(long time) {
415 Date date = dateToGMT(new Date(time));
416 String dateGmt;
417 synchronized (sHttpDateFormat) {
418 dateGmt = sHttpDateFormat.format(date) + " GMT";
419 }
420 return dateGmt;
421 }
422
423
424
425
426
427
428
429
430 private static Date dateToGMT(Date date) {
431 Calendar cal = Calendar.getInstance();
432 long tzMillis = cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET);
433 return new Date(date.getTime() - tzMillis);
434 }
435
436 private boolean doGetFromSrcMainWebApp(String requestURI, ServletRequest request, ServletResponse response) throws IOException {
437
438 if (!isInGWTHostedMode)
439 return false;
440
441
442 File resourceFile = new File("src/main/webapp/", requestURI);
443 if (!resourceFile.exists())
444 return false;
445
446
447 String mimeType = mimeTypes.get(getExtension(requestURI));
448 if (mimeType == null) {
449 mimeType = "application/octet-stream";
450 }
451
452 HttpServletResponse resp = (HttpServletResponse) response;
453 resp.setStatus(HttpServletResponse.SC_OK);
454
455
456 long cacheTime = 5;
457 long expires = 24 * 1000;
458 resp.setHeader("Cache-Control", "max-age=" + cacheTime);
459 String expiresString = toInternetDateFormat(expires);
460 resp.setHeader("Expires", expiresString);
461
462
463 long now = new Date().getTime();
464 resp.setHeader("Date", toInternetDateFormat(now));
465
466
467 resp.setContentType(mimeType);
468
469
470 long lastModified = resourceFile.lastModified();
471 String lastModifiedStr = toInternetDateFormat(resourceFile.lastModified());
472 resp.setHeader("Last-Modified", lastModifiedStr);
473
474
475 long contentLength = resourceFile.length();
476 if (contentLength >= 0) {
477 resp.setHeader("Content-Length", Long.toString(contentLength));
478 }
479
480
481 OutputStream out = resp.getOutputStream();
482 BufferedInputStream in = new BufferedInputStream(new FileInputStream(resourceFile));
483 byte[] buf = new byte[1024];
484 int bytesRead = 0;
485 while ((bytesRead = in.read(buf)) >= 0) {
486 out.write(buf, 0, bytesRead);
487 }
488 in.close();
489 return true;
490 }
491
492 public static boolean isGWTHostedMode() {
493 return Boolean.parseBoolean(System.getProperty("gwt-hosted-mode"));
494 }
495
496 public void init(FilterConfig config) throws ServletException {
497 _logger.info("initializing RequestDispatcher");
498
499 isInGWTHostedMode = isGWTHostedMode();
500
501 if (isInGWTHostedMode) {
502 _logger.info("GWT Hosted Mode");
503 initMimeTypes();
504 }
505
506 initRequestMap();
507 }
508
509 public void initRequestMap() {
510 addRequestMap(new DefaultRequestMap());
511 }
512
513 public void addRequestMap(RequestMap map) {
514 requestMapList.add(map);
515 }
516
517 }