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