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.id.IdentifierGenerator;
20  
21  import java.security.NoSuchAlgorithmException;
22  import java.security.NoSuchProviderException;
23  import java.security.SecureRandom;
24  import java.util.Random;
25  
26  /**
27   * <p>Class is responsible for generating version 4 UUID's per RFC 4122.
28   * This class attempts to use a java.security.SecureRandom with
29   * the following instantiation
30   * <code>SecureRandom.getInstance("SHA1PRNG", "SUN")</code>. If neither secure
31   * random implementation is avialable or an Exception is raised a java.util.Random
32   * is used.</p>
33   * <p>Note: Instantiation of SecureRandom is an expensive operation. The
34   * constructor therefore creates a static member to hold the SecureRandom.
35   * The first call to getInstance may take time; subsequent calls should return
36   * quickly.</p>
37   *
38   * @author Commons-Id team
39   * @version $Revision: 480488 $ $Date: 2006-11-29 08:57:26 +0000 (Wed, 29 Nov 2006) $
40   *
41   */
42  public final class VersionFourGenerator implements IdentifierGenerator, Constants {
43  
44          /** Random used to generate UUID's */
45          private static final Random regularRandom = new Random();
46  
47          /** SecureRandom used to generate UUID's */
48          private static Random secureRandom;
49  
50          /** The pseudo-random number generator to use */
51          private static String usePRNG = "SHA1PRNG";
52  
53          /** The pseudo-random number generator package name to use */
54          private static String usePRNGPackage = "SUN";
55          
56          private static VersionFourGenerator generator;
57  
58          /**
59           * <p>Constructs a new VersionFourGenerator.</p>
60           */
61          public VersionFourGenerator() {
62              super();
63          }
64  
65          /**
66           * <p>Returns a singleton instance of the version four UUID generator.</p>
67           *
68           * @return the singleton instance of the version four UUID generator.
69           */
70          public static VersionFourGenerator getInstance() {
71                  if (generator == null) {
72                      generator = new VersionFourGenerator();
73                  }
74                  return generator;
75          }
76  
77          /**
78           * <p>Returns a new version four UUID.</p>
79           *
80           * @return Object a new version 4 UUID.
81           */
82          public Object nextIdentifier() {
83              return nextUUID(false);
84          }
85  
86          /**
87           * <p>Returns a new version four UUID.</p>
88           * <p>This overloaded method may produce both UUID's using a <code>SecureRandom</code> as well as using normal
89           * <code>Random</code>
90           * </p>
91           *
92           * @param secure indicates whether or not to use <code>SecureRandom</code> in generating the random bits.
93           * @return a new version four UUID that was generated by either a <code>Random</code> or <code>SecureRandom</code>.
94           */
95          public Object nextIdentifier(boolean secure)  {
96              return nextUUID(secure);
97          }
98  
99          /**
100         * <p>Returns a new version four UUID.</p>
101         *
102         * @return Object a new version 4 UUID.
103         */
104         public UUID nextUUID() {
105             //Call nextUUID with secure = false
106             return nextUUID(false);
107         }
108 
109         /**
110          * <p>Returns a new version four UUID using either <code>SecureRandom</code> or <code>Random</code>.</p>
111          *
112          * @param secure boolean flag indicating whether to use <code>SecureRandom</code> or <code>Random</code>.
113          * @return a new version four UUID using either <code>SecureRandom</code> or <code>Random</code>.
114          */
115         private UUID nextUUID(boolean secure) {
116             byte[] raw = new byte[UUID_BYTE_LENGTH];
117             if (secure) {
118                 //Initialize the secure random if null.
119                 if (secureRandom == null) {
120                     try {
121                         if (usePRNGPackage != null) {
122                             secureRandom = SecureRandom.getInstance(usePRNG, usePRNGPackage);
123                         } else {
124                             secureRandom = SecureRandom.getInstance(usePRNG);
125                         }
126                     } catch (NoSuchAlgorithmException nsae) {
127                         secure = false; //Fail back to default PRNG/Random
128                     } catch (NoSuchProviderException nspe) {
129                         secure = false; //Fail back to default PRNG/Random
130                     }
131                 }
132                 if (secureRandom != null) { 
133                     secureRandom.nextBytes(raw); 
134                 }                
135             } else {
136                 regularRandom.nextBytes(raw);
137             }
138 
139             raw[TIME_HI_AND_VERSION_BYTE_6] &= 0x0F;
140             raw[TIME_HI_AND_VERSION_BYTE_6] |= (UUID.VERSION_FOUR << 4);
141 
142             raw[CLOCK_SEQ_HI_AND_RESERVED_BYTE_8] &= 0x3F; //0011 1111
143             raw[CLOCK_SEQ_HI_AND_RESERVED_BYTE_8] |= 0x80; //1000 0000
144 
145             return new UUID(raw);
146         }
147 
148        /**
149         * <p>Allows clients to set the pseudo-random number generator implementation used when generating a version four uuid with
150         * the secure option. The secure option uses a <code>SecureRandom</code>. The packageName string may be null to specify
151         * no preferred package.</p>
152         *
153         * @param prngName the pseudo-random number generator implementation name. For example "SHA1PRNG".
154         * @param packageName the package name for the PRNG provider. For example "SUN".
155         */
156        public static void setPRNGProvider(String prngName, String packageName) {
157            VersionFourGenerator.usePRNG = prngName;
158            VersionFourGenerator.usePRNGPackage = packageName;
159            VersionFourGenerator.secureRandom = null;
160        }
161     }