Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
"iterations" : 4,
"threads" : 1,
"forks" : 3,
"mean_ops" : 823635.7718335792
"mean_ops" : 824615.1373750888
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
"iterations" : 4,
"threads" : 1,
"forks" : 3,
"mean_ops" : 655010.8023043653
"mean_ops" : 668869.350006137
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
@ToString
public class Id {
private String id;
private String prefix;
private String suffix;
private Date generatedDate;
private int node;
private int exponent;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ public Base36IdFormatter(IdFormatter idFormatter) {
this.idFormatter = idFormatter;
}

@Override
public IdParserType getType() {
throw new UnsupportedOperationException();
}

@Override
public String format(final DateTime dateTime,
final int nodeId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ public class DefaultIdFormatter implements IdFormatter {
private static final Pattern PATTERN = Pattern.compile("(.*)([0-9]{15})([0-9]{4})([0-9]{3})");
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormat.forPattern("yyMMddHHmmssSSS");

@Override
public IdParserType getType() {
return IdParserType.DEFAULT;
}

@Override
public String format(final DateTime dateTime,
final int nodeId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

public interface IdFormatter {

IdParserType getType();

String format(final DateTime dateTime,
final int nodeId,
final int randomNonce);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class IdFormatters {

private static final IdFormatter originalIdFormatter = new DefaultIdFormatter();
private static final IdFormatter base36IdFormatter = new Base36IdFormatter(originalIdFormatter);
private static final IdFormatter suffixIdFormatter = new SuffixIdFormatter();

public static IdFormatter original() {
return originalIdFormatter;
Expand All @@ -31,4 +32,8 @@ public static IdFormatter base36() {
return base36IdFormatter;
}

public static IdFormatter suffix() {
return suffixIdFormatter;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package io.appform.ranger.discovery.bundle.id.formatter;

import lombok.Getter;

@Getter
public enum IdParserType {
DEFAULT (0),
SUFFIX (11);
Comment on lines +7 to +8
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@r0goyal To maintain consistency, shouldnt it be DEFAULT(00), SUFFIX(01) ?


private final int value;

IdParserType(final int value) {
this.value = value;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,21 @@
import lombok.extern.slf4j.Slf4j;
import lombok.val;

import java.util.Map;
import java.util.Optional;
import java.util.regex.Pattern;


@Slf4j
@UtilityClass
public class IdParsers {
private static final int MINIMUM_ID_LENGTH = 22;
private static final Pattern PATTERN = Pattern.compile("(.*)([0-9]{22})");
private static final Pattern PATTERN = Pattern.compile("([A-Za-z]*)([0-9]{22})([0-9]{2})?(.*)");

private final Map<Integer, IdFormatter> parserRegistry = Map.of(
IdFormatters.original().getType().getValue(), IdFormatters.original(),
IdFormatters.suffix().getType().getValue(), IdFormatters.suffix()
);

/**
* Parse the given string to get ID
Expand All @@ -44,7 +51,18 @@ public Optional<Id> parse(final String idString) {
if (!matcher.find()) {
return Optional.empty();
}
return IdFormatters.original().parse(idString);

val parserType = matcher.group(3);
if (parserType == null) {
return IdFormatters.original().parse(idString);
}

val parser = parserRegistry.get(Integer.parseInt(matcher.group(3)));
if (parser == null) {
log.warn("Could not parse idString {}, Invalid formatter type {}", idString, parserType);
return Optional.empty();
}
return parser.parse(idString);
} catch (Exception e) {
log.warn("Could not parse idString {}", e.getMessage());
return Optional.empty();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright 2024 Authors, Flipkart Internet Pvt. Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.appform.ranger.discovery.bundle.id.formatter;

import io.appform.ranger.discovery.bundle.id.Id;
import lombok.val;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

import java.util.Optional;
import java.util.regex.Pattern;

public class SuffixIdFormatter implements IdFormatter {
private static final Pattern PATTERN = Pattern.compile("([A-Za-z]*)([0-9]{15})([0-9]{4})([0-9]{3})([0-9]{2})([0-9]*)");
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormat.forPattern("yyMMddHHmmssSSS");

@Override
public IdParserType getType() {
return IdParserType.SUFFIX;
}

@Override
public String format(final DateTime dateTime,
final int nodeId,
final int randomNonce) {
return String.format("%s%04d%03d%02d", DATE_TIME_FORMATTER.print(dateTime), nodeId, randomNonce, getType().getValue());
}

@Override
public Optional<Id> parse(final String idString) {
val matcher = PATTERN.matcher(idString);
if (!matcher.find()) {
return Optional.empty();
}
return Optional.of(Id.builder()
.id(idString)
.prefix(matcher.group(1))
.suffix(matcher.group(6))
.node(Integer.parseInt(matcher.group(3)))
.exponent(Integer.parseInt(matcher.group(4)))
.generatedDate(DATE_TIME_FORMATTER.parseDateTime(matcher.group(2)).toDate())
.build());
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
package io.appform.ranger.discovery.bundle.id.generator;

import io.appform.ranger.discovery.bundle.id.formatter.IdFormatter;
import io.appform.ranger.discovery.bundle.id.formatter.IdFormatters;
import io.appform.ranger.discovery.bundle.id.nonce.NonceGenerator;
import io.appform.ranger.discovery.bundle.id.nonce.RandomNonceGenerator;

public class DefaultIdGenerator extends IdGeneratorBase {

public DefaultIdGenerator() {
super(IdFormatters.original(), new RandomNonceGenerator());
}

public DefaultIdGenerator(final IdFormatter idFormatter) {
super(idFormatter, new RandomNonceGenerator());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,25 @@ public final Id getIdFromIdInfo(final NonceInfo nonceInfo, final String namespac
.build();
}

public final Id getIdFromIdInfo(final NonceInfo nonceInfo, final String namespace, final String suffix, final IdFormatter idFormatter) {
val dateTime = new DateTime(nonceInfo.getTime());
val id = String.format("%s%s%s", namespace, idFormatter.format(dateTime, getNodeId(), nonceInfo.getExponent()), suffix != null ? suffix : "");
return Id.builder()
.id(id)
.exponent(nonceInfo.getExponent())
.generatedDate(dateTime.toDate())
.node(getNodeId())
.build();
}

public final Id getIdFromIdInfo(final NonceInfo nonceInfo, final String namespace) {
return getIdFromIdInfo(nonceInfo, namespace, idFormatter);
}

public final Id getIdFromIdInfo(final NonceInfo nonceInfo, final String namespace, final String suffix) {
return getIdFromIdInfo(nonceInfo, namespace, suffix, idFormatter);
}

public final IdValidationState validateId(final List<IdValidationConstraint> inConstraints, final Id id, final boolean skipGlobal) {
// First evaluate global constraints
val failedGlobalConstraint
Expand Down Expand Up @@ -139,6 +154,10 @@ public final Id generate(final String namespace) {
return getIdFromIdInfo(idInfo, namespace);
}

public final Id generate(final String namespace, final String suffix) {
val idInfo = nonceGenerator.generate(namespace);
return getIdFromIdInfo(idInfo, namespace, suffix);
}

public final Id generate(final String namespace, final IdFormatter idFormatter) {
val idInfo = nonceGenerator.generate(namespace);
Expand Down Expand Up @@ -167,16 +186,29 @@ public final Optional<Id> generateWithConstraints(final String namespace, final
return generateWithConstraints(request);
}

public Optional<Id> generateWithConstraints(
String namespace,
String suffix,
final List<IdValidationConstraint> inConstraints) {
return generateWithConstraints(IdGenerationRequest.builder()
.prefix(namespace)
.constraints(inConstraints)
.skipGlobal(false)
.idFormatter(idFormatter)
.build());
}

public final Optional<Id> generateWithConstraints(final IdGenerationRequest request) {
val domain = request.getDomain() != null ? registeredDomains.getOrDefault(request.getDomain(), Domain.DEFAULT) : Domain.DEFAULT;
val idGenerationInput = IdGenerationInput.builder()
.prefix(request.getPrefix())
.suffix(request.getSuffix())
.domain(domain)
.build();
return Optional.ofNullable(retryer.get(
() -> {
val idInfoOptional = nonceGenerator.generateWithConstraints(idGenerationInput);
val id = getIdFromIdInfo(idInfoOptional, request.getPrefix(), request.getIdFormatter());
val id = getIdFromIdInfo(idInfoOptional, request.getPrefix(), request.getSuffix(), request.getIdFormatter());
return new GenerationResult(
idInfoOptional,
validateId(request.getConstraints(), id, request.isSkipGlobal()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
@Builder
public class IdGenerationInput {
String prefix;
String suffix;
Domain domain;

}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
public class IdGenerationRequest {

String prefix;
String suffix;
String domain;
boolean skipGlobal;
List<IdValidationConstraint> constraints;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ void testConstraintFailure() {

@Test
void testNodeId() {
val generatedId = IdGenerator.generate("TEST123");
val generatedId = IdGenerator.generate("TEST");
val parsedId = IdGenerator.parse(generatedId.getId()).orElse(null);
Assertions.assertNotNull(parsedId);
Assertions.assertEquals(parsedId.getNode(), nodeId);
Expand Down Expand Up @@ -225,17 +225,24 @@ void testParseSuccess() {
}

@Test
void testParseSuccessAfterGeneration() {
void testParseFailAfterGeneration() {
val generatedId = IdGenerator.generate("TEST123");
val parsedId = IdGenerator.parse(generatedId.getId()).orElse(null);
Assertions.assertNull(parsedId);
}

@Test
void testParseSuccessAfterGeneration() {
val prefix = "TEST";
val generatedId = IdGenerator.generate(prefix);
val parsedId = IdGenerator.parse(generatedId.getId()).orElse(null);
Assertions.assertNotNull(parsedId);
Assertions.assertEquals(parsedId.getId(), generatedId.getId());
Assertions.assertEquals(parsedId.getExponent(), generatedId.getExponent());
Assertions.assertEquals(parsedId.getNode(), generatedId.getNode());
Assertions.assertEquals(parsedId.getGeneratedDate(), generatedId.getGeneratedDate());
}


@SuppressWarnings("SameParameterValue")
private Date generateDate(int year, int month, int day, int hour, int min, int sec, int ms, ZoneId zoneId) {
return Date.from(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package io.appform.ranger.discovery.bundle.id;

import io.appform.ranger.discovery.bundle.id.formatter.IdFormatters;
import io.appform.ranger.discovery.bundle.id.formatter.IdParsers;
import io.appform.ranger.discovery.bundle.id.generator.DefaultIdGenerator;
import lombok.val;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class IdParsersTest {

@Test
void testDefaultId() throws ParseException {
val id = "T2407101232336168748798";
val parsedId = IdParsers.parse(id).orElse(null);
Assertions.assertNotNull(parsedId);
Assertions.assertEquals(id, parsedId.getId());
Assertions.assertEquals(798, parsedId.getExponent());
Assertions.assertEquals(8748, parsedId.getNode());
assertDate("240710123233616", parsedId.getGeneratedDate());
}

private void assertDate(final String dateString, final Date date) throws ParseException {
Assertions.assertEquals(new SimpleDateFormat("yyMMddHHmmssSSS").parse(dateString), date);
}

@Test
void testParseSuccessAfterGenerationWithSuffix() {
val idGenerator = new DefaultIdGenerator(IdFormatters.suffix());
val prefix = "TEST";
val suffix = "007";
val generatedId = idGenerator.generate(prefix, suffix);
val parsedId = IdGenerator.parse(generatedId.getId()).orElse(null);
Assertions.assertNotNull(parsedId);
Assertions.assertEquals(prefix, parsedId.getPrefix());
Assertions.assertEquals(suffix, parsedId.getSuffix());
Assertions.assertEquals(parsedId.getId(), generatedId.getId());
Assertions.assertEquals(parsedId.getExponent(), generatedId.getExponent());
Assertions.assertEquals(parsedId.getNode(), generatedId.getNode());
Assertions.assertEquals(parsedId.getGeneratedDate(), generatedId.getGeneratedDate());
}
}