1 16 package com.google.gwt.dev.shell; 17 18 import com.google.gwt.core.ext.TreeLogger; 19 import com.google.gwt.core.ext.UnableToCompleteException; 20 import com.google.gwt.dev.cfg.ModuleDef; 21 import com.google.gwt.dev.cfg.ModuleDefLoader; 22 import com.google.gwt.dev.util.HttpHeaders; 23 import com.google.gwt.dev.util.SelectionScriptGenerator; 24 import com.google.gwt.dev.util.log.ServletContextTreeLogger; 25 26 import java.io.File ; 27 import java.io.IOException ; 28 import java.io.InputStream ; 29 import java.io.OutputStream ; 30 import java.io.PrintWriter ; 31 import java.net.MalformedURLException ; 32 import java.net.URL ; 33 import java.net.URLConnection ; 34 import java.util.Date ; 35 import java.util.HashMap ; 36 import java.util.Iterator ; 37 import java.util.Map ; 38 39 import javax.servlet.ServletContext ; 40 import javax.servlet.ServletException ; 41 import javax.servlet.http.HttpServlet ; 42 import javax.servlet.http.HttpServletRequest ; 43 import javax.servlet.http.HttpServletResponse ; 44 45 49 public class GWTShellServlet extends HttpServlet { 50 51 private static class RequestParts { 52 public final String moduleName; 53 54 public final String partialPath; 55 56 public RequestParts(HttpServletRequest request) 57 throws UnableToCompleteException { 58 String pathInfo = request.getPathInfo(); 59 if (pathInfo != null) { 60 int slash = pathInfo.indexOf('/', 1); 61 if (slash != -1) { 62 moduleName = pathInfo.substring(1, slash); 63 partialPath = pathInfo.substring(slash + 1); 64 return; 65 } else { 66 moduleName = pathInfo.substring(1); 67 partialPath = null; 68 return; 69 } 70 } 71 throw new UnableToCompleteException(); 72 } 73 } 74 75 79 private static final int DEFAULT_CACHE_SECONDS = 5; 80 81 private static final String XHTML_MIME_TYPE = "application/xhtml+xml"; 82 83 private final Map loadedModulesByName = new HashMap (); 84 85 private final Map loadedServletsByClassName = new HashMap (); 86 87 private final Map mimeTypes = new HashMap (); 88 89 private final Map modulesByServletPath = new HashMap (); 90 91 private int nextRequestId; 92 93 private File outDir; 94 95 private final Object requestIdLock = new Object (); 96 97 private TreeLogger topLogger; 98 99 public GWTShellServlet() { 100 initMimeTypes(); 101 } 102 103 protected void doGet(HttpServletRequest request, HttpServletResponse response) 104 throws ServletException , IOException { 105 processFileRequest(request, response); 106 } 107 108 protected void doPost(HttpServletRequest request, HttpServletResponse response) 109 throws ServletException , IOException { 110 processFileRequest(request, response); 111 } 112 113 protected void processFileRequest(HttpServletRequest request, 114 HttpServletResponse response) throws IOException { 115 116 String pathInfo = request.getPathInfo(); 117 if (pathInfo.length() == 0 || pathInfo.equals("/")) { 118 response.setContentType("text/html"); 119 PrintWriter writer = response.getWriter(); 120 writer.println("<html><body><basefont face='arial'>"); 121 writer.println("To launch an application, specify a URL of the form <code>/<i>module</i>/<i>file.html</i></code>"); 122 writer.println("</body></html>"); 123 return; 124 } 125 126 TreeLogger logger = getLogger(); 127 128 RequestParts parts; 131 try { 132 parts = new RequestParts(request); 133 } catch (UnableToCompleteException e) { 134 sendErrorResponse(response, HttpServletResponse.SC_NOT_FOUND, 135 "Don't know what to do with this URL: '" + pathInfo + "'"); 136 return; 137 } 138 139 String partialPath = parts.partialPath; 140 String moduleName = parts.moduleName; 141 142 if (partialPath == null) { 143 response.sendRedirect(moduleName + "/"); 146 return; 147 } else if (partialPath.length() > 0) { 148 doGetPublicFile(request, response, logger, partialPath, moduleName); 151 return; 152 } else { 153 doGetModule(request, response, logger, parts); 156 return; 157 } 158 } 159 160 protected void service(HttpServletRequest request, 161 HttpServletResponse response) throws ServletException , IOException { 162 163 TreeLogger logger = getLogger(); 164 int id = allocateRequestId(); 165 if (logger.isLoggable(TreeLogger.TRACE)) { 166 StringBuffer url = request.getRequestURL(); 167 168 logger = logger.branch(TreeLogger.TRACE, "Request " + id + ": " + url, 170 null); 171 } 172 173 String servletClassName = null; 174 175 try { 176 RequestParts parts = new RequestParts(request); 179 180 ModuleDef moduleDef = (ModuleDef) loadedModulesByName.get(parts.moduleName); 186 if (moduleDef != null) { 187 String servletPath = "/" + parts.partialPath; 192 servletClassName = moduleDef.findServletForPath(servletPath); 193 194 } else { 196 } 198 } catch (UnableToCompleteException e) { 199 } 201 202 if (servletClassName == null) { 204 String path = request.getPathInfo(); 207 ModuleDef moduleDef = (ModuleDef) modulesByServletPath.get(path); 208 if (moduleDef != null) { 209 servletClassName = moduleDef.findServletForPath(path); 211 212 if (servletClassName != null) { 213 TreeLogger branch = logger.branch(TreeLogger.WARN, 214 "Use of deprecated hosted mode servlet path mapping", null); 215 branch.log( 216 TreeLogger.WARN, 217 "The client code is invoking the servlet with a URL that is not module-relative: " 218 + path, null); 219 branch.log( 220 TreeLogger.WARN, 221 "Prepend GWT.getModuleBaseURL() to the URL in client code to create a module-relative URL: /" 222 + moduleDef.getName() + path, null); 223 branch.log( 224 TreeLogger.WARN, 225 "Using module-relative URLs ensures correct URL-independent behavior in external servlet containers", 226 null); 227 } 228 229 } else { 231 } 233 } 234 236 if (servletClassName != null) { 238 HttpServlet delegatee = tryGetOrLoadServlet(logger, servletClassName); 239 if (delegatee == null) { 240 logger.log(TreeLogger.ERROR, "Unable to dispatch request", null); 241 sendErrorResponse(response, 242 HttpServletResponse.SC_INTERNAL_SERVER_ERROR, 243 "Unable to find/load mapped servlet class '" + servletClassName 244 + "'"); 245 return; 246 } 247 248 delegatee.service(request, response); 250 } else { 251 super.service(request, response); 254 } 255 } 256 257 private int allocateRequestId() { 258 synchronized (requestIdLock) { 259 return nextRequestId++; 260 } 261 } 262 263 268 private boolean autoGenerateResources(HttpServletRequest request, 269 HttpServletResponse response, TreeLogger logger, String partialPath, 270 String moduleName) throws IOException { 271 272 boolean nocacheHtml = partialPath.equals(moduleName + ".nocache.js"); 276 boolean nocacheScript = !nocacheHtml 277 && partialPath.equals(moduleName + "-xs.nocache.js"); 278 if (nocacheHtml || nocacheScript) { 279 if (request.getParameter("compiled") == null) { 281 try { 283 String js = genSelectionScript(logger, moduleName, nocacheScript); 284 setResponseCacheHeaders(response, 0); response.setStatus(HttpServletResponse.SC_OK); 286 response.setContentType("text/javascript"); 287 response.getWriter().println(js); 288 return true; 289 } catch (UnableToCompleteException e) { 290 } 294 } 295 } 296 297 return false; 298 } 299 300 private void doGetModule(HttpServletRequest request, 301 HttpServletResponse response, TreeLogger logger, RequestParts parts) 302 throws IOException { 303 304 if ("favicon.ico".equalsIgnoreCase(parts.moduleName)) { 305 sendErrorResponse(response, HttpServletResponse.SC_NOT_FOUND, 306 "Icon not available"); 307 return; 308 } 309 310 String msg = "The development shell servlet received a request to generate a host page for module '" 313 + parts.moduleName + "' "; 314 315 logger = logger.branch(TreeLogger.TRACE, msg, null); 316 317 try { 318 getModuleDef(logger, parts.moduleName); 320 } catch (UnableToCompleteException e) { 321 sendErrorResponse(response, HttpServletResponse.SC_NOT_FOUND, 322 "Unable to find/load module '" + parts.moduleName 323 + "' (see server log for details)"); 324 return; 325 } 326 327 response.setContentType("text/html"); 328 PrintWriter writer = response.getWriter(); 329 writer.println("<html><head>"); 330 writer.print("<script language='javascript' SRC='"); 331 writer.print(parts.moduleName); 332 writer.println(".nocache.js'></script>"); 333 334 Map params = request.getParameterMap(); 337 for (Iterator iter = params.entrySet().iterator(); iter.hasNext();) { 338 Map.Entry entry = (Map.Entry ) iter.next(); 339 String [] values = (String []) entry.getValue(); 340 if (values.length > 0) { 341 writer.print("<meta name='gwt:property' content='"); 342 writer.print(entry.getKey()); 343 writer.print("="); 344 writer.print(values[values.length - 1]); 345 writer.println("'>"); 346 } 347 } 348 349 writer.println("</head><body>"); 350 writer.println("<iframe SRC=\"javascript:''\" id='__gwt_historyFrame' " 351 + "style='width:0;height:0;border:0'></iframe>"); 352 writer.println("</body></html>"); 353 354 } 356 357 370 private void doGetPublicFile(HttpServletRequest request, 371 HttpServletResponse response, TreeLogger logger, String partialPath, 372 String moduleName) throws IOException { 373 374 String msg = "The development shell servlet received a request for '" 376 + partialPath + "' in module '" + moduleName + "' "; 377 logger = logger.branch(TreeLogger.TRACE, msg, null); 378 379 if (autoGenerateResources(request, response, logger, partialPath, 381 moduleName)) { 382 return; 383 } 384 385 URL foundResource; 386 try { 387 ModuleDef moduleDef = getModuleDef(logger, moduleName); 390 foundResource = moduleDef.findPublicFile(partialPath); 391 392 if (foundResource == null) { 393 File moduleDir = new File (getOutputDir(), moduleName); 395 File requestedFile = new File (moduleDir, partialPath); 396 if (requestedFile.exists()) { 397 try { 398 foundResource = requestedFile.toURL(); 399 } catch (MalformedURLException e) { 400 } 402 } 403 404 if (foundResource == null) { 405 msg = "Resource not found: " + partialPath; 406 logger.log(TreeLogger.WARN, msg, null); 407 throw new UnableToCompleteException(); 408 } 409 } 410 } catch (UnableToCompleteException e) { 411 sendErrorResponse(response, HttpServletResponse.SC_NOT_FOUND, 412 "Cannot find resource '" + partialPath 413 + "' in the public path of module '" + moduleName + "'"); 414 return; 415 } 416 417 String path = foundResource.toExternalForm(); 419 String mimeType = null; 420 try { 421 mimeType = getServletContext().getMimeType(path); 422 } catch (UnsupportedOperationException e) { 423 } 426 427 if (mimeType == null) { 428 mimeType = guessMimeType(path); 429 msg = "Guessed MIME type '" + mimeType + "'"; 430 logger.log(TreeLogger.TRACE, msg, null); 431 } 432 433 maybeIssueXhtmlWarning(logger, mimeType, partialPath); 434 435 long cacheSeconds = getCacheTime(path); 436 437 InputStream is = null; 438 try { 439 URLConnection conn = foundResource.openConnection(); 441 long lastModified = conn.getLastModified(); 442 if (isNotModified(request, lastModified)) { 443 response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); 444 setResponseCacheHeaders(response, cacheSeconds); 445 return; 446 } 447 448 response.setStatus(HttpServletResponse.SC_OK); 450 long now = new Date ().getTime(); 451 response.setHeader(HttpHeaders.DATE, 452 HttpHeaders.toInternetDateFormat(now)); 453 response.setContentType(mimeType); 454 String lastModifiedStr = HttpHeaders.toInternetDateFormat(lastModified); 455 response.setHeader(HttpHeaders.LAST_MODIFIED, lastModifiedStr); 456 457 setResponseCacheHeaders(response, cacheSeconds); 461 462 int contentLength = conn.getContentLength(); 464 if (contentLength >= 0) { 465 response.setHeader(HttpHeaders.CONTENT_LENGTH, 466 Integer.toString(contentLength)); 467 } 468 469 is = foundResource.openStream(); 471 streamOut(is, response.getOutputStream(), 1024 * 8); 472 } finally { 473 if (is != null) { 474 try { 475 is.close(); 476 } catch (IOException swallowed) { 477 } 480 } 481 } 482 } 483 484 490 private String genSelectionScript(TreeLogger logger, String moduleName, 491 boolean asScript) throws UnableToCompleteException { 492 String msg = asScript ? "Generating a script selection script for module " 493 : "Generating an html selection script for module "; 494 msg += moduleName; 495 logger.log(TreeLogger.TRACE, msg, null); 496 497 ModuleDef moduleDef = getModuleDef(logger, moduleName); 498 SelectionScriptGenerator gen = new SelectionScriptGenerator(moduleDef); 499 return gen.generateSelectionScript(false, asScript); 500 } 501 502 509 private long getCacheTime(String path) { 510 int lastDot = path.lastIndexOf('.'); 511 if (lastDot >= 0) { 512 String prefix = path.substring(0, lastDot); 513 if (prefix.endsWith(".cache")) { 514 return HttpHeaders.SEC_YR; 517 } else if (prefix.endsWith(".nocache")) { 518 return 0; 519 } 520 } 521 return DEFAULT_CACHE_SECONDS; 522 } 523 524 private synchronized TreeLogger getLogger() { 525 if (topLogger == null) { 526 ServletContext servletContext = getServletContext(); 527 final String attr = "com.google.gwt.dev.shell.logger"; 528 topLogger = (TreeLogger) servletContext.getAttribute(attr); 529 if (topLogger == null) { 530 topLogger = new ServletContextTreeLogger(servletContext); 533 } 534 } 535 return topLogger; 536 } 537 538 541 private ModuleDef getModuleDef(TreeLogger logger, String moduleName) 542 throws UnableToCompleteException { 543 synchronized (loadedModulesByName) { 544 ModuleDef moduleDef = (ModuleDef) loadedModulesByName.get(moduleName); 545 if (moduleDef == null) { 546 moduleDef = ModuleDefLoader.loadFromClassPath(logger, moduleName); 547 loadedModulesByName.put(moduleName, moduleDef); 548 549 String [] servletPaths = moduleDef.getServletPaths(); 556 for (int i = 0; i < servletPaths.length; i++) { 557 ModuleDef oldDef = (ModuleDef) modulesByServletPath.put( 558 servletPaths[i], moduleDef); 559 if (oldDef != null) { 560 logger.log(TreeLogger.WARN, "Undefined behavior: Servlet path " 561 + servletPaths[i] + " conflicts in modules " 562 + moduleDef.getName() + " and " + oldDef.getName(), null); 563 } 564 } 565 } 567 return moduleDef; 568 } 569 } 570 571 private synchronized File getOutputDir() { 572 if (outDir == null) { 573 ServletContext servletContext = getServletContext(); 574 final String attr = "com.google.gwt.dev.shell.outdir"; 575 outDir = (File ) servletContext.getAttribute(attr); 576 assert (outDir != null); 577 } 578 return outDir; 579 } 580 581 private String guessMimeType(String fullPath) { 582 int dot = fullPath.lastIndexOf('.'); 583 if (dot != -1) { 584 String ext = fullPath.substring(dot + 1); 585 String mimeType = (String ) mimeTypes.get(ext); 586 if (mimeType != null) { 587 return mimeType; 588 } 589 590 } 593 594 return "application/octet-stream"; 597 } 598 599 private void initMimeTypes() { 600 mimeTypes.put("abs", "audio/x-mpeg"); 601 mimeTypes.put("ai", "application/postscript"); 602 mimeTypes.put("aif", "audio/x-aiff"); 603 mimeTypes.put("aifc", "audio/x-aiff"); 604 mimeTypes.put("aiff", "audio/x-aiff"); 605 mimeTypes.put("aim", "application/x-aim"); 606 mimeTypes.put("art", "image/x-jg"); 607 mimeTypes.put("asf", "video/x-ms-asf"); 608 mimeTypes.put("asx", "video/x-ms-asf"); 609 mimeTypes.put("au", "audio/basic"); 610 mimeTypes.put("avi", "video/x-msvideo"); 611 mimeTypes.put("avx", "video/x-rad-screenplay"); 612 mimeTypes.put("bcpio", "application/x-bcpio"); 613 mimeTypes.put("bin", "application/octet-stream"); 614 mimeTypes.put("bmp", "image/bmp"); 615 mimeTypes.put("body", "text/html"); 616 mimeTypes.put("cdf", "application/x-cdf"); 617 mimeTypes.put("cer", "application/x-x509-ca-cert"); 618 mimeTypes.put("class", "application/java"); 619 mimeTypes.put("cpio", "application/x-cpio"); 620 mimeTypes.put("csh", "application/x-csh"); 621 mimeTypes.put("css", "text/css"); 622 mimeTypes.put("dib", "image/bmp"); 623 mimeTypes.put("doc", "application/msword"); 624 mimeTypes.put("dtd", "text/plain"); 625 mimeTypes.put("dv", "video/x-dv"); 626 mimeTypes.put("dvi", "application/x-dvi"); 627 mimeTypes.put("eps", "application/postscript"); 628 mimeTypes.put("etx", "text/x-setext"); 629 mimeTypes.put("exe", "application/octet-stream"); 630 mimeTypes.put("gif", "image/gif"); 631 mimeTypes.put("gtar", "application/x-gtar"); 632 mimeTypes.put("gz", "application/x-gzip"); 633 mimeTypes.put("hdf", "application/x-hdf"); 634 mimeTypes.put("hqx", "application/mac-binhex40"); 635 mimeTypes.put("htc", "text/x-component"); 636 mimeTypes.put("htm", "text/html"); 637 mimeTypes.put("html", "text/html"); 638 mimeTypes.put("hqx", "application/mac-binhex40"); 639 mimeTypes.put("ief", "image/ief"); 640 mimeTypes.put("jad", "text/vnd.sun.j2me.app-descriptor"); 641 mimeTypes.put("jar", "application/java-archive"); 642 mimeTypes.put("java", "text/plain"); 643 mimeTypes.put("jnlp", "application/x-java-jnlp-file"); 644 mimeTypes.put("jpe", "image/jpeg"); 645 mimeTypes.put("jpeg", "image/jpeg"); 646 mimeTypes.put("jpg", "image/jpeg"); 647 mimeTypes.put("js", "text/javascript"); 648 mimeTypes.put("jsf", "text/plain"); 649 mimeTypes.put("jspf", "text/plain"); 650 mimeTypes.put("kar", "audio/x-midi"); 651 mimeTypes.put("latex", "application/x-latex"); 652 mimeTypes.put("m3u", "audio/x-mpegurl"); 653 mimeTypes.put("mac", "image/x-macpaint"); 654 mimeTypes.put("man", "application/x-troff-man"); 655 mimeTypes.put("me", "application/x-troff-me"); 656 mimeTypes.put("mid", "audio/x-midi"); 657 mimeTypes.put("midi", "audio/x-midi"); 658 mimeTypes.put("mif", "application/x-mif"); 659 mimeTypes.put("mov", "video/quicktime"); 660 mimeTypes.put("movie", "video/x-sgi-movie"); 661 mimeTypes.put("mp1", "audio/x-mpeg"); 662 mimeTypes.put("mp2", "audio/x-mpeg"); 663 mimeTypes.put("mp3", "audio/x-mpeg"); 664 mimeTypes.put("mpa", "audio/x-mpeg"); 665 mimeTypes.put("mpe", "video/mpeg"); 666 mimeTypes.put("mpeg", "video/mpeg"); 667 mimeTypes.put("mpega", "audio/x-mpeg"); 668 mimeTypes.put("mpg", "video/mpeg"); 669 mimeTypes.put("mpv2", "video/mpeg2"); 670 mimeTypes.put("ms", "application/x-wais-source"); 671 mimeTypes.put("nc", "application/x-netcdf"); 672 mimeTypes.put("oda", "application/oda"); 673 mimeTypes.put("pbm", "image/x-portable-bitmap"); 674 mimeTypes.put("pct", "image/pict"); 675 mimeTypes.put("pdf", "application/pdf"); 676 mimeTypes.put("pgm", "image/x-portable-graymap"); 677 mimeTypes.put("pic", "image/pict"); 678 mimeTypes.put("pict", "image/pict"); 679 mimeTypes.put("pls", "audio/x-scpls"); 680 mimeTypes.put("png", "image/png"); 681 mimeTypes.put("pnm", "image/x-portable-anymap"); 682 mimeTypes.put("pnt", "image/x-macpaint"); 683 mimeTypes.put("ppm", "image/x-portable-pixmap"); 684 mimeTypes.put("ppt", "application/powerpoint"); 685 mimeTypes.put("ps", "application/postscript"); 686 mimeTypes.put("psd", "image/x-photoshop"); 687 mimeTypes.put("qt", "video/quicktime"); 688 mimeTypes.put("qti", "image/x-quicktime"); 689 mimeTypes.put("qtif", "image/x-quicktime"); 690 mimeTypes.put("ras", "image/x-cmu-raster"); 691 mimeTypes.put("rgb", "image/x-rgb"); 692 mimeTypes.put("rm", "application/vnd.rn-realmedia"); 693 mimeTypes.put("roff", "application/x-troff"); 694 mimeTypes.put("rtf", "application/rtf"); 695 mimeTypes.put("rtx", "text/richtext"); 696 mimeTypes.put("sh", "application/x-sh"); 697 mimeTypes.put("shar", "application/x-shar"); 698 mimeTypes.put("smf", "audio/x-midi"); 699 mimeTypes.put("sit", "application/x-stuffit"); 700 mimeTypes.put("snd", "audio/basic"); 701 mimeTypes.put("src", "application/x-wais-source"); 702 mimeTypes.put("sv4cpio", "application/x-sv4cpio"); 703 mimeTypes.put("sv4crc", "application/x-sv4crc"); 704 mimeTypes.put("swf", "application/x-shockwave-flash"); 705 mimeTypes.put("t", "application/x-troff"); 706 mimeTypes.put("tar", "application/x-tar"); 707 mimeTypes.put("tcl", "application/x-tcl"); 708 mimeTypes.put("tex", "application/x-tex"); 709 mimeTypes.put("texi", "application/x-texinfo"); 710 mimeTypes.put("texinfo", "application/x-texinfo"); 711 mimeTypes.put("tif", "image/tiff"); 712 mimeTypes.put("tiff", "image/tiff"); 713 mimeTypes.put("tr", "application/x-troff"); 714 mimeTypes.put("tsv", "text/tab-separated-values"); 715 mimeTypes.put("txt", "text/plain"); 716 mimeTypes.put("ulw", "audio/basic"); 717 mimeTypes.put("ustar", "application/x-ustar"); 718 mimeTypes.put("xbm", "image/x-xbitmap"); 719 mimeTypes.put("xht", "application/xhtml+xml"); 720 mimeTypes.put("xhtml", "application/xhtml+xml"); 721 mimeTypes.put("xml", "text/xml"); 722 mimeTypes.put("xpm", "image/x-xpixmap"); 723 mimeTypes.put("xsl", "text/xml"); 724 mimeTypes.put("xwd", "image/x-xwindowdump"); 725 mimeTypes.put("wav", "audio/x-wav"); 726 mimeTypes.put("svg", "image/svg+xml"); 727 mimeTypes.put("svgz", "image/svg+xml"); 728 mimeTypes.put("vsd", "application/x-visio"); 729 mimeTypes.put("wbmp", "image/vnd.wap.wbmp"); 730 mimeTypes.put("wml", "text/vnd.wap.wml"); 731 mimeTypes.put("wmlc", "application/vnd.wap.wmlc"); 732 mimeTypes.put("wmls", "text/vnd.wap.wmlscript"); 733 mimeTypes.put("wmlscriptc", "application/vnd.wap.wmlscriptc"); 734 mimeTypes.put("wrl", "x-world/x-vrml"); 735 mimeTypes.put("Z", "application/x-compress"); 736 mimeTypes.put("z", "application/x-compress"); 737 mimeTypes.put("zip", "application/zip"); 738 } 739 740 744 private boolean isNotModified(HttpServletRequest request, long ageOfServerCopy) { 745 ageOfServerCopy -= (ageOfServerCopy % 1000); 752 753 long ageOfClientCopy = 0; 754 String ifModifiedSince = request.getHeader("If-Modified-Since"); 755 if (ifModifiedSince != null) { 756 int lastSemi = ifModifiedSince.lastIndexOf(';'); 760 if (lastSemi != -1) { 761 ifModifiedSince = ifModifiedSince.substring(0, lastSemi); 762 } 763 ageOfClientCopy = HttpHeaders.fromInternetDateFormat(ifModifiedSince); 764 } 765 766 if (ageOfClientCopy >= ageOfServerCopy) { 767 return true; 770 } else { 771 return false; 774 } 775 } 776 777 private void maybeIssueXhtmlWarning(TreeLogger logger, String mimeType, 778 String path) { 779 if (!XHTML_MIME_TYPE.equals(mimeType)) { 780 return; 781 } 782 783 String msg = "File was returned with content-type of \"" + mimeType 784 + "\". GWT requires browser features that are not available to " 785 + "documents with this content-type."; 786 787 int ix = path.lastIndexOf('.'); 788 if (ix >= 0 && ix < path.length()) { 789 String base = path.substring(0, ix); 790 msg += " Consider renaming \"" + path + "\" to \"" + base + ".html\"."; 791 } 792 793 logger.log(TreeLogger.WARN, msg, null); 794 } 795 796 private void sendErrorResponse(HttpServletResponse response, int statusCode, 797 String msg) throws IOException { 798 response.setContentType("text/html"); 799 response.getWriter().println(msg); 800 response.setStatus(statusCode); 801 } 802 803 815 private void setResponseCacheHeaders(HttpServletResponse response, 816 long cacheTime) { 817 long expires; 818 if (cacheTime < 0) { 819 throw new IllegalArgumentException ("cacheTime of " + cacheTime 820 + " is negative"); 821 } 822 if (cacheTime > 0) { 823 expires = new Date ().getTime() + cacheTime * HttpHeaders.MS_SEC; 825 } else { 826 expires = HttpHeaders.SEC_DAY * HttpHeaders.MS_SEC; 831 } 832 response.setHeader(HttpHeaders.CACHE_CONTROL, 833 HttpHeaders.CACHE_CONTROL_MAXAGE + cacheTime); 834 String expiresString = HttpHeaders.toInternetDateFormat(expires); 835 response.setHeader(HttpHeaders.EXPIRES, expiresString); 836 } 837 838 private void streamOut(InputStream in, OutputStream out, int bufferSize) 839 throws IOException { 840 assert (bufferSize >= 0); 841 842 byte[] buffer = new byte[bufferSize]; 843 int bytesRead = 0; 844 while (true) { 845 bytesRead = in.read(buffer); 846 if (bytesRead >= 0) { 847 out.write(buffer, 0, bytesRead); 849 } else { 850 return; 852 } 853 } 854 } 855 856 private HttpServlet tryGetOrLoadServlet(TreeLogger logger, String className) { 857 synchronized (loadedServletsByClassName) { 858 HttpServlet servlet = (HttpServlet ) loadedServletsByClassName.get(className); 859 if (servlet != null) { 860 return servlet; 863 } 864 865 Throwable caught = null; 868 try { 869 Class servletClass = Class.forName(className); 870 Object newInstance = servletClass.newInstance(); 871 if (!(newInstance instanceof HttpServlet )) { 872 logger.log(TreeLogger.ERROR, 873 "Not compatible with HttpServlet: " + className 874 + " (does your service extend RemoteServiceServlet?)", null); 875 return null; 876 } 877 878 servlet = (HttpServlet ) newInstance; 881 882 servlet.init(getServletConfig()); 883 884 loadedServletsByClassName.put(className, servlet); 885 return servlet; 886 } catch (ClassNotFoundException e) { 887 caught = e; 888 } catch (InstantiationException e) { 889 caught = e; 890 } catch (IllegalAccessException e) { 891 caught = e; 892 } catch (ServletException e) { 893 caught = e; 894 } 895 String msg = "Unable to instantiate '" + className + "'"; 896 logger.log(TreeLogger.ERROR, msg, caught); 897 return null; 898 } 899 } 900 } 901 | Popular Tags |