Coverage Report - org.apache.commons.id.uuid.clock.ThreadClockImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
ThreadClockImpl
84%
43/51
72%
13/18
2
 
 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  
 
 18  
 package org.apache.commons.id.uuid.clock;
 19  
 
 20  
 
 21  
 /**
 22  
  * <p>{@link Clock} provides a timing mechanism for returning the current time in
 23  
  * 100-nano second intervals since 00:00:00.00, 15 October 1582.</p>
 24  
  *
 25  
  * <p>This Class consumes a single thread which will die off if not utilized before
 26  
  * the expiration. Subsequent calls after a thread expires start a new thread.
 27  
  * Compensates for jvm time resolution issues. This clock should be used in
 28  
  * instances where the system resolution does not perform adequately - the
 29  
  * clocking resolution on some windows virtual machines can range from 10 to 50
 30  
  * milliseconds before the System.currentTimeMillis changes. In instances where
 31  
  * 10,000 or more uuid's may be generated in a millisecond this Clock
 32  
  * implementation may be required.</p>
 33  
  *
 34  
  * @author Commons-Id Team
 35  
  * @version $Revision: 480488 $ $Date: 2006-11-29 08:57:26 +0000 (Wed, 29 Nov 2006) $
 36  
  */
 37  
 
 38  
 public final class ThreadClockImpl extends Thread implements Clock {
 39  
 
 40  
     /** Default time to live of the Clock thread in milliseconds */
 41  
     public static final long DEFAULT_THREAD_LIFE = 200;
 42  
 
 43  
     /** Life time of the clock thread in milliseconds */
 44  1
     private static long threadLife = DEFAULT_THREAD_LIFE;
 45  
 
 46  
     /** Singleton instance of the Clock thread*/
 47  1
     private static ThreadClockImpl worker = null;
 48  
 
 49  
     /** The current time in milliseconds held in this clock thread. */
 50  
     private static long currentTimeMillis;
 51  
 
 52  
     /** Time when the clock thread should die */
 53  1
     private static long expires = threadLife;
 54  
 
 55  
     //---------------- Instance members ---------------------
 56  
     /** The time in time milliseconds used in this instance */
 57  24
     private long lastTimeMs = 0;
 58  
 
 59  
     /** The counter for nanoseconds generated during this system interval(ms) */
 60  
     private int generatedThisInterval;
 61  
 
 62  
     /** The system time interval to increment the clock */
 63  1
     private static short sysInterval = 1;
 64  
     // See bug parade 4814012, 4500388
 65  
     static {
 66  1
         if (System.getProperty("os.name").indexOf("Windows") != -1) {
 67  1
             sysInterval = 10;
 68  
         }
 69  1
     }
 70  
 
 71  
     /**
 72  
      * <p>Public constructor to instantiate a Clock instance.</p>
 73  
      */
 74  23
     public ThreadClockImpl() {
 75  23
         if (worker == null) {
 76  3
             synchronized (ThreadClockImpl.class) {
 77  1
                 worker = new ThreadClockImpl(true);
 78  1
             }
 79  
         }
 80  23
     }
 81  
 
 82  
     /**
 83  
      * Private constructor for clock implementation. Utilizes a single thread to
 84  
      * increment the clock every milli seconds this should be more
 85  
      * accurate than System.currentTimeMillis() as described in
 86  
      * the javaworld article:
 87  
      * http://www.javaworld.com/javaworld/javaqa/2003-01/01-qa-0110-timing.html
 88  
      *
 89  
      * @param isWorkerThread boolean indicating this is the worker thread.
 90  
      */
 91  1
     private ThreadClockImpl(boolean isWorkerThread) {
 92  1
         setDaemon(true);
 93  1
         setPriority(Thread.MAX_PRIORITY);
 94  1
         currentTimeMillis = System.currentTimeMillis();
 95  1
         generatedThisInterval = 0;
 96  1
         start();
 97  1
     }
 98  
 
 99  
     /**
 100  
      * Returns the thread life in milliseconds. If the clock thread is not
 101  
      * accessed within this time span the thread will die off.
 102  
      *
 103  
      * @return thread life time span in milliseconds
 104  
      */
 105  
     public static long getThreadLife() {
 106  0
         return ThreadClockImpl.threadLife;
 107  
     }
 108  
 
 109  
     /**
 110  
      * @param threadLifeLen milliseconds this thread should live for. Each
 111  
      * call to getCurrentTime resets the expiration time value.
 112  
      */
 113  
     public static void setThreadLife(long threadLifeLen) {
 114  0
         ThreadClockImpl.threadLife = threadLifeLen;
 115  0
     }
 116  
 
 117  
     /**
 118  
      * Threads run method that increments the clock and resets the generated
 119  
      * nano seconds counter.
 120  
      */
 121  
     public void run() {
 122  
         try {
 123  201
             while (--expires >= 0) {
 124  200
                 sleep(sysInterval);
 125  200
                 synchronized (ThreadClockImpl.class) {
 126  200
                     currentTimeMillis += sysInterval;
 127  200
                 }
 128  200
             }
 129  0
         } catch (InterruptedException e) {
 130  0
             System.out.println("Clock thread interrupted");
 131  1
         }
 132  1
     }
 133  
 
 134  
     /**
 135  
      * Returns the current time as described in the clock resolution and
 136  
      * timestamp sections of the uuid specification.
 137  
      *
 138  
      * @return the current time in 100-nano second intervals (simulated)
 139  
      * @throws  OverClockedException an exception when the number of timestamps
 140  
      *          generated exceeds the allowable timestamps for the system time
 141  
      *          interval.
 142  
      */
 143  
     private synchronized long getTimeSynchronized()
 144  
             throws OverClockedException {
 145  3
         long current = 0;
 146  3
         synchronized (ThreadClockImpl.class) {
 147  3
             current = currentTimeMillis;
 148  3
         }
 149  3
         if (current != lastTimeMs) {
 150  3
             generatedThisInterval = 0;
 151  3
             lastTimeMs = current;
 152  
         }
 153  3
         if (generatedThisInterval + 1 >= (INTERVALS_PER_MILLI * sysInterval)) {
 154  0
             throw new OverClockedException();
 155  
         }
 156  3
         return ((current + GREGORIAN_CHANGE_OFFSET) * INTERVALS_PER_MILLI)
 157  
                 + generatedThisInterval++;
 158  
       }
 159  
 
 160  
     /**
 161  
      * Method returns the clocks current time in 100-nanosecond intervals
 162  
      * since the Gregorian calander change. Calendar.GREGORIAN_OFFSET
 163  
      *
 164  
      * @return  Coordinated Universal Time (UTC) as a count of 100- nanosecond
 165  
      *          intervals since 00:00:00.00, 15 October 1582.
 166  
      * @throws  OverClockedException an exception when the number of timestamps
 167  
      *          generated exceeds the allowable timestamps for the system time
 168  
      *          interval.
 169  
      */
 170  
     public long getUUIDTime() throws OverClockedException {
 171  11
             if (!worker.isAlive()) {
 172  8
                 synchronized (SystemClockImpl.class) {
 173  8
                     currentTimeMillis = System.currentTimeMillis();
 174  8
                     worker.start();
 175  0
                 }
 176  0
                 generatedThisInterval = 0;
 177  
             }
 178  3
         return getTimeSynchronized();
 179  
     }
 180  
 }