Throw any exceptions thrown unwrapped. This way, the caller knows what it's dealing...
[pithos] / src / gr / ebs / gss / server / webdav / FastHttpDateFormat.java
1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */
17 package gr.ebs.gss.server.webdav;
18
19 import java.text.DateFormat;
20 import java.text.ParseException;
21 import java.text.SimpleDateFormat;
22 import java.util.Date;
23 import java.util.Locale;
24 import java.util.TimeZone;
25 import java.util.concurrent.ConcurrentHashMap;
26
27 /**
28  * Utility class to generate HTTP dates.
29  *
30  * @author Remy Maucherat
31  */
32 public final class FastHttpDateFormat {
33
34
35     // -------------------------------------------------------------- Variables
36
37
38     /**
39      *
40      */
41     protected static final int CACHE_SIZE =
42         Integer.parseInt(System.getProperty("org.apache.tomcat.util.http.FastHttpDateFormat.CACHE_SIZE", "1000"));
43
44
45     /**
46      * HTTP date format.
47      */
48     protected static final SimpleDateFormat format =
49         new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
50
51
52     /**
53      * The set of SimpleDateFormat formats to use in getDateHeader().
54      */
55     protected static final SimpleDateFormat formats[] = {
56         new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
57         new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
58         new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US)
59     };
60
61
62     /**
63      *
64      */
65     protected final static TimeZone gmtZone = TimeZone.getTimeZone("GMT");
66
67
68     /**
69      * GMT timezone - all HTTP dates are on GMT
70      */
71     static {
72
73         format.setTimeZone(gmtZone);
74
75         formats[0].setTimeZone(gmtZone);
76         formats[1].setTimeZone(gmtZone);
77         formats[2].setTimeZone(gmtZone);
78
79     }
80
81
82     /**
83      * Instant on which the currentDate object was generated.
84      */
85     protected static long currentDateGenerated = 0L;
86
87
88     /**
89      * Current formatted date.
90      */
91     protected static String currentDate = null;
92
93
94     /**
95      * Formatter cache.
96      */
97     protected static final ConcurrentHashMap<Long, String> formatCache =
98         new ConcurrentHashMap<Long, String>(CACHE_SIZE);
99
100
101     /**
102      * Parser cache.
103      */
104     protected static final ConcurrentHashMap<String, Long> parseCache =
105         new ConcurrentHashMap<String, Long>(CACHE_SIZE);
106
107
108     // --------------------------------------------------------- Public Methods
109
110
111     /**
112      * Get the current date in HTTP format.
113      * @return the formatted date
114      */
115     public static final String getCurrentDate() {
116
117         long now = System.currentTimeMillis();
118         if (now - currentDateGenerated > 1000)
119                         synchronized (format) {
120                 if (now - currentDateGenerated > 1000) {
121                     currentDateGenerated = now;
122                     currentDate = format.format(new Date(now));
123                 }
124             }
125         return currentDate;
126
127     }
128
129
130     /**
131      * Get the HTTP format of the specified date.
132      * @param value
133      * @param threadLocalformat
134      * @return the formatted date
135      */
136     public static final String formatDate
137         (long value, DateFormat threadLocalformat) {
138
139         Long longValue = new Long(value);
140         String cachedDate = formatCache.get(longValue);
141         if (cachedDate != null)
142             return cachedDate;
143
144         String newDate = null;
145         Date dateValue = new Date(value);
146         if (threadLocalformat != null) {
147             newDate = threadLocalformat.format(dateValue);
148             updateFormatCache(longValue, newDate);
149         } else
150                         synchronized (formatCache) {
151                 synchronized (format) {
152                     newDate = format.format(dateValue);
153                 }
154                 updateFormatCache(longValue, newDate);
155             }
156         return newDate;
157
158     }
159
160
161     /**
162      * Try to parse the given date as a HTTP date.
163      * @param value
164      * @param threadLocalformats
165      * @return the date value
166      */
167     public static final long parseDate(String value,
168                                        DateFormat[] threadLocalformats) {
169
170         Long cachedDate = parseCache.get(value);
171         if (cachedDate != null)
172             return cachedDate.longValue();
173
174         Long date = null;
175         if (threadLocalformats != null) {
176             date = internalParseDate(value, threadLocalformats);
177             updateParseCache(value, date);
178         } else
179                         synchronized (parseCache) {
180                 date = internalParseDate(value, formats);
181                 updateParseCache(value, date);
182             }
183         if (date == null)
184                         return -1L;
185                 return date.longValue();
186
187     }
188
189
190     /**
191      * Parse date with given formatters.
192      * @param value
193      * @param theFormats
194      * @return the date value
195      */
196     private static final Long internalParseDate
197         (String value, DateFormat[] theFormats) {
198         Date date = null;
199         for (int i = 0; date == null && i < theFormats.length; i++)
200                         try {
201                 date = theFormats[i].parse(value);
202             } catch (ParseException e) {
203                 // Do nothing.
204             }
205         if (date == null)
206                         return null;
207         return new Long(date.getTime());
208     }
209
210
211     /**
212      * Update cache.
213      * @param key
214      * @param value
215      */
216     private static void updateFormatCache(Long key, String value) {
217         if (value == null)
218                         return;
219         if (formatCache.size() > CACHE_SIZE)
220                         formatCache.clear();
221         formatCache.put(key, value);
222     }
223
224
225     /**
226      * Update cache.
227      * @param key
228      * @param value
229      */
230     private static void updateParseCache(String key, Long value) {
231         if (value == null)
232                         return;
233         if (parseCache.size() > CACHE_SIZE)
234                         parseCache.clear();
235         parseCache.put(key, value);
236     }
237
238
239 }