Skip to content

Commit

Permalink
Merge pull request #50 from openepcis/EDG-39_sensor_report_randomizer
Browse files Browse the repository at this point in the history
EDG-39: Adding support to random values in SensorReport double fields
  • Loading branch information
sboeckelmann authored Aug 14, 2024
2 parents 0cfefcf + a6e6859 commit 427f94a
Show file tree
Hide file tree
Showing 16 changed files with 403 additions and 152 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import io.openepcis.testdata.generator.template.EPCISEventType;
import io.openepcis.testdata.generator.template.InputTemplate;
import io.smallrye.mutiny.Multi;

import java.util.List;
import java.util.Optional;

Expand All @@ -35,9 +36,9 @@ public static List<EventCreationModel<EPCISEventType, EPCISEvent>> createModels(
try {
return inputTemplate.getEvents().stream()
.map(
e ->
EventModelUtil.createModel(
e, EventModelUtil.usedIdentifiers(e, inputTemplate.getIdentifiers())))
e ->
EventModelUtil.createModel(
e, EventModelUtil.usedIdentifiers(e, inputTemplate.getIdentifiers()), inputTemplate.getRandomGenerators()))
.filter(Optional::isPresent)
.map(Optional::get)
.toList();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,122 +1,26 @@
/*
* Copyright 2022-2024 benelog GmbH & Co. KG
*
* 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.openepcis.testdata.generator.format;

import io.openepcis.testdata.generator.constants.RandomizationType;
import io.openepcis.testdata.generator.constants.TestDataGeneratorException;
import io.quarkus.runtime.annotations.RegisterForReflection;

import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
import io.openepcis.testdata.generator.template.RandomGenerators;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.commons.math3.distribution.TriangularDistribution;
import org.apache.commons.math3.random.MersenneTwister;
import org.apache.commons.math3.random.RandomGenerator;

import java.util.List;

@NoArgsConstructor(access = AccessLevel.PRIVATE)
@RegisterForReflection
public class RandomValueGenerator {

private SecureRandom random = new SecureRandom();

private static final RandomValueGenerator INSTANCE = new RandomValueGenerator();

public static final RandomValueGenerator getInstance() {
return INSTANCE;
}
public List<String> randomGenerator(
RandomizationType type, int minLength, int maxLength, int randomCount) {
return switch (type) {
case ALPHA_NUMERIC:
yield alphaNumericGenerator(minLength, maxLength, randomCount);
case URL_SAFE_CHARACTERS:
yield urlSafeGenerator(minLength, maxLength, randomCount);
default:
yield numericGenerator(minLength, maxLength, randomCount);
};
}

// If Numeric random values needs to be generated
public List<String> numericGenerator(int minLength, int maxLength, int randomCount) {
try {
final List<String> randomList = new ArrayList<>();
final var numericRandomSet = "1234567890";

for (var id = 0; id < randomCount; id++) {
var randomID = new StringBuilder();
final int charPicker = minLength + random.nextInt(maxLength - minLength + 1);

for (var i = 0; i < charPicker; i++) {
randomID.append(numericRandomSet.charAt(random.nextInt(numericRandomSet.length())));
}
randomList.add(randomID.toString());
}
return randomList;
} catch (Exception ex) {
throw new TestDataGeneratorException(
"Exception occurred during creation of seral numbers in Random Numeric format, Please check the values provided values for Identifiers random values : "
+ ex.getMessage(), ex);
}
}

// If Alphanumeric random values needs to be generated
public List<String> alphaNumericGenerator(int minLength, int maxLength, int randomCount) {
try {
final var alphaNumericRandomSet =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
final List<String> randomList = new ArrayList<>();

for (var id = 0; id < randomCount; id++) {
var randomID = new StringBuilder();
final int charPicker = minLength + random.nextInt(maxLength - minLength + 1);

for (var i = 0; i < charPicker; i++) {
randomID.append(
alphaNumericRandomSet.charAt(random.nextInt(alphaNumericRandomSet.length())));
}
randomList.add(randomID.toString());
}
return randomList;
} catch (Exception ex) {
throw new TestDataGeneratorException(
"Exception occurred during creation of seral numbers in Random Alphanumeric format, Please check the values provided values for Identifiers random values : "
+ ex.getMessage(), ex);
}
}

// If URL Safe random values needs to be generated
public List<String> urlSafeGenerator(int minLength, int maxLength, int randomCount) {
try {
final var urlSafeRandomSet = "abcdefghijklmnopqrstuvwxyz0123456789-_";
final List<String> randomList = new ArrayList<>();

for (var id = 0; id < randomCount; id++) {
var randomID = new StringBuilder();
final int charPicker = minLength + random.nextInt(maxLength - minLength + 1);

for (var i = 0; i < charPicker; i++) {
randomID.append(urlSafeRandomSet.charAt(random.nextInt(urlSafeRandomSet.length())));
//Method to generate the Mersenne Twister instance for each of the RandomGenerators to get subsequent numbers when used multiple times
public static void generateInstance(final List<RandomGenerators> randomGenerators) {
if (randomGenerators != null) {
randomGenerators.forEach(r -> {
// Initialize Mersenne Twister with the seed
final RandomGenerator random = new MersenneTwister(r.getSeedValue());
final TriangularDistribution triangularDistribution = new TriangularDistribution(random, r.getMinValue(), r.getMeanValue(), r.getMaxValue());
r.setTriangularDistribution(triangularDistribution);
});
}
randomList.add(randomID.toString());
}
return randomList;
} catch (Exception ex) {
throw new TestDataGeneratorException(
"Exception occurred during creation of seral numbers in Random Alphanumeric with special characters, Please check the values provided values for Identifiers random values : "
+ ex.getMessage(), ex);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package io.openepcis.testdata.generator.format;

import io.openepcis.testdata.generator.constants.TestDataGeneratorException;
import io.openepcis.testdata.generator.template.RandomGenerators;
import io.quarkus.runtime.annotations.RegisterForReflection;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
import org.eclipse.microprofile.openapi.annotations.media.Schema;

import java.io.Serializable;
import java.util.List;

@Setter
@Getter
@RegisterForReflection
public class ValueTypeSyntax implements Serializable {
@NotNull(message = "Type cannot be Null for Static/Random value generation")
@Schema(type = SchemaType.STRING, description = "Type of the Static/Random value generation static/random.")
private String type;

@Schema(type = SchemaType.NUMBER, description = "Static value if the type is static.")
private double staticValue;

@Schema(type = SchemaType.INTEGER, description = "randomID associated to randomGenerators if the type is random.")
private int randomID;

// Method to get the value, either static or generated randomly
public double getValue(final List<RandomGenerators> randomGenerators) {
if (this.type.equals("static")) {
return this.staticValue;
} else if (this.type.equals("random") && randomGenerators != null) {
return generateRandomValue(randomGenerators);
}

throw new TestDataGeneratorException("Unknown type for Value generation : " + this.type);
}

private double generateRandomValue(final List<RandomGenerators> randomGenerators) {
// Find the corresponding RandomGenerators entry
final RandomGenerators generatorConfig = randomGenerators.stream()
.filter(r -> r.getRandomID() == this.randomID)
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("No generator found for randomID: " + randomID));

double sample = generatorConfig.getTriangularDistribution().sample(); // Generate and return the random value

//If user specified format for RandomGenerator then format based on specific format
if(!StringUtils.isBlank(generatorConfig.getFormatValue())){
try{
return Double.parseDouble(String.format(generatorConfig.getFormatValue(), sample));
}catch (Exception ex){
throw new TestDataGeneratorException("Invalid format value provided for formatting Random value : " + ex.getMessage(), ex);
}
}

return Double.parseDouble(String.format("%.3f", sample));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import io.openepcis.testdata.generator.reactivestreams.EventIdentifierTracker;
import io.openepcis.testdata.generator.template.EPCISEventType;
import io.openepcis.testdata.generator.template.Identifier;
import io.openepcis.testdata.generator.template.RandomGenerators;
import io.openepcis.testdata.generator.template.ReferencedIdentifier;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
Expand Down Expand Up @@ -60,17 +61,21 @@ public abstract class AbstractEventCreationModel<T extends EPCISEventType, E ext

protected final List<Identifier> identifiers;

protected final List<RandomGenerators> randomGenerators;

private EPCISEventDownstreamHandler epcisEventDownstreamHandler = null;

private final DateTimeFormatter dateFormatter =
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX");

private final RandomSerialNumberGenerator randomSerialNumberGenerator;

public AbstractEventCreationModel(final T typeInfo, final List<Identifier> identifiers) {
public AbstractEventCreationModel(final T typeInfo, final List<Identifier> identifiers, final List<RandomGenerators> randomGenerators) {
this.typeInfo = typeInfo;
this.identifiers = identifiers;
this.randomGenerators = randomGenerators;
this.randomSerialNumberGenerator = RandomSerialNumberGenerator.getInstance(typeInfo.getSeed()); //Since instance of MersenneTwister for each model
RandomValueGenerator.generateInstance(randomGenerators); // Generate Random instance for each of the randomGenerators
}

@Override
Expand Down Expand Up @@ -98,9 +103,23 @@ protected void configure(final E epcisEvent, final List<EventIdentifierTracker>
// Call the method to add the Error related information
configureErrorInformation(epcisEvent, syntax);

// Add Sensor Info
// Add Sensor Info by formatting the values based on Static/Random
if (typeInfo.getSensorElementList() != null && !typeInfo.getSensorElementList().isEmpty()) {
epcisEvent.setSensorElementList(typeInfo.getSensorElementList());
final List<SensorElementList> sensorElementList = new ArrayList<>();

typeInfo.getSensorElementList().forEach(element -> {
final SensorElementList sensorElement = new SensorElementList();
final List<SensorReport> sensorReports = new ArrayList<>();

sensorElement.setSensorMetadata(element.getSensorMetadata());
element.getSensorReport().forEach(report -> sensorReports.add(report.format(randomGenerators))); //Format the SensorReportType to SensorReport

sensorElement.setSensorReport(sensorReports);
sensorElementList.add(sensorElement);
});

//Assign formatted sensorElementList to EPCISEvent SensorElementList
epcisEvent.setSensorElementList(sensorElementList);
}

// Add the certificationInfo by formatting from UserExtension syntax
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import io.openepcis.testdata.generator.reactivestreams.EventIdentifierTracker;
import io.openepcis.testdata.generator.template.AggregationEventType;
import io.openepcis.testdata.generator.template.Identifier;
import io.openepcis.testdata.generator.template.RandomGenerators;

import java.util.List;

public class AggregationEventCreationModel
Expand All @@ -32,8 +34,8 @@ public class AggregationEventCreationModel
private Identifier matchingParentId = null;

public AggregationEventCreationModel(
final AggregationEventType typeInfo, final List<Identifier> identifiers) {
super(typeInfo, identifiers);
final AggregationEventType typeInfo, final List<Identifier> identifiers, final List<RandomGenerators> randomGenerators) {
super(typeInfo, identifiers, randomGenerators);

// Check if user has provided values for the Parent Identifiers
if (typeInfo.getParentReferencedIdentifier() != null && typeInfo.getParentReferencedIdentifier().getIdentifierId() > 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import io.openepcis.testdata.generator.reactivestreams.EventIdentifierTracker;
import io.openepcis.testdata.generator.template.AssociationEventType;
import io.openepcis.testdata.generator.template.Identifier;
import io.openepcis.testdata.generator.template.RandomGenerators;

import java.util.List;

public class AssociationEventCreationModel
Expand All @@ -32,8 +34,8 @@ public class AssociationEventCreationModel
private Identifier matchingParentId = null;

public AssociationEventCreationModel(
final AssociationEventType typeInfo, final List<Identifier> identifiers) {
super(typeInfo, identifiers);
final AssociationEventType typeInfo, final List<Identifier> identifiers, final List<RandomGenerators> randomGenerators) {
super(typeInfo, identifiers, randomGenerators);

// Check if user has provided values for the Parent Identifiers
if (typeInfo.getParentReferencedIdentifier() != null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,21 @@ public class EventModelUtil {
private EventModelUtil() {}

public static Optional<EventCreationModel<EPCISEventType, EPCISEvent>> createModel(
final EPCISEventType epcisEventType, final List<Identifier> identifiers) {
final EPCISEventType epcisEventType, final List<Identifier> identifiers, final List<RandomGenerators> randomGenerators) {
if (epcisEventType instanceof ObjectEventType objectEventType) {
return createEventCreationModel(new ObjectEventCreationModel(objectEventType, identifiers));
return createEventCreationModel(new ObjectEventCreationModel(objectEventType, identifiers, randomGenerators));
} else if (epcisEventType instanceof AggregationEventType aggregationEventType) {
return createEventCreationModel(
new AggregationEventCreationModel(aggregationEventType, identifiers));
new AggregationEventCreationModel(aggregationEventType, identifiers, randomGenerators));
} else if (epcisEventType instanceof TransactionEventType transactionEventType) {
return createEventCreationModel(
new TransactionEventCreationModel(transactionEventType, identifiers));
new TransactionEventCreationModel(transactionEventType, identifiers, randomGenerators));
} else if (epcisEventType instanceof TransformationEventType transformationEventType) {
return createEventCreationModel(
new TransformationEventCreationModel(transformationEventType, identifiers));
new TransformationEventCreationModel(transformationEventType, identifiers, randomGenerators));
} else if (epcisEventType instanceof AssociationEventType associationEventType) {
return createEventCreationModel(
new AssociationEventCreationModel(associationEventType, identifiers));
new AssociationEventCreationModel(associationEventType, identifiers, randomGenerators));
}
return Optional.empty();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import io.openepcis.testdata.generator.reactivestreams.EventIdentifierTracker;
import io.openepcis.testdata.generator.template.Identifier;
import io.openepcis.testdata.generator.template.ObjectEventType;
import io.openepcis.testdata.generator.template.RandomGenerators;
import org.apache.commons.collections4.CollectionUtils;

import java.util.List;
Expand All @@ -37,8 +38,8 @@ public class ObjectEventCreationModel
extends AbstractEventCreationModel<ObjectEventType, ObjectEvent> {

public ObjectEventCreationModel(
final ObjectEventType typeInfo, final List<Identifier> identifiers) {
super(typeInfo, identifiers);
final ObjectEventType typeInfo, final List<Identifier> identifiers, final List<RandomGenerators> randomGenerators) {
super(typeInfo, identifiers, randomGenerators);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import io.openepcis.testdata.generator.format.SourceFormatter;
import io.openepcis.testdata.generator.reactivestreams.EventIdentifierTracker;
import io.openepcis.testdata.generator.template.Identifier;
import io.openepcis.testdata.generator.template.RandomGenerators;
import io.openepcis.testdata.generator.template.TransactionEventType;
import java.util.List;

Expand All @@ -32,8 +33,8 @@ public class TransactionEventCreationModel
private Identifier matchingParentId = null;

public TransactionEventCreationModel(
final TransactionEventType typeInfo, final List<Identifier> identifiers) {
super(typeInfo, identifiers);
final TransactionEventType typeInfo, final List<Identifier> identifiers, final List<RandomGenerators> randomGenerators) {
super(typeInfo, identifiers, randomGenerators);

// Check if user has provided values for the Parent Identifiers
if (typeInfo.getParentReferencedIdentifier() != null
Expand Down
Loading

0 comments on commit 427f94a

Please sign in to comment.