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