001 /*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License"). You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at
010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 * Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 * Copyright 2006-2008 Sun Microsystems, Inc.
026 */
027 package org.opends.server.util;
028
029
030
031 import java.text.SimpleDateFormat;
032 import java.util.Calendar;
033 import java.util.Date;
034 import java.util.GregorianCalendar;
035 import java.util.Iterator;
036 import java.util.TimeZone;
037 import java.util.concurrent.ConcurrentHashMap;
038 import java.util.concurrent.CopyOnWriteArrayList;
039
040 import org.opends.server.api.DirectoryThread;
041
042 import static org.opends.server.loggers.debug.DebugLogger.*;
043 import org.opends.server.loggers.debug.DebugTracer;
044 import org.opends.server.types.DebugLogLevel;
045 import static org.opends.server.util.ServerConstants.*;
046
047
048 /**
049 * This class defines a thread that will wake up periodically, get the current
050 * time, and store various representations of it. Note that only limited
051 * debugging will be performed in this class due to the frequency with which it
052 * will be called.
053 */
054 @org.opends.server.types.PublicAPI(
055 stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
056 mayInstantiate=false,
057 mayExtend=false,
058 mayInvoke=true)
059 public final class TimeThread
060 extends DirectoryThread
061 {
062 /**
063 * The tracer object for the debug logger.
064 */
065 private static final DebugTracer TRACER = getTracer();
066
067
068
069 /**
070 * The singleton instance for this time thread.
071 */
072 private static final TimeThread threadInstance = new TimeThread();
073
074
075
076 // The calendar holding the current time.
077 private static GregorianCalendar calendar;
078
079 // A set of arbitrary formatters that should be maintained by this time
080 // thread.
081 private static CopyOnWriteArrayList<SimpleDateFormat> userDefinedFormatters;
082
083 // A set of abitrary formatted times, mapped from format string to the
084 // corresponding formatted time representation.
085 private static ConcurrentHashMap<String,String> userDefinedTimeStrings;
086
087 // The date for this time thread.
088 private static Date date;
089
090 // The current time in HHmm form as an integer.
091 private static int hourAndMinute;
092
093 // The current time in milliseconds since the epoch.
094 private static volatile long time;
095
096 // The current time in nanoseconds.
097 private static volatile long nanoTime;
098
099 // The date formatter that will be used to obtain the generalized time.
100 private static SimpleDateFormat generalizedTimeFormatter;
101
102 // The date formatter that will be used to obtain the local timestamp.
103 private static SimpleDateFormat localTimestampFormatter;
104
105 // The date formatter that will be used to obtain the GMT timestamp.
106 private static SimpleDateFormat gmtTimestampFormatter;
107
108 // The timestamp for this time thread in the generalized time format.
109 private static String generalizedTime;
110
111 // The timestamp for this time thread in the local time zone.
112 private static String localTimestamp;
113
114 // The timestamp for this time thread in GMT.
115 private static String gmtTimestamp;
116
117
118
119 /**
120 * Creates a new instance of this time thread and starts it.
121 */
122 private TimeThread()
123 {
124 super("Time Thread");
125
126 setDaemon(true);
127
128 userDefinedFormatters = new CopyOnWriteArrayList<SimpleDateFormat>();
129 userDefinedTimeStrings = new ConcurrentHashMap<String,String>();
130
131 TimeZone utcTimeZone = TimeZone.getTimeZone(TIME_ZONE_UTC);
132
133 generalizedTimeFormatter =
134 new SimpleDateFormat(DATE_FORMAT_GENERALIZED_TIME);
135 generalizedTimeFormatter.setTimeZone(utcTimeZone);
136
137 gmtTimestampFormatter = new SimpleDateFormat(DATE_FORMAT_GMT_TIME);
138 gmtTimestampFormatter.setTimeZone(utcTimeZone);
139
140 localTimestampFormatter = new SimpleDateFormat(DATE_FORMAT_LOCAL_TIME);
141
142 calendar = new GregorianCalendar();
143 date = calendar.getTime();
144 time = date.getTime();
145 nanoTime = System.nanoTime();
146 generalizedTime = generalizedTimeFormatter.format(date);
147 localTimestamp = localTimestampFormatter.format(date);
148 gmtTimestamp = gmtTimestampFormatter.format(date);
149 hourAndMinute = (calendar.get(Calendar.HOUR_OF_DAY) * 100) +
150 calendar.get(Calendar.MINUTE);
151
152 start();
153 }
154
155
156
157 /**
158 * Operates in a loop, getting the current time and then sleeping briefly
159 * before checking again.
160 */
161 public void run()
162 {
163 while (true)
164 {
165 try
166 {
167 calendar = new GregorianCalendar();
168 date = calendar.getTime();
169 time = date.getTime();
170 nanoTime = System.nanoTime();
171 generalizedTime = generalizedTimeFormatter.format(date);
172 localTimestamp = localTimestampFormatter.format(date);
173 gmtTimestamp = gmtTimestampFormatter.format(date);
174 hourAndMinute = (calendar.get(Calendar.HOUR_OF_DAY) * 100) +
175 calendar.get(Calendar.MINUTE);
176
177 for (SimpleDateFormat format : userDefinedFormatters)
178 {
179 userDefinedTimeStrings.put(format.toPattern(),
180 format.format(date));
181 }
182
183 Thread.sleep(200);
184 }
185 catch (Exception e)
186 {
187 if (debugEnabled())
188 {
189 TRACER.debugCaught(DebugLogLevel.ERROR, e);
190 }
191 }
192 }
193 }
194
195
196
197 /**
198 * Retrieves a <CODE>Calendar</CODE> containing the time at the last update.
199 *
200 * @return A <CODE>Calendar</CODE> containing the time at the last update.
201 */
202 public static Calendar getCalendar()
203 {
204 return calendar;
205 }
206
207
208
209 /**
210 * Retrieves a <CODE>Date</CODE> containing the time at the last update.
211 *
212 * @return A <CODE>Date</CODE> containing the time at the last update.
213 */
214 public static Date getDate()
215 {
216 return date;
217 }
218
219
220
221 /**
222 * Retrieves the time in milliseconds since the epoch at the last update.
223 *
224 * @return The time in milliseconds since the epoch at the last update.
225 */
226 public static long getTime()
227 {
228 return time;
229 }
230
231 /**
232 * Retrieves the time in nanoseconds from the most precise available system
233 * timer. The value retured represents nanoseconds since some fixed but
234 * arbitrary time.
235 *
236 * @return The time in nanoseconds from some fixed but arbitrary time.
237 */
238 public static long getNanoTime()
239 {
240 return nanoTime;
241 }
242
243
244
245 /**
246 * Retrieves a string containing a normalized representation of the current
247 * time in a generalized time format. The timestamp will look like
248 * "20050101000000.000Z".
249 *
250 * @return A string containing a normalized representation of the current
251 * time in a generalized time format.
252 */
253 public static String getGeneralizedTime()
254 {
255 return generalizedTime;
256 }
257
258
259
260 /**
261 * Retrieves a string containing the current time in the local time zone. The
262 * timestamp format will look like "01/Jan/2005:00:00:00 -0600".
263 *
264 * @return A string containing the current time in the local time zone.
265 */
266 public static String getLocalTime()
267 {
268 return localTimestamp;
269 }
270
271
272
273 /**
274 * Retrieves a string containing the current time in GMT. The timestamp will
275 * look like "20050101000000Z".
276 *
277 * @return A string containing the current time in GMT.
278 */
279 public static String getGMTTime()
280 {
281 return gmtTimestamp;
282 }
283
284
285
286 /**
287 * Retrieves an integer containing the time in HHmm format at the last
288 * update. It will be calculated as "(hourOfDay*100) + minuteOfHour".
289 *
290 * @return An integer containing the time in HHmm format at the last update.
291 */
292 public static int getHourAndMinute()
293 {
294 return hourAndMinute;
295 }
296
297
298
299 /**
300 * Retrieves the current time formatted using the given format string. The
301 * first time this method is used with a given format string, it will be used
302 * to create a formatter that will generate the time string. That formatter
303 * will then be put into a list so that it will be maintained automatically
304 * for future use.
305 *
306 * @param formatString The string that defines the format of the time string
307 * to retrieve.
308 *
309 * @return The formatted time string.
310 *
311 * @throws IllegalArgumentException If the provided format string is
312 * invalid.
313 */
314 public static String getUserDefinedTime(String formatString)
315 throws IllegalArgumentException
316 {
317 String timeString = userDefinedTimeStrings.get(formatString);
318
319 if (timeString == null)
320 {
321 SimpleDateFormat formatter = new SimpleDateFormat(formatString);
322 timeString = formatter.format(date);
323 userDefinedTimeStrings.put(formatString, timeString);
324 userDefinedFormatters.add(formatter);
325 }
326
327 return timeString;
328 }
329
330
331
332 /**
333 * Removes the user-defined time formatter from this time thread so that it
334 * will no longer be maintained. This is a safe operation because if the
335 * same format string is used for multiple purposes then it will be added back
336 * the next time a time is requested with the given format.
337 *
338 * @param formatString The format string for the date formatter to remove.
339 */
340 public static void removeUserDefinedFormatter(String formatString)
341 {
342 Iterator<SimpleDateFormat> iterator = userDefinedFormatters.iterator();
343 while (iterator.hasNext())
344 {
345 SimpleDateFormat format = iterator.next();
346 if (format.toPattern().equals(formatString))
347 {
348 iterator.remove();
349 }
350 }
351
352 userDefinedTimeStrings.remove(formatString);
353 }
354 }
355