Skip to content

Commit

Permalink
Merge pull request #52 from openepcis/EDG-54_number_type_to_custom_us…
Browse files Browse the repository at this point in the history
…er_extension

Edg 54 number type to custom user extension
  • Loading branch information
sboeckelmann authored Feb 3, 2025
2 parents 00eae2c + ddb06a4 commit 7e3662d
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@
import lombok.Setter;
import lombok.ToString;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.NumberUtils;
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.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -67,15 +69,21 @@ public class UserExtensionSyntax implements Serializable {
)
private String data;

@Schema(
type = SchemaType.STRING,
enumeration = {
"simple",
"complex"
},
description =
"Type of user extension simple type with direct value or complex type with children elements")
private List<UserExtensionSyntax> children;
@Schema(type = SchemaType.NUMBER,
description = "Number Data associated with the custom user extension (Ex: 1, 10, 1234, 20.0 etc.)"
)
private String numberData;

@Schema(
type = SchemaType.STRING,
enumeration = {
"string",
"number",
"complex"
},
description =
"Type of user extension simple type with direct value or complex type with children elements")
private List<UserExtensionSyntax> children;

@Schema(type = SchemaType.OBJECT,
description = "Raw JSON-LD formatted extension with @context which can be directly appended as extensions."
Expand All @@ -87,44 +95,53 @@ public class UserExtensionSyntax implements Serializable {
public Map<String, Object> toMap() {
final Map<String, Object> map = new HashMap<>();

if (this.rawJsonld == null) {
//Add the context prefix and url to the document context
buildContextInfo(this.prefix, this.contextURL);

//Based on the Web Vocabulary or Custom Extensions get the respective key and add information
final String key = StringUtils.isNotBlank(this.label) ? this.label : (this.prefix + ":" + this.property);

//for complex children is not empty then recursively loop over children and format the elements
if (CollectionUtils.isNotEmpty(children)) {
final Map<String, Object> complexMap = children.stream()
.flatMap(c -> c.toMap().entrySet().stream())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
map.put(key, complexMap);
} else {
//for simple string directly add the information
map.put(key, data);
}
} else if (this.rawJsonld instanceof Map<?, ?>) {
// Check if rawJsonld is a Map if so extract context info and append others to map
@SuppressWarnings("unchecked")
final Map<String, Object> genExtMap = (Map<String, Object>) this.rawJsonld;

// Extract @context if present and append it to the StreamingEPCISDocument @context of EPCIS Document
Optional.ofNullable(genExtMap.get("@context"))
.filter(obj -> obj instanceof List)
.map(obj -> (List<Map<String, String>>) obj)
.ifPresent(contextList -> contextList.stream()
.flatMap(contextMap -> contextMap.entrySet().stream())
.forEach(entry -> buildContextInfo(entry.getKey(), entry.getValue())));


genExtMap.remove("@context"); // exclude the @context from the rawJsonld
map.putAll(genExtMap); // add remaining entries to the map
if (this.rawJsonld == null) {
//Add the context prefix and url to the document context
buildContextInfo(this.prefix, this.contextURL);

// Determine the key based on Web Vocabulary or Custom Extensions
final String key = StringUtils.defaultIfBlank(this.label, this.prefix + ":" + this.property);

// If children are present, recursively process them
if (CollectionUtils.isNotEmpty(children)) {
final Map<String, Object> complexMap = children.stream()
.flatMap(c -> c.toMap().entrySet().stream())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
map.put(key, complexMap);
} else {
// Determine the value to store
final String value = StringUtils.defaultIfBlank(data, numberData);

// If number add as Number else add as String
if(NumberUtils.isNumber(value)){
final Number number = value.contains(".") || value.toLowerCase().contains("e")
? new BigDecimal(value)
: NumberUtils.createNumber(value);
map.put(key, number);
}else {
map.put(key, value);
}
}
} else if (this.rawJsonld instanceof Map<?, ?>) {
// Check if rawJsonld is a Map if so extract context info and append others to map
@SuppressWarnings("unchecked") final Map<String, Object> genExtMap = (Map<String, Object>) this.rawJsonld;

// Extract @context if present and append it to the StreamingEPCISDocument @context of EPCIS Document
Optional.ofNullable(genExtMap.get("@context"))
.filter(obj -> obj instanceof List)
.map(obj -> (List<Map<String, String>>) obj)
.ifPresent(contextList -> contextList.stream()
.flatMap(contextMap -> contextMap.entrySet().stream())
.forEach(entry -> buildContextInfo(entry.getKey(), entry.getValue())));


genExtMap.remove("@context"); // exclude the @context from the rawJsonld
map.putAll(genExtMap); // add remaining entries to the map
}

return map;
}

return map;
}


//Function to add the context url and the prefix to the StreamingEPCISDocument context to generate the @context
private void buildContextInfo(final String prefix, final String contextURL) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import io.openepcis.model.epcis.EPCISEvent;
import io.openepcis.testdata.generator.format.UserExtensionSyntax;
import io.openepcis.testdata.generator.template.CustomContextUrl;
import io.openepcis.testdata.generator.template.EPCISEventType;
import io.openepcis.testdata.generator.template.ObjectEventType;
import io.openepcis.testdata.generator.template.TransformationEventType;
Expand All @@ -30,7 +31,9 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

@Getter
@Setter
Expand All @@ -41,6 +44,9 @@ public class StreamingEPCISDocument {
@Getter
private static Map<String, String> context;

@Getter
private static List<String> selectedContextUrls;

private Multi<EPCISEvent> epcisEvents;
private boolean prettyPrint;

Expand Down Expand Up @@ -76,8 +82,16 @@ public static void storeContextInfo(final List<EPCISEventType> events) {
});
}

public static void storeContextUrls(final List<CustomContextUrl> customContextUrls) {
selectedContextUrls = customContextUrls.stream()
.filter(c -> Objects.nonNull(c.getIsChecked()) && c.getIsChecked())
.map(CustomContextUrl::getContextURL)
.toList();
}

/**
* Extract namespaceURI and localname from each event and store in context.
*
* @param extensions list of extensions from ilmd, error and userExtensions
*/
public static void extractNamespaces(final List<UserExtensionSyntax> extensions) {
Expand All @@ -86,6 +100,7 @@ public static void extractNamespaces(final List<UserExtensionSyntax> extensions)

/**
* write to OutputStream
*
* @param fn builder reference
* @throws IOException throws the io exception
*/
Expand All @@ -95,6 +110,7 @@ public void writeToOutputStream(Function<StreamingEPCISDocumentOutput.OutputStre

/**
* write to Writer
*
* @param fn builder reference
* @throws IOException throws the io exception
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import io.openepcis.constants.EPCIS;
import io.openepcis.constants.EPCISVersion;
import io.openepcis.model.epcis.EPCISEvent;
import io.openepcis.model.rest.ProblemResponseBody;
import io.openepcis.testdata.generator.constants.TestDataGeneratorException;
import io.smallrye.mutiny.Multi;
import org.apache.commons.collections4.CollectionUtils;
import org.jboss.resteasy.reactive.RestResponse;

import java.io.IOException;
Expand Down Expand Up @@ -50,7 +53,7 @@ public class StreamingEPCISDocumentOutput {
private static final DateTimeFormatter DATE_TIME_FORMATTER =
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SS'Z'");

private StreamingEPCISDocumentOutput( final Executor executor, final ObjectMapper objectMapper, final OutputStream outputStream, final Writer writer) {
private StreamingEPCISDocumentOutput(final Executor executor, final ObjectMapper objectMapper, final OutputStream outputStream, final Writer writer) {
this.executor = executor;
this.objectMapper = objectMapper.copy();
this.outputStream = outputStream;
Expand All @@ -74,7 +77,7 @@ public static WriterBuilder writerBuilder() {
}

private JsonGenerator createJsonGenerator() throws IOException {
final JsonGenerator jsonGenerator = outputStream != null?JSON_FACTORY.createGenerator(outputStream):JSON_FACTORY.createGenerator(writer);
final JsonGenerator jsonGenerator = outputStream != null ? JSON_FACTORY.createGenerator(outputStream) : JSON_FACTORY.createGenerator(writer);
jsonGenerator.setCodec(objectMapper);
return jsonGenerator;
}
Expand Down Expand Up @@ -102,7 +105,7 @@ void write(final StreamingEPCISDocument streamingEPCISDocument) throws IOExcepti
}
}

public Flow.Subscriber<EPCISEvent> createSubscriber(final JsonGenerator jsonGenerator, final AtomicBoolean running) {
public Flow.Subscriber<EPCISEvent> createSubscriber(final JsonGenerator jsonGenerator, final AtomicBoolean running) {
return new Flow.Subscriber<>() {
final AtomicReference<Flow.Subscription> refSubscription = new AtomicReference<>();

Expand All @@ -116,10 +119,21 @@ public void onSubscribe(Flow.Subscription s) {
jsonGenerator.writeStartObject();

// Write the info related to Context element in JSON
jsonGenerator.writeFieldName("@context");
jsonGenerator.writeFieldName(EPCIS.CONTEXT);
jsonGenerator.writeStartArray();
jsonGenerator.writeString(
"https://ref.gs1.org/standards/epcis/2.0.0/epcis-context.jsonld");
jsonGenerator.writeString(EPCISVersion.getDefaultJSONContext());

// Adds all selected context URLs to the EPCIS document's @context array.
if (CollectionUtils.isNotEmpty(StreamingEPCISDocument.getSelectedContextUrls())) {
StreamingEPCISDocument.getSelectedContextUrls()
.forEach(url -> {
try {
jsonGenerator.writeString(url);
} catch (IOException e) {
throw new TestDataGeneratorException("Failed to write context URL: " + url, e);
}
});
}

// If context contains any values then add them to context array
if (StreamingEPCISDocument.getContext() != null
Expand Down Expand Up @@ -179,7 +193,7 @@ public void onError(Throwable t) {
jsonGenerator.writeEndObject(); // End epcisBody

//If there is error then add the error message to JSON
final ProblemResponseBody pb = ProblemResponseBody.fromException(t, RestResponse.Status.BAD_REQUEST);
final ProblemResponseBody pb = ProblemResponseBody.fromException(t, RestResponse.Status.BAD_REQUEST);
jsonGenerator.writeObjectField("problemResponse", pb);

jsonGenerator.writeEndObject(); // End whole json file
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package io.openepcis.testdata.generator.template;

import io.quarkus.runtime.annotations.RegisterForReflection;
import lombok.Getter;
import lombok.Setter;
import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
import org.eclipse.microprofile.openapi.annotations.media.Schema;

import java.io.Serializable;

@Setter
@Getter
@RegisterForReflection
public class CustomContextUrl implements Serializable {
@Schema(
type = SchemaType.NUMBER,
description = "Unique identifier for the custom context.")
private int ID;

@Schema(
type = SchemaType.STRING,
description = "URL associated with the custom context.")
private String contextURL;

@Schema(
type = SchemaType.STRING,
description = "Prefix associated with the custom context URL.")
private String prefix;

@Schema(
type = SchemaType.BOOLEAN,
description = "Flag indicating whether the custom context should be included in generated events.")
private Boolean isChecked;
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,25 @@
@ToString
@RegisterForReflection
public class InputTemplate {
@Schema(
type = SchemaType.ARRAY,
description = "List of events information required for creation of EPCIS events.",
required = true)
private List<@Valid EPCISEventType> events;
@Schema(
type = SchemaType.ARRAY,
description = "List of events information required for creation of EPCIS events.",
required = true)
private List<@Valid EPCISEventType> events;

@Schema(
type = SchemaType.ARRAY,
description = "List of identifiers information required for creation of EPCIS events.",
required = true)
private List<@Valid Identifier> identifiers;
@Schema(
type = SchemaType.ARRAY,
description = "List of identifiers information required for creation of EPCIS events.",
required = true)
private List<@Valid Identifier> identifiers;

@Schema(
type = SchemaType.ARRAY,
description = "List of random types information required for creation of random values/serials.")
private List<@Valid RandomGenerators> randomGenerators;
@Schema(
type = SchemaType.ARRAY,
description = "List of random types information required for creation of random values/serials.")
private List<@Valid RandomGenerators> randomGenerators;

@Schema(
type = SchemaType.ARRAY,
description = "A list of custom context URL definitions, used to extend the @context field in generated events.")
private List<@Valid CustomContextUrl> contextUrls;
}
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ public StreamingEPCISDocument generateTestData(
if (violations.isEmpty()) {
final StreamingEPCISDocument streamingEPCISDocument = new StreamingEPCISDocument();
StreamingEPCISDocument.storeContextInfo(inputTemplate.getEvents());
StreamingEPCISDocument.storeContextUrls(inputTemplate.getContextUrls());
streamingEPCISDocument.setPrettyPrint(pretty);
streamingEPCISDocument.setEpcisEvents(EPCISEventGenerator.generate(inputTemplate));
return streamingEPCISDocument;
Expand Down

0 comments on commit 7e3662d

Please sign in to comment.