Save This Page
Home » tapestry-src-5.0.19 » org.apache.tapestry5.internal.services » [javadoc | source]
    1   // Copyright 2006, 2008 The Apache Software Foundation
    2   //
    3   // Licensed under the Apache License, Version 2.0 (the "License");
    4   // you may not use this file except in compliance with the License.
    5   // You may obtain a copy of the License at
    6   //
    7   //     http://www.apache.org/licenses/LICENSE-2.0
    8   //
    9   // Unless required by applicable law or agreed to in writing, software
   10   // distributed under the License is distributed on an "AS IS" BASIS,
   11   // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   12   // See the License for the specific language governing permissions and
   13   // limitations under the License.
   14   
   15   package org.apache.tapestry5.internal.services;
   16   
   17   import org.apache.tapestry5.ioc.Resource;
   18   import org.apache.tapestry5.ioc.internal.util.ClasspathResource;
   19   import org.apache.tapestry5.services.ClasspathAssetAliasManager;
   20   import org.apache.tapestry5.services.Dispatcher;
   21   import org.apache.tapestry5.services.Request;
   22   import org.apache.tapestry5.services.Response;
   23   
   24   import javax.servlet.http.HttpServletResponse;
   25   import java.io.IOException;
   26   
   27   /**
   28    * Recognizes requests where the path begins with "/asset/" and delivers the content therein as a bytestream. Also
   29    * handles requests that are simply polling for a change to the file.
   30    *
   31    * @see ResourceStreamer
   32    * @see ClasspathAssetAliasManager
   33    * @see ResourceCache
   34    */
   35   public class AssetDispatcher implements Dispatcher
   36   {
   37       private final ResourceStreamer streamer;
   38   
   39       private final ClasspathAssetAliasManager aliasManager;
   40   
   41       private final ResourceCache resourceCache;
   42   
   43       static final String IF_MODIFIED_SINCE_HEADER = "If-Modified-Since";
   44   
   45       public AssetDispatcher(ResourceStreamer streamer, ClasspathAssetAliasManager aliasManager,
   46                              ResourceCache resourceCache)
   47       {
   48           this.streamer = streamer;
   49           this.aliasManager = aliasManager;
   50           this.resourceCache = resourceCache;
   51       }
   52   
   53       public boolean dispatch(Request request, Response response) throws IOException
   54       {
   55           String path = request.getPath();
   56   
   57           // Remember that the request path does not include the context path, so we can simply start
   58           // looking for the asset path prefix right off the bat.
   59   
   60           if (!path.startsWith(RequestConstants.ASSET_PATH_PREFIX)) return false;
   61   
   62           // ClassLoaders like their paths to start with a leading slash.
   63   
   64           String resourcePath = aliasManager.toResourcePath(path);
   65   
   66           Resource resource = findResourceAndValidateDigest(response, resourcePath);
   67   
   68           if (resource == null) return true;
   69   
   70           if (!resource.exists())
   71           {
   72               response.sendError(HttpServletResponse.SC_NOT_FOUND, ServicesMessages
   73                       .assetDoesNotExist(resource));
   74               return true;
   75           }
   76   
   77           long ifModifiedSince = 0;
   78   
   79           try
   80           {
   81               ifModifiedSince = request.getDateHeader(IF_MODIFIED_SINCE_HEADER);
   82           }
   83           catch (IllegalArgumentException ex)
   84           {
   85               // Simulate the header being missing if it is poorly formatted.
   86   
   87               ifModifiedSince = -1;
   88           }
   89   
   90           if (ifModifiedSince > 0)
   91           {
   92               long modified = resourceCache.getTimeModified(resource);
   93   
   94               if (ifModifiedSince >= modified)
   95               {
   96                   response.sendError(HttpServletResponse.SC_NOT_MODIFIED, "");
   97                   return true;
   98               }
   99           }
  100   
  101           streamer.streamResource(resource);
  102   
  103           return true;
  104       }
  105   
  106       /**
  107        * @param response     used to send errors back to the client
  108        * @param resourcePath the path to the requested resource, from the request
  109        * @return the resource for the path, with the digest stripped out of the URL, or null if the digest is invalid (and
  110        *         an error has been sent back to the client)
  111        * @throws IOException
  112        */
  113       private Resource findResourceAndValidateDigest(Response response, String resourcePath) throws IOException
  114       {
  115           Resource resource = new ClasspathResource(resourcePath);
  116   
  117           if (!resourceCache.requiresDigest(resource)) return resource;
  118   
  119           String file = resource.getFile();
  120   
  121           // Somehow this code got real ugly, but it's all about preventing NPEs when a resource
  122           // that should have a digest doesn't.
  123   
  124           boolean valid = false;
  125           Resource result = resource;
  126   
  127           int lastdotx = file.lastIndexOf('.');
  128   
  129           if (lastdotx > 0)
  130           {
  131               int prevdotx = file.lastIndexOf('.', lastdotx - 1);
  132   
  133               if (prevdotx > 0)
  134               {
  135   
  136                   String requestDigest = file.substring(prevdotx + 1, lastdotx);
  137   
  138                   // Strip the digest out of the file name.
  139   
  140                   String realFile = file.substring(0, prevdotx) + file.substring(lastdotx);
  141   
  142                   result = resource.forFile(realFile);
  143   
  144                   String actualDigest = resourceCache.getDigest(result);
  145   
  146                   valid = requestDigest.equals(actualDigest);
  147               }
  148           }
  149   
  150           if (!valid)
  151           {
  152               response.sendError(HttpServletResponse.SC_FORBIDDEN, ServicesMessages
  153                       .wrongAssetDigest(result));
  154               result = null;
  155           }
  156   
  157           return result;
  158       }
  159   }

Save This Page
Home » tapestry-src-5.0.19 » org.apache.tapestry5.internal.services » [javadoc | source]