View Javadoc

1   package com.atlassian.plugin.servlet.util;
2   
3   import javax.servlet.http.HttpServletRequest;
4   import javax.servlet.http.HttpServletResponse;
5   import java.util.Date;
6   
7   /**
8    * This class manages the last modified date of a single HTTP resource.
9    */
10  public class LastModifiedHandler
11  {
12      private long lastModified;
13      private String etag;
14      private static final int ONE_SECOND_MILLIS = 1000;
15  
16      public LastModifiedHandler()
17      {
18          modified(new Date());
19      }
20  
21      public LastModifiedHandler(Date lastModifiedDate)
22      {
23          modified(lastModifiedDate);
24      }
25      /**
26       * Check whether we need to generate a response for this request. Set the necessary headers on the response, and if
27       * we don't need to provide content, set the response status to 304.
28       *
29       * If this method returns true, the caller should not perform any more processing on the request.
30       *
31       * @return true if we don't need to provide any data to satisfy this request
32       */
33      public boolean checkRequest(HttpServletRequest request, HttpServletResponse response)
34      {
35          return checkRequest(request, response, lastModified, etag);
36      }
37  
38      /**
39       * The content has changed, reset the modified date and the etag
40       */
41      public void modified()
42      {
43          modified(new Date());
44      }
45  
46      private void modified(Date date)
47      {
48          lastModified = calculateLastModifiedDate(date);
49          etag = calculateEtag(lastModified);
50      }
51  
52      private static long calculateLastModifiedDate(Date lastModifiedDate)
53      {
54          long lastModified = lastModifiedDate.getTime();
55          // resolution of 1 second
56          lastModified -= lastModified % ONE_SECOND_MILLIS;
57          return lastModified;
58      }
59  
60      private static String calculateEtag(long lastModified)
61      {
62          return "\"" + lastModified + "\"";
63      }
64  
65      /**
66       * This static method is used when the resource being served by the servlet keeps track of the last modified date,
67       * and so no state needs to be maintained by this handler.
68       */
69      public static boolean checkRequest(HttpServletRequest request, HttpServletResponse response, Date lastModifiedDate)
70      {
71          long lastModified = calculateLastModifiedDate(lastModifiedDate);
72          return checkRequest(request, response, lastModified,  calculateEtag(lastModified));
73      }
74  
75      private static boolean checkRequest(HttpServletRequest request, HttpServletResponse response, long lastModified, String etagString)
76      {
77          if ("true".equals(System.getProperty("atlassian.disable.caches", "false")))
78                  return false;
79  
80          response.setDateHeader("Last-Modified",lastModified);
81          response.setHeader("ETag",etagString);
82  
83          long ifModifiedSince = request.getDateHeader("If-Modified-Since");
84          String ifNoneMatch = request.getHeader("If-None-Match");
85          if (noConditionalGetHeadersFound(ifModifiedSince, ifNoneMatch)
86              || isContentModifiedSince(ifModifiedSince, lastModified)
87              || !etagMatches(ifNoneMatch, etagString))
88          {
89              return false;
90          }
91          response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
92          return true;
93      }
94  
95      private static boolean etagMatches(String ifNoneMatch, String etagString)
96      {
97          return ifNoneMatch != null && ifNoneMatch.equals(etagString);
98      }
99  
100     private static boolean isContentModifiedSince(long ifModifiedSince, long lastModified)
101     {
102         return ifModifiedSince != -1 && ifModifiedSince < lastModified;
103     }
104 
105     private static boolean noConditionalGetHeadersFound(long ifModifiedSince, String ifNoneMatch)
106     {
107         return ifModifiedSince == -1 && ifNoneMatch == null;
108     }
109 }