View Javadoc

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 org.apache.commons.id.uuid;
18  
19  import org.apache.commons.discovery.tools.DiscoverSingleton;
20  import org.apache.commons.id.IdentifierGenerator;
21  import org.apache.commons.id.uuid.clock.OverClockedException;
22  import org.apache.commons.id.uuid.state.Node;
23  
24  /**
25   * Class is responsible for generating version 1 UUID's per RFC 4122.
26   * This class attempts to locate the machine's node identifier
27   * first by attempting to loading the properties file UUID.properties
28   * from the system classpath. If the UUID.properties file does not exist
29   * then the generator will create a node identifier from random information as
30   * defined in the
31   * <a href="ftp://ftp.rfc-editor.org/in-notes/rfc4122.txt">RFC 4122:
32   * A Universally Unique IDentifier (UUID) URN Namespace</a>.
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  
39  public final class VersionOneGenerator implements IdentifierGenerator, Constants {
40  
41      /** Positions 10-16: Length of node bytes */
42      private static final int NODE_ID_BYTE_LENGTH = 6;
43  
44      /** Position 8: CLOCK_SEQ_LOW byte */
45      private static final int CLOCK_HI_VARIANT_BYTE8 = 8;
46      /** Position 9: CLOCK_SEQ_HIGH and VARIANT byte */
47      private static final int CLOCK_LOW_BYTE9 = 9;
48      /** Positions 10-16: Start of node bytes */
49      private static final int NODE_ID_BYTE10 = 10;
50  
51      /** The default NodeManager implementation. */
52      private static final String DEFAULT_NODEMANAGER_IMPL = NodeManagerImpl.class.getName();
53  
54      /** The NodeManager implementation */
55      private NodeManager manager;
56  
57      /** Singleton instance such that only one instance is accessing the static
58       * fields at any time.
59       */
60      private static VersionOneGenerator generator;
61  
62      /**
63       *  <p>Private singleton constructor.</p>
64       */
65      private VersionOneGenerator() {
66          super();
67          manager = (NodeManager) DiscoverSingleton.find( NodeManager.class, DEFAULT_NODEMANAGER_IMPL);
68      }
69  
70      /**
71       * <p>Returns the singleton instance of the version one UUID generator.</p>
72       *
73       * @return the singleton instance of the version one UUID generator.
74       */
75      public static VersionOneGenerator getInstance()  {
76              if (generator == null) {
77                  generator = new VersionOneGenerator();
78              }
79              return generator;
80      }
81      
82      /**
83       * @see org.apache.commons.id.IdentifierGenerator#nextIdentifier()
84       */
85      public Object nextIdentifier() {
86          return nextUUID();
87      }
88  
89      /**
90       * <p>Returns a new version 1 UUID. The method acts upons static variables
91       * and so should be sychronized.</p>
92       *
93       * @return Returns a new version 1 UUID.
94       */
95      public synchronized UUID nextUUID() {
96          byte[] rawUUID = new byte[UUID_BYTE_LENGTH];
97          long time = 0;
98          short clockSq = 0;
99          Node node = manager.currentNode();
100         while (time < 1) {
101             try {
102                 manager.lockNode(node);
103                 time = node.getUUIDTime();
104                 clockSq = node.getClockSequence();
105                 System.arraycopy(node.getNodeIdentifier(), 0, rawUUID, NODE_ID_BYTE10, NODE_ID_BYTE_LENGTH);
106                 manager.releaseNode(node);
107             } catch (OverClockedException e) {
108                 node = manager.nextAvailableNode();
109             } finally {
110                 manager.releaseNode(node);
111             }
112         }
113         byte[] timeBytes = Bytes.toBytes(time);
114         //Copy time low
115         System.arraycopy(timeBytes, TIME_LOW_TS_POS, rawUUID, TIME_LOW_START_POS, TIME_LOW_BYTE_LEN);
116         //Copy time mid
117         System.arraycopy(timeBytes, TIME_MID_TS_POS, rawUUID, TIME_MID_START_POS, TIME_MID_BYTE_LEN);
118         //Copy time hi
119         System.arraycopy(timeBytes, TIME_HI_TS_POS, rawUUID, TIME_HI_START_POS, TIME_HI_BYTE_LEN);
120         //Set version
121         rawUUID[6] |= 0x10; // 0001 0000
122         //Set clock sequence
123         rawUUID[CLOCK_HI_VARIANT_BYTE8] = (byte) ((clockSq & 0x3F00) >>> 8);
124         rawUUID[CLOCK_HI_VARIANT_BYTE8] |= 0x80;
125         rawUUID[CLOCK_LOW_BYTE9] = (byte) (clockSq & 0xFF);
126 
127         return new UUID(rawUUID);
128     }
129 }