You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by jk...@apache.org on 2006/12/02 23:11:17 UTC

svn commit: r481641 - in /tapestry/tapestry4/trunk/tapestry-framework/src: java/org/apache/tapestry/asset/AssetService.java test/org/apache/tapestry/valid/TestUrlValidator.java

Author: jkuhnert
Date: Sat Dec  2 14:11:16 2006
New Revision: 481641

URL: http://svn.apache.org/viewvc?view=rev&rev=481641
Log:
Vastly improved AssetService cache header response handling. Page load times should go way way down with 
cahcing enabled, and when caching is disabled it will actually accurately report the last modified 
time of each resource in question. (instead of generically using some other time, like system startup/ etc..)

Hard to describe how much faster things become. 

Modified:
    tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/asset/AssetService.java
    tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/valid/TestUrlValidator.java

Modified: tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/asset/AssetService.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/asset/AssetService.java?view=diff&rev=481641&r1=481640&r2=481641
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/asset/AssetService.java (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/asset/AssetService.java Sat Dec  2 14:11:16 2006
@@ -14,8 +14,6 @@
 
 package org.apache.tapestry.asset;
 
-import java.io.BufferedInputStream;
-import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -32,10 +30,10 @@
 import javax.servlet.http.HttpServletResponse;
 
 import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.io.IOUtils;
 import org.apache.commons.logging.Log;
 import org.apache.hivemind.ClassResolver;
 import org.apache.hivemind.util.Defense;
-import org.apache.hivemind.util.IOUtils;
 import org.apache.tapestry.IRequestCycle;
 import org.apache.tapestry.Tapestry;
 import org.apache.tapestry.engine.IEngineService;
@@ -101,8 +99,6 @@
         _mimeTypes.put("html", "text/html");
     }
 
-    private static final int BUFFER_SIZE = 10240;
-
     private static final DateFormat CACHED_FORMAT = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z", Locale.ENGLISH);
     
     /** Represents a month of time in seconds. */
@@ -229,6 +225,8 @@
         String md5Digest = cycle.getParameter(DIGEST);
         boolean checkDigest = !_unprotectedMatcher.containsResource(path);
         
+        URLConnection resourceConnection = null;
+        
         try
         {
             if (checkDigest
@@ -254,21 +252,22 @@
                 _response.setStatus(HttpServletResponse.SC_NOT_FOUND);
                 _log.warn(AssetMessages.noSuchResource(path));
                 return;
-                // throw new ApplicationRuntimeException(AssetMessages.noSuchResource(path));
             }
             
+            resourceConnection = resourceURL.openConnection();
+            
             // check caching for unprotected resources
             
-            if (!checkDigest && cachedResource(resourceURL))
+            if (!checkDigest && cachedResource(resourceConnection))
                 return;
             
-            URLConnection resourceConnection = resourceURL.openConnection();
-            
             writeAssetContent(cycle, path, resourceConnection);
         }
         catch (Throwable ex)
         {
             _exceptionReporter.reportRequestException(AssetMessages.exceptionReportTitle(path), ex);
+        } finally {
+            resourceConnection = null;
         }
 
     }
@@ -331,13 +330,8 @@
      * @since 4.1
      */
     
-    boolean cachedResource(URL resourceURL)
+    boolean cachedResource(URLConnection resourceURL)
     {
-        File resource = new File(resourceURL.getFile());
-        
-        if (!resource.exists()) 
-            return false;
-        
         // even if it doesn't exist in header the value will be -1, 
         // which means we need to write out the contents of the resource
         
@@ -349,7 +343,7 @@
                 modify = CACHED_FORMAT.parse(header).getTime();
         } catch (ParseException e) { e.printStackTrace(); }
         
-        if (resource.lastModified() > modify
+        if (resourceURL.getLastModified() > modify
                 || (_lastResetTime > modify))
             return false;
         
@@ -376,48 +370,47 @@
 
             if (contentLength > 0)
                 _response.setContentLength(contentLength);
-
-            _response.setDateHeader("Last-Modified", _startupTime);
-            _response.setDateHeader("Expires", _expireTime);
+            
+            long lastModified = _startupTime;
+            if (_lastResetTime > 0)
+                lastModified = _lastResetTime;
+            else
+                lastModified = resourceConnection.getLastModified();
+            
+            _response.setDateHeader("Last-Modified", lastModified);
+            
+            // write out expiration/cache info
+            
+            if (_lastResetTime <= 0) {
+                
+                _response.setDateHeader("Expires", _expireTime);
+                _response.setHeader("Cache-Control", "max-age=" + (MONTH_SECONDS * 3));
+                _response.setHeader("ETag", String.valueOf(resourcePath.hashCode()));
+            }
             
             // Set the content type. If the servlet container doesn't
             // provide it, try and guess it by the extension.
-
+            
             if (contentType == null || contentType.length() == 0)
                 contentType = getMimeType(resourcePath);
             
-            // force image caching when detected, esp helps with ie related things
+            input = resourceConnection.getInputStream();
+            
+            byte[] data = IOUtils.toByteArray(input);
+            
+            // force image(or other) caching when detected, esp helps with ie related things
             // see http://mir.aculo.us/2005/08/28/internet-explorer-and-ajax-image-caching-woes
             
-            if (contentType != null && "image".indexOf(contentType) > -1) {
-                
-                _response.setHeader("Cache-Control", "max-age=" + MONTH_SECONDS);
-                
-                _response.setHeader("ETag", String.valueOf(resourcePath.hashCode()));
-            }
+            _response.setContentLength(data.length);
             
             OutputStream output = _response.getOutputStream(new ContentType(contentType));
-
-            input = new BufferedInputStream(resourceConnection.getInputStream());
-
-            byte[] buffer = new byte[BUFFER_SIZE];
-
-            while (true)
-            {
-                int bytesRead = input.read(buffer);
-
-                if (bytesRead < 0)
-                    break;
-
-                output.write(buffer, 0, bytesRead);
-            }
-
-            input.close();
-            input = null;
+            
+            output.write(data);
         }
         finally
         {
-            IOUtils.close(input);
+            IOUtils.closeQuietly(input);
+            input = null;
         }
     }
 

Modified: tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/valid/TestUrlValidator.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/valid/TestUrlValidator.java?view=diff&rev=481641&r1=481640&r2=481641
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/valid/TestUrlValidator.java (original)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/valid/TestUrlValidator.java Sat Dec  2 14:11:16 2006
@@ -30,7 +30,7 @@
  * @author Jimmy Dyson
  * @since 3.0
  */
-@Test
+@Test(sequential=true)
 public class TestUrlValidator extends BaseValidatorTestCase
 {
     private UrlValidator v = new UrlValidator();