View Javadoc
1   /*
2    * Licensed under the Apache License, Version 2.0 (the "License");
3    * you may not use this file except in compliance with the License.
4    * You may obtain a copy of the License at
5    *
6    * http://www.apache.org/licenses/LICENSE-2.0
7    *
8    * Unless required by applicable law or agreed to in writing, software
9    * distributed under the License is distributed on an "AS IS" BASIS,
10   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11   * See the License for the specific language governing permissions and
12   * limitations under the License.
13   */
14  
15  package org.basepom.mojo.propertyhelper.fields;
16  
17  import static com.google.common.base.Preconditions.checkNotNull;
18  
19  import org.basepom.mojo.propertyhelper.Field;
20  import org.basepom.mojo.propertyhelper.FieldContext;
21  import org.basepom.mojo.propertyhelper.ValueProvider;
22  import org.basepom.mojo.propertyhelper.definitions.UuidDefinition;
23  
24  import java.util.Optional;
25  import java.util.Random;
26  import java.util.StringJoiner;
27  import java.util.UUID;
28  
29  import com.google.common.annotations.VisibleForTesting;
30  
31  public final class UuidField extends Field<String, UuidDefinition> {
32  
33      private final ValueProvider valueProvider;
34      private final Random secureRandom;
35  
36      @VisibleForTesting
37      public static UuidField forTesting(UuidDefinition uuidDefinition, ValueProvider valueProvider) {
38          return new UuidField(uuidDefinition, valueProvider, FieldContext.forTesting());
39      }
40  
41      public UuidField(final UuidDefinition uuidDefinition, final ValueProvider valueProvider,
42          FieldContext fieldContext) {
43          super(uuidDefinition, fieldContext);
44  
45          this.valueProvider = checkNotNull(valueProvider, "valueProvider is null");
46  
47          this.secureRandom = fieldContext.getRandom();
48      }
49  
50      @Override
51      public String getFieldName() {
52          return fieldDefinition.getId();
53      }
54  
55      @Override
56      public String getValue() {
57          final Optional<String> propValue = valueProvider.getValue();
58  
59          // Only add the value from the provider if it is not null.
60          UUID result = propValue.map(UUID::fromString)
61              .orElse(fieldDefinition.getValue()
62                  .orElseGet(this::createRandomUUID));
63  
64          valueProvider.setValue(result.toString());
65          return formatResult(result.toString());
66      }
67  
68      private UUID createRandomUUID() {
69          long upperValue = secureRandom.nextLong();
70          long lowerValue = secureRandom.nextLong();
71  
72          // UUID v4 (random) - see https://datatracker.ietf.org/doc/html/rfc4122#section-4.4
73          lowerValue &= 0xff0fffffffffffffL; // clear top four bits of time_hi_and_version
74          lowerValue |= 0x0040000000000000L; // set to 0100 (UUID v4)
75          upperValue &= 0xffffffffffffff3fL; // clear top two bits of clock_seq_hi_and_reserved
76          upperValue |= 0x0000000000000080L; // set to 1 and 0
77  
78          return new UUID(upperValue, lowerValue);
79      }
80  
81  
82      @Override
83      public String toString() {
84          return new StringJoiner(", ", UuidField.class.getSimpleName() + "[", "]")
85              .add("uuidDefinition=" + fieldDefinition)
86              .add("valueProvider=" + valueProvider)
87              .toString();
88      }
89  }