001: /*
002: * Copyright 1999-2004 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 org.apache.tomcat.util.http;
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: * Utility class to generate HTTP dates.
029: *
030: * @author Remy Maucherat
031: */
032: public final class FastHttpDateFormat {
033:
034: // -------------------------------------------------------------- Variables
035:
036: /**
037: * HTTP date format.
038: */
039: protected static final SimpleDateFormat format = new SimpleDateFormat(
040: "EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
041:
042: /**
043: * The set of SimpleDateFormat formats to use in getDateHeader().
044: */
045: protected static final SimpleDateFormat formats[] = {
046: new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz",
047: Locale.US),
048: new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz",
049: Locale.US),
050: new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US) };
051:
052: protected final static TimeZone gmtZone = TimeZone
053: .getTimeZone("GMT");
054:
055: /**
056: * GMT timezone - all HTTP dates are on GMT
057: */
058: static {
059:
060: format.setTimeZone(gmtZone);
061:
062: formats[0].setTimeZone(gmtZone);
063: formats[1].setTimeZone(gmtZone);
064: formats[2].setTimeZone(gmtZone);
065:
066: }
067:
068: /**
069: * Instant on which the currentDate object was generated.
070: */
071: protected static long currentDateGenerated = 0L;
072:
073: /**
074: * Current formatted date.
075: */
076: protected static String currentDate = null;
077:
078: /**
079: * Formatter cache.
080: */
081: protected static final HashMap formatCache = new HashMap();
082:
083: /**
084: * Parser cache.
085: */
086: protected static final HashMap parseCache = new HashMap();
087:
088: // --------------------------------------------------------- Public Methods
089:
090: /**
091: * Get the current date in HTTP format.
092: */
093: public static final String getCurrentDate() {
094:
095: long now = System.currentTimeMillis();
096: if ((now - currentDateGenerated) > 1000) {
097: synchronized (format) {
098: if ((now - currentDateGenerated) > 1000) {
099: currentDateGenerated = now;
100: currentDate = format.format(new Date(now));
101: }
102: }
103: }
104: return currentDate;
105:
106: }
107:
108: /**
109: * Get the HTTP format of the specified date.
110: */
111: public static final String formatDate(long value,
112: DateFormat threadLocalformat) {
113:
114: String cachedDate = null;
115: Long longValue = new Long(value);
116: try {
117: cachedDate = (String) formatCache.get(longValue);
118: } catch (Exception e) {
119: }
120: if (cachedDate != null)
121: return cachedDate;
122:
123: String newDate = null;
124: Date dateValue = new Date(value);
125: if (threadLocalformat != null) {
126: newDate = threadLocalformat.format(dateValue);
127: synchronized (formatCache) {
128: updateCache(formatCache, longValue, newDate);
129: }
130: } else {
131: synchronized (formatCache) {
132: newDate = format.format(dateValue);
133: updateCache(formatCache, longValue, newDate);
134: }
135: }
136: return newDate;
137:
138: }
139:
140: /**
141: * Try to parse the given date as a HTTP date.
142: */
143: public static final long parseDate(String value,
144: DateFormat[] threadLocalformats) {
145:
146: Long cachedDate = null;
147: try {
148: cachedDate = (Long) parseCache.get(value);
149: } catch (Exception e) {
150: }
151: if (cachedDate != null)
152: return cachedDate.longValue();
153:
154: Long date = null;
155: if (threadLocalformats != null) {
156: date = internalParseDate(value, threadLocalformats);
157: synchronized (parseCache) {
158: updateCache(parseCache, value, date);
159: }
160: } else {
161: synchronized (parseCache) {
162: date = internalParseDate(value, formats);
163: updateCache(parseCache, value, date);
164: }
165: }
166: if (date == null) {
167: return (-1L);
168: } else {
169: return date.longValue();
170: }
171:
172: }
173:
174: /**
175: * Parse date with given formatters.
176: */
177: private static final Long internalParseDate(String value,
178: DateFormat[] formats) {
179: Date date = null;
180: for (int i = 0; (date == null) && (i < formats.length); i++) {
181: try {
182: date = formats[i].parse(value);
183: } catch (ParseException e) {
184: ;
185: }
186: }
187: if (date == null) {
188: return null;
189: }
190: return new Long(date.getTime());
191: }
192:
193: /**
194: * Update cache.
195: */
196: private static final void updateCache(HashMap cache, Object key,
197: Object value) {
198: if (value == null) {
199: return;
200: }
201: if (cache.size() > 1000) {
202: cache.clear();
203: }
204: cache.put(key, value);
205: }
206:
207: }
|