001: /* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
002: *
003: * Licensed under the Apache License, Version 2.0 (the "License");
004: * you may not use this file except in compliance with the License.
005: * You may obtain a copy of the License at
006: *
007: * http://www.apache.org/licenses/LICENSE-2.0
008: *
009: * Unless required by applicable law or agreed to in writing, software
010: * distributed under the License is distributed on an "AS IS" BASIS,
011: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: * See the License for the specific language governing permissions and
013: * limitations under the License.
014: */
015:
016: package org.acegisecurity.ui.savedrequest;
017:
018: import java.text.DateFormat;
019: import java.text.ParseException;
020: import java.text.SimpleDateFormat;
021:
022: import java.util.Date;
023: import java.util.HashMap;
024: import java.util.Locale;
025: import java.util.TimeZone;
026:
027: /**
028: * <p>Utility class to generate HTTP dates.</p>
029: * <p>This class is based on code in Apache Tomcat.</p>
030: *
031: * @author Remy Maucherat
032: * @author Andrey Grebnev
033: * @version $Id: FastHttpDateFormat.java 1784 2007-02-24 21:00:24Z luke_t $
034: */
035: public class FastHttpDateFormat {
036: //~ Static fields/initializers =====================================================================================
037:
038: /** HTTP date format. */
039: protected static final SimpleDateFormat format = new SimpleDateFormat(
040: "EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
041:
042: /** The set of SimpleDateFormat formats to use in <code>getDateHeader()</code>. */
043: protected static final SimpleDateFormat[] formats = {
044: new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz",
045: Locale.US),
046: new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz",
047: Locale.US),
048: new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US) };
049:
050: /** GMT timezone - all HTTP dates are on GMT */
051: protected static final TimeZone gmtZone = TimeZone
052: .getTimeZone("GMT");
053:
054: static {
055: format.setTimeZone(gmtZone);
056:
057: formats[0].setTimeZone(gmtZone);
058: formats[1].setTimeZone(gmtZone);
059: formats[2].setTimeZone(gmtZone);
060: }
061:
062: /** Instant on which the currentDate object was generated. */
063: protected static long currentDateGenerated = 0L;
064:
065: /** Current formatted date. */
066: protected static String currentDate = null;
067:
068: /** Formatter cache. */
069: protected static final HashMap formatCache = new HashMap();
070:
071: /** Parser cache. */
072: protected static final HashMap parseCache = new HashMap();
073:
074: //~ Methods ========================================================================================================
075:
076: /**
077: * Formats a specified date to HTTP format. If local format is not <code>null</code>, it's used instead.
078: *
079: * @param value Date value to format
080: * @param threadLocalformat The format to use (or <code>null</code> -- then HTTP format will be used)
081: *
082: * @return Formatted date
083: */
084: public static final String formatDate(long value,
085: DateFormat threadLocalformat) {
086: String cachedDate = null;
087: Long longValue = new Long(value);
088:
089: try {
090: cachedDate = (String) formatCache.get(longValue);
091: } catch (Exception e) {
092: }
093:
094: if (cachedDate != null) {
095: return cachedDate;
096: }
097:
098: String newDate = null;
099: Date dateValue = new Date(value);
100:
101: if (threadLocalformat != null) {
102: newDate = threadLocalformat.format(dateValue);
103:
104: synchronized (formatCache) {
105: updateCache(formatCache, longValue, newDate);
106: }
107: } else {
108: synchronized (formatCache) {
109: newDate = format.format(dateValue);
110: updateCache(formatCache, longValue, newDate);
111: }
112: }
113:
114: return newDate;
115: }
116:
117: /**
118: * Gets the current date in HTTP format.
119: *
120: * @return Current date in HTTP format
121: */
122: public static final String getCurrentDate() {
123: long now = System.currentTimeMillis();
124:
125: if ((now - currentDateGenerated) > 1000) {
126: synchronized (format) {
127: if ((now - currentDateGenerated) > 1000) {
128: currentDateGenerated = now;
129: currentDate = format.format(new Date(now));
130: }
131: }
132: }
133:
134: return currentDate;
135: }
136:
137: /**
138: * Parses date with given formatters.
139: *
140: * @param value The string to parse
141: * @param formats Array of formats to use
142: *
143: * @return Parsed date (or <code>null</code> if no formatter mached)
144: */
145: private static Long internalParseDate(String value,
146: DateFormat[] formats) {
147: Date date = null;
148:
149: for (int i = 0; (date == null) && (i < formats.length); i++) {
150: try {
151: date = formats[i].parse(value);
152: } catch (ParseException e) {
153: ;
154: }
155: }
156:
157: if (date == null) {
158: return null;
159: }
160:
161: return new Long(date.getTime());
162: }
163:
164: /**
165: * Tries to parse the given date as an HTTP date. If local format list is not <code>null</code>, it's used
166: * instead.
167: *
168: * @param value The string to parse
169: * @param threadLocalformats Array of formats to use for parsing. If <code>null</code>, HTTP formats are used.
170: *
171: * @return Parsed date (or -1 if error occured)
172: */
173: public static final long parseDate(String value,
174: DateFormat[] threadLocalformats) {
175: Long cachedDate = null;
176:
177: try {
178: cachedDate = (Long) parseCache.get(value);
179: } catch (Exception e) {
180: }
181:
182: if (cachedDate != null) {
183: return cachedDate.longValue();
184: }
185:
186: Long date = null;
187:
188: if (threadLocalformats != null) {
189: date = internalParseDate(value, threadLocalformats);
190:
191: synchronized (parseCache) {
192: updateCache(parseCache, value, date);
193: }
194: } else {
195: synchronized (parseCache) {
196: date = internalParseDate(value, formats);
197: updateCache(parseCache, value, date);
198: }
199: }
200:
201: if (date == null) {
202: return (-1L);
203: } else {
204: return date.longValue();
205: }
206: }
207:
208: /**
209: * Updates cache.
210: *
211: * @param cache Cache to be updated
212: * @param key Key to be updated
213: * @param value New value
214: */
215: private static void updateCache(HashMap cache, Object key,
216: Object value) {
217: if (value == null) {
218: return;
219: }
220:
221: if (cache.size() > 1000) {
222: cache.clear();
223: }
224:
225: cache.put(key, value);
226: }
227: }
|