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