001/* 002 * Licensed under the Apache License, Version 2.0 (the "License"); 003 * you may not use this file except in compliance with the License. 004 * You may obtain a copy of the License at 005 * 006 * http://www.apache.org/licenses/LICENSE-2.0 007 * 008 * Unless required by applicable law or agreed to in writing, software 009 * distributed under the License is distributed on an "AS IS" BASIS, 010 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 011 * See the License for the specific language governing permissions and 012 * limitations under the License. 013 */ 014 015package org.basepom.mojo.propertyhelper.fields; 016 017import static com.google.common.base.Preconditions.checkNotNull; 018 019import org.basepom.mojo.propertyhelper.Field; 020import org.basepom.mojo.propertyhelper.FieldContext; 021import org.basepom.mojo.propertyhelper.ValueProvider; 022import org.basepom.mojo.propertyhelper.definitions.UuidDefinition; 023 024import java.util.Optional; 025import java.util.Random; 026import java.util.StringJoiner; 027import java.util.UUID; 028 029import com.google.common.annotations.VisibleForTesting; 030 031public final class UuidField extends Field<String, UuidDefinition> { 032 033 private final ValueProvider valueProvider; 034 private final Random secureRandom; 035 036 @VisibleForTesting 037 public static UuidField forTesting(UuidDefinition uuidDefinition, ValueProvider valueProvider) { 038 return new UuidField(uuidDefinition, valueProvider, FieldContext.forTesting()); 039 } 040 041 public UuidField(final UuidDefinition uuidDefinition, final ValueProvider valueProvider, 042 FieldContext fieldContext) { 043 super(uuidDefinition, fieldContext); 044 045 this.valueProvider = checkNotNull(valueProvider, "valueProvider is null"); 046 047 this.secureRandom = fieldContext.getRandom(); 048 } 049 050 @Override 051 public String getFieldName() { 052 return fieldDefinition.getId(); 053 } 054 055 @Override 056 public String getValue() { 057 final Optional<String> propValue = valueProvider.getValue(); 058 059 // Only add the value from the provider if it is not null. 060 UUID result = propValue.map(UUID::fromString) 061 .orElse(fieldDefinition.getValue() 062 .orElseGet(this::createRandomUUID)); 063 064 valueProvider.setValue(result.toString()); 065 return formatResult(result.toString()); 066 } 067 068 private UUID createRandomUUID() { 069 long upperValue = secureRandom.nextLong(); 070 long lowerValue = secureRandom.nextLong(); 071 072 // UUID v4 (random) - see https://datatracker.ietf.org/doc/html/rfc4122#section-4.4 073 lowerValue &= 0xff0fffffffffffffL; // clear top four bits of time_hi_and_version 074 lowerValue |= 0x0040000000000000L; // set to 0100 (UUID v4) 075 upperValue &= 0xffffffffffffff3fL; // clear top two bits of clock_seq_hi_and_reserved 076 upperValue |= 0x0000000000000080L; // set to 1 and 0 077 078 return new UUID(upperValue, lowerValue); 079 } 080 081 082 @Override 083 public String toString() { 084 return new StringJoiner(", ", UuidField.class.getSimpleName() + "[", "]") 085 .add("uuidDefinition=" + fieldDefinition) 086 .add("valueProvider=" + valueProvider) 087 .toString(); 088 } 089}