Skip to content

Commit

Permalink
Added support for arrays
Browse files Browse the repository at this point in the history
  • Loading branch information
codepitbull committed Dec 13, 2024
1 parent 801d49c commit 8565553
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

public class BuiltinJsonSchema {

Expand All @@ -44,6 +46,9 @@ public class BuiltinJsonSchema {
private static final @NotNull String MINIMUM_KEY_WORD = "minimum";
private static final @NotNull String MAXIMUM_KEY_WORD = "maximum";
public static final @NotNull String INTEGER_DATA_TYPE = "integer";
public static final @NotNull String ARRAY_DATA_TYPE = "array";
public static final @NotNull String ARRAY_ITEMS = "items";
public static final @NotNull String ARRAY_MAX_TIMES = "maxItems";

private final @NotNull HashMap<BuiltinDataType, JsonNode> classToJsonSchema = new HashMap<>();

Expand Down Expand Up @@ -111,6 +116,10 @@ public BuiltinJsonSchema() {
return classToJsonSchema.get(builtinDataType);
}

public @NotNull JsonNode getJsonSchemaForArray(final @NotNull BuiltinDataType builtinDataType) {
return classToJsonSchema.get(builtinDataType);
}

private @NotNull JsonNode createJsonSchemaForBuiltinType(
final @NotNull String title, final @NotNull BuiltinDataType builtinDataType) {
final ObjectNode rootNode = OBJECT_MAPPER.createObjectNode();
Expand All @@ -130,6 +139,30 @@ public BuiltinJsonSchema() {
return rootNode;
}

public static void populatePropertiesForArray(final @NotNull ObjectNode propertiesNode,
final @NotNull BuiltinDataType builtinDataType,
final @NotNull ObjectMapper objectMapper,
final @NotNull UInteger[] dimensions) {
final long maxSize = dimensions[0].longValue();

propertiesNode.set("type", new TextNode(ARRAY_DATA_TYPE));

//0 for a dimension means unlimited
if(maxSize > 0) {
propertiesNode.set("maxItems", new LongNode(maxSize));
}
final ObjectNode itemsNode = objectMapper.createObjectNode();
propertiesNode.set("items", itemsNode);

if (dimensions.length == 1) { //we are the last element
//last element, we can now set the array type
populatePropertiesForBuiltinType(itemsNode, builtinDataType, objectMapper);
} else {
//nesting deeper
populatePropertiesForArray(itemsNode, builtinDataType, objectMapper, Arrays.copyOfRange(dimensions, 1, dimensions.length));
}
}

public static void populatePropertiesForBuiltinType(
final @NotNull ObjectNode nestedPropertiesNode,
final @NotNull BuiltinDataType builtinDataType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.eclipse.milo.opcua.stack.core.serialization.codecs.DataTypeCodec;
import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId;
import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.opcfoundation.opcua.binaryschema.FieldType;
Expand Down Expand Up @@ -67,34 +68,50 @@ public void createJsonSchema(
output.tagNotFound("No node was found for the given node id '" + destinationNodeId + "'");
return;
}

final NodeId dataTypeNodeId = uaVariableNode.getDataType();
final DataTypeTree.DataType dataType = tree.getDataType(dataTypeNodeId);
final UInteger[] dimensions = uaVariableNode.getArrayDimensions();
if (dataType == null) {
output.fail("Unable to find the data type for the given node id '" + destinationNodeId + "'.");
return;
}
final BuiltinDataType builtinType = tree.getBuiltinType(dataType.getNodeId());
if (builtinType != BuiltinDataType.ExtensionObject) {
output.finish(builtinJsonSchema.getJsonSchema(builtinType));
if(dimensions != null && dimensions.length > 0) {
final ObjectNode node = objectMapper.createObjectNode();
BuiltinJsonSchema.populatePropertiesForArray(
node,
builtinType,
objectMapper,
dimensions);

System.out.println("HMM " + node);
output.finish(node);
} else {
output.finish(builtinJsonSchema.getJsonSchema(builtinType));
}
} else {
final NodeId binaryEncodingId = dataType.getBinaryEncodingId();
if (binaryEncodingId == null) {
output.fail("No encoding was present for the complex data type: '" + dataType + "'.");
}
output.finish(jsonSchemaFromNodeId(binaryEncodingId));
output.finish(jsonSchemaFromNodeId(binaryEncodingId, dimensions));
}
});
}

public void addNestedStructureInformation(
final @NotNull ObjectNode propertiesNode, final @NotNull FieldType fieldType) {
final @NotNull ObjectNode propertiesNode, final @NotNull FieldType fieldType, final @NotNull UInteger[] dimensions) {
final BuiltinDataType builtinDataType = convertFieldTypeToBuiltInDataType(fieldType, client);

final ObjectNode nestedPropertiesNode = objectMapper.createObjectNode();
propertiesNode.set(fieldType.getName(), nestedPropertiesNode);

if (builtinDataType != BuiltinDataType.ExtensionObject) {
BuiltinJsonSchema.populatePropertiesForBuiltinType(nestedPropertiesNode, builtinDataType, objectMapper);
} else if(dimensions != null && dimensions.length > 0) {
BuiltinJsonSchema.populatePropertiesForArray(nestedPropertiesNode, builtinDataType, objectMapper, dimensions);
} else {
nestedPropertiesNode.set("type", new TextNode("object"));
final ObjectNode innerProperties = objectMapper.createObjectNode();
Expand Down Expand Up @@ -128,13 +145,13 @@ public void addNestedStructureInformation(
final ArrayNode requiredAttributesArray = objectMapper.createArrayNode();
for (final Map.Entry<String, FieldType> entry : embeddedFields.entrySet()) {
requiredAttributesArray.add(entry.getValue().getName());
addNestedStructureInformation(innerProperties, entry.getValue());
addNestedStructureInformation(innerProperties, entry.getValue(), dimensions);
}
nestedPropertiesNode.set("required", requiredAttributesArray);
}
}

private @NotNull JsonNode jsonSchemaFromNodeId(final @Nullable NodeId binaryEncodingId) {
private @NotNull JsonNode jsonSchemaFromNodeId(final @Nullable NodeId binaryEncodingId, final @NotNull UInteger[] dimensions) {
if (binaryEncodingId == null) {
throw new RuntimeException("Binary encoding id was null for nested struct.");
}
Expand All @@ -157,7 +174,7 @@ public void addNestedStructureInformation(
for (final Map.Entry<String, FieldType> entry : fields.entrySet()) {
requiredAttributesArray.add(entry.getValue().getName());
final FieldType fieldType = entry.getValue();
addNestedStructureInformation(propertiesNode, fieldType);
addNestedStructureInformation(propertiesNode, fieldType, dimensions);
}
valueNode.set("required", requiredAttributesArray);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
package com.hivemq.edge.adapters.opcua.mqtt2opcua;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.DoubleNode;
import com.fasterxml.jackson.databind.node.IntNode;
import com.fasterxml.jackson.databind.node.LongNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.eclipse.milo.opcua.stack.core.BuiltinDataType;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UByte;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UShort;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

Expand Down Expand Up @@ -94,5 +98,4 @@ void extractFloat() {
assertEquals(12.2, value, 0.0001);
}


}

0 comments on commit 8565553

Please sign in to comment.