View Javadoc

1   /* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
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  
16  package org.acegisecurity.ui.savedrequest;
17  
18  import java.text.DateFormat;
19  import java.text.ParseException;
20  import java.text.SimpleDateFormat;
21  
22  import java.util.Date;
23  import java.util.HashMap;
24  import java.util.Locale;
25  import java.util.TimeZone;
26  
27  
28  /**
29   * <p>Utility class to generate HTTP dates.</p>
30   * <p>This class is based on code in Apache Tomcat.</p>
31   *
32   * @author Remy Maucherat
33   * @author Andrey Grebnev
34   * @version $Id: FastHttpDateFormat.java 1784 2007-02-24 21:00:24Z luke_t $
35   */
36  public class FastHttpDateFormat {
37      //~ Static fields/initializers =====================================================================================
38  
39      /** HTTP date format. */
40      protected static final SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
41  
42      /** The set of SimpleDateFormat formats to use in <code>getDateHeader()</code>. */
43      protected static final SimpleDateFormat[] formats = {
44              new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
45              new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
46              new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US)
47          };
48  
49      /** GMT timezone - all HTTP dates are on GMT */
50      protected static final TimeZone gmtZone = TimeZone.getTimeZone("GMT");
51  
52      static {
53          format.setTimeZone(gmtZone);
54  
55          formats[0].setTimeZone(gmtZone);
56          formats[1].setTimeZone(gmtZone);
57          formats[2].setTimeZone(gmtZone);
58      }
59  
60      /** Instant on which the currentDate object was generated. */
61      protected static long currentDateGenerated = 0L;
62  
63      /** Current formatted date. */
64      protected static String currentDate = null;
65  
66      /** Formatter cache. */
67      protected static final HashMap formatCache = new HashMap();
68  
69      /** Parser cache. */
70      protected static final HashMap parseCache = new HashMap();
71  
72      //~ Methods ========================================================================================================
73  
74      /**
75       * Formats a specified date to HTTP format. If local format is not <code>null</code>, it's used instead.
76       *
77       * @param value Date value to format
78       * @param threadLocalformat The format to use (or <code>null</code> -- then HTTP format will be used)
79       *
80       * @return Formatted date
81       */
82      public static final String formatDate(long value, DateFormat threadLocalformat) {
83          String cachedDate = null;
84          Long longValue = new Long(value);
85  
86          try {
87              cachedDate = (String) formatCache.get(longValue);
88          } catch (Exception e) {}
89  
90          if (cachedDate != null) {
91              return cachedDate;
92          }
93  
94          String newDate = null;
95          Date dateValue = new Date(value);
96  
97          if (threadLocalformat != null) {
98              newDate = threadLocalformat.format(dateValue);
99  
100             synchronized (formatCache) {
101                 updateCache(formatCache, longValue, newDate);
102             }
103         } else {
104             synchronized (formatCache) {
105                 newDate = format.format(dateValue);
106                 updateCache(formatCache, longValue, newDate);
107             }
108         }
109 
110         return newDate;
111     }
112 
113     /**
114      * Gets the current date in HTTP format.
115      *
116      * @return Current date in HTTP format
117      */
118     public static final String getCurrentDate() {
119         long now = System.currentTimeMillis();
120 
121         if ((now - currentDateGenerated) > 1000) {
122             synchronized (format) {
123                 if ((now - currentDateGenerated) > 1000) {
124                     currentDateGenerated = now;
125                     currentDate = format.format(new Date(now));
126                 }
127             }
128         }
129 
130         return currentDate;
131     }
132 
133     /**
134      * Parses date with given formatters.
135      *
136      * @param value The string to parse
137      * @param formats Array of formats to use
138      *
139      * @return Parsed date (or <code>null</code> if no formatter mached)
140      */
141     private static Long internalParseDate(String value, DateFormat[] formats) {
142         Date date = null;
143 
144         for (int i = 0; (date == null) && (i < formats.length); i++) {
145             try {
146                 date = formats[i].parse(value);
147             } catch (ParseException e) {
148                 ;
149             }
150         }
151 
152         if (date == null) {
153             return null;
154         }
155 
156         return new Long(date.getTime());
157     }
158 
159     /**
160      * Tries to parse the given date as an HTTP date. If local format list is not <code>null</code>, it's used
161      * instead.
162      *
163      * @param value The string to parse
164      * @param threadLocalformats Array of formats to use for parsing. If <code>null</code>, HTTP formats are used.
165      *
166      * @return Parsed date (or -1 if error occured)
167      */
168     public static final long parseDate(String value, DateFormat[] threadLocalformats) {
169         Long cachedDate = null;
170 
171         try {
172             cachedDate = (Long) parseCache.get(value);
173         } catch (Exception e) {}
174 
175         if (cachedDate != null) {
176             return cachedDate.longValue();
177         }
178 
179         Long date = null;
180 
181         if (threadLocalformats != null) {
182             date = internalParseDate(value, threadLocalformats);
183 
184             synchronized (parseCache) {
185                 updateCache(parseCache, value, date);
186             }
187         } else {
188             synchronized (parseCache) {
189                 date = internalParseDate(value, formats);
190                 updateCache(parseCache, value, date);
191             }
192         }
193 
194         if (date == null) {
195             return (-1L);
196         } else {
197             return date.longValue();
198         }
199     }
200 
201     /**
202      * Updates cache.
203      *
204      * @param cache Cache to be updated
205      * @param key Key to be updated
206      * @param value New value
207      */
208     private static void updateCache(HashMap cache, Object key, Object value) {
209         if (value == null) {
210             return;
211         }
212 
213         if (cache.size() > 1000) {
214             cache.clear();
215         }
216 
217         cache.put(key, value);
218     }
219 }