import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.opendaylight.netconf.sal.rest.doc.impl.ApiDocServiceImpl.OAversion;
+import org.opendaylight.yangtools.yang.common.Decimal64;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.model.api.ActionDefinition;
import org.opendaylight.yangtools.yang.model.api.ActionNodeContainer;
private static final String INT32_FORMAT = "int32";
private static final String INT64_FORMAT = "int64";
private static final String BOOLEAN_TYPE = "boolean";
+ // Special characters used in automaton inside Generex.
+ // See https://www.brics.dk/automaton/doc/dk/brics/automaton/RegExp.html
+ private static final Pattern AUTOMATON_SPECIAL_CHARACTERS = Pattern.compile("[@&\"<>#~]");
private Module topLevelModule;
public ObjectNode convertToJsonSchema(final Module module, final EffectiveModelContext schemaContext,
- final ObjectNode definitions, final DefinitionNames definitionNames,
- final OAversion oaversion, final boolean isForSingleModule)
- throws IOException {
+ final ObjectNode definitions, final DefinitionNames definitionNames, final OAversion oaversion,
+ final boolean isForSingleModule) throws IOException {
topLevelModule = module;
processIdentities(module, definitions, definitionNames, schemaContext);
}
public ObjectNode convertToJsonSchema(final Module module, final EffectiveModelContext schemaContext,
- final DefinitionNames definitionNames, final OAversion oaversion,
- final boolean isForSingleModule)
+ final DefinitionNames definitionNames, final OAversion oaversion, final boolean isForSingleModule)
throws IOException {
final ObjectNode definitions = JsonNodeFactory.instance.objectNode();
if (isForSingleModule) {
}
private void processModule(final Module module, final ObjectNode definitions, final DefinitionNames definitionNames,
- final EffectiveModelContext schemaContext, final OAversion oaversion) {
+ final EffectiveModelContext schemaContext, final OAversion oaversion) {
final ObjectNode definition = JsonNodeFactory.instance.objectNode();
final ObjectNode properties = JsonNodeFactory.instance.objectNode();
final ArrayNode required = JsonNodeFactory.instance.arrayNode();
//add module name prefix to property name, when ServiceNow can process colons
properties.set(localName, childNodeProperties);
}
- } else {
- if (node instanceof LeafSchemaNode) {
- /*
- Add module name prefix to property name, when ServiceNow can process colons(second parameter
- of processLeafNode).
- */
- processLeafNode((LeafSchemaNode) node, localName, properties, required, stack,
- definitions, definitionNames, oaversion);
- }
+ } else if (node instanceof LeafSchemaNode) {
+ /*
+ Add module name prefix to property name, when ServiceNow can process colons(second parameter
+ of processLeafNode).
+ */
+ processLeafNode((LeafSchemaNode) node, localName, properties, required, stack,
+ definitions, definitionNames, oaversion);
}
}
stack.exit();
}
private void processContainersAndLists(final Module module, final ObjectNode definitions,
- final DefinitionNames definitionNames, final EffectiveModelContext schemaContext, final OAversion oaversion)
- throws IOException {
+ final DefinitionNames definitionNames, final EffectiveModelContext schemaContext,
+ final OAversion oaversion) throws IOException {
final String moduleName = module.getName();
final SchemaInferenceStack stack = SchemaInferenceStack.of(schemaContext);
for (final DataSchemaNode childNode : module.getChildNodes()) {
}
private void processActionNodeContainer(final DataSchemaNode childNode, final String moduleName,
- final ObjectNode definitions, final DefinitionNames definitionNames,
- final SchemaInferenceStack stack, final OAversion oaversion)
- throws IOException {
+ final ObjectNode definitions, final DefinitionNames definitionNames, final SchemaInferenceStack stack,
+ final OAversion oaversion) throws IOException {
for (final ActionDefinition actionDef : ((ActionNodeContainer) childNode).getActions()) {
+ stack.enterSchemaTree(actionDef.getQName());
processOperations(actionDef, moduleName, definitions, definitionNames, stack, oaversion);
+ stack.exit();
}
}
private void processRPCs(final Module module, final ObjectNode definitions, final DefinitionNames definitionNames,
- final EffectiveModelContext schemaContext, final OAversion oaversion) throws IOException {
+ final EffectiveModelContext schemaContext, final OAversion oaversion) throws IOException {
final String moduleName = module.getName();
final SchemaInferenceStack stack = SchemaInferenceStack.of(schemaContext);
for (final RpcDefinition rpcDefinition : module.getRpcs()) {
private void processOperations(final OperationDefinition operationDef, final String parentName,
final ObjectNode definitions, final DefinitionNames definitionNames,
- final SchemaInferenceStack stack, final OAversion oaversion)
- throws IOException {
+ final SchemaInferenceStack stack, final OAversion oaversion) throws IOException {
final String operationName = operationDef.getQName().getLocalName();
processOperationInputOutput(operationDef.getInput(), operationName, parentName, true, definitions,
definitionNames, stack, oaversion);
}
private void processOperationInputOutput(final ContainerLike container, final String operationName,
- final String parentName, final boolean isInput,
- final ObjectNode definitions, final DefinitionNames definitionNames,
- final SchemaInferenceStack stack, final OAversion oaversion)
+ final String parentName, final boolean isInput, final ObjectNode definitions,
+ final DefinitionNames definitionNames, final SchemaInferenceStack stack, final OAversion oaversion)
throws IOException {
stack.enterSchemaTree(container.getQName());
if (!container.getChildNodes().isEmpty()) {
* @param definitionNames Store for definition names
*/
private static void processIdentities(final Module module, final ObjectNode definitions,
- final DefinitionNames definitionNames, final EffectiveModelContext context) {
+ final DefinitionNames definitionNames, final EffectiveModelContext context) {
final String moduleName = module.getName();
final Collection<? extends IdentitySchemaNode> idNodes = module.getIdentities();
LOG.debug("Processing Identities for module {} . Found {} identity statements", moduleName, idNodes.size());
}
private static void populateEnumWithDerived(final Collection<? extends IdentitySchemaNode> derivedIds,
- final ArrayNode enumPayload, final EffectiveModelContext context) {
+ final ArrayNode enumPayload, final EffectiveModelContext context) {
for (final IdentitySchemaNode derivedId : derivedIds) {
enumPayload.add(derivedId.getQName().getLocalName());
populateEnumWithDerived(context.getDerivedIdentities(derivedId), enumPayload, context);
}
private ObjectNode processDataNodeContainer(final DataNodeContainer dataNode, final String parentName,
- final ObjectNode definitions, final DefinitionNames definitionNames,
- final boolean isConfig, final SchemaInferenceStack stack,
- final OAversion oaversion) throws IOException {
+ final ObjectNode definitions, final DefinitionNames definitionNames, final boolean isConfig,
+ final SchemaInferenceStack stack, final OAversion oaversion) throws IOException {
if (dataNode instanceof ListSchemaNode || dataNode instanceof ContainerSchemaNode) {
final Collection<? extends DataSchemaNode> containerChildren = dataNode.getChildNodes();
final SchemaNode schemaNode = (SchemaNode) dataNode;
/**
* Processes the nodes.
*/
- private ObjectNode processChildren(
- final ObjectNode parentNode, final Collection<? extends DataSchemaNode> nodes, final String parentName,
- final ObjectNode definitions, final DefinitionNames definitionNames, final boolean isConfig,
- final SchemaInferenceStack stack, final OAversion oaversion) throws IOException {
+ private ObjectNode processChildren(final ObjectNode parentNode, final Collection<? extends DataSchemaNode> nodes,
+ final String parentName, final ObjectNode definitions, final DefinitionNames definitionNames,
+ final boolean isConfig, final SchemaInferenceStack stack, final OAversion oaversion) throws IOException {
final ObjectNode properties = JsonNodeFactory.instance.objectNode();
final ArrayNode required = JsonNodeFactory.instance.arrayNode();
for (final DataSchemaNode node : nodes) {
- stack.enterSchemaTree(node.getQName());
if (!isConfig || node.isConfiguration()) {
- /*
- Add module name prefix to property name, when needed, when ServiceNow can process colons,
- use RestDocGenUtil#resolveNodesName for creating property name
- */
- final String propertyName = node.getQName().getLocalName();
- final ObjectNode property;
- if (node instanceof LeafSchemaNode) {
- processLeafNode((LeafSchemaNode) node, propertyName, properties,
- required, stack, definitions, definitionNames, oaversion);
- } else if (node instanceof AnyxmlSchemaNode) {
- processAnyXMLNode((AnyxmlSchemaNode) node, propertyName, properties,
- required);
- } else if (node instanceof AnydataSchemaNode) {
- processAnydataNode((AnydataSchemaNode) node, propertyName, properties, required);
- } else {
- if (node instanceof ListSchemaNode || node instanceof ContainerSchemaNode) {
- property = processDataNodeContainer((DataNodeContainer) node, parentName, definitions,
- definitionNames, isConfig, stack, oaversion);
- if (!isConfig) {
- processActionNodeContainer(node, parentName, definitions, definitionNames, stack,
- oaversion);
- }
- } else if (node instanceof LeafListSchemaNode) {
- property = processLeafListNode((LeafListSchemaNode) node, stack, definitions,
- definitionNames, oaversion);
-
- } else if (node instanceof ChoiceSchemaNode) {
- for (final CaseSchemaNode variant : ((ChoiceSchemaNode) node).getCases()) {
- stack.enterSchemaTree(variant.getQName());
- processChoiceNode(variant.getChildNodes(), parentName, definitions, definitionNames,
- isConfig, stack, properties, oaversion);
- stack.exit();
- }
- stack.exit();
- // FIXME dangerous statement here! Try to rework without continue.
- continue;
- } else {
- throw new IllegalArgumentException("Unknown DataSchemaNode type: " + node.getClass());
- }
- properties.set(propertyName, property);
- }
+ processChildNode(node, parentName, definitions, definitionNames, isConfig, stack, properties,
+ oaversion);
}
- stack.exit();
}
parentNode.set(PROPERTIES_KEY, properties);
setRequiredIfNotEmpty(parentNode, required);
return properties;
}
+ private void processChildNode(final DataSchemaNode node, final String parentName, final ObjectNode definitions,
+ final DefinitionNames definitionNames, final boolean isConfig, final SchemaInferenceStack stack,
+ final ObjectNode properties, final OAversion oaversion) throws IOException {
+
+ stack.enterSchemaTree(node.getQName());
+
+ /*
+ Add module name prefix to property name, when needed, when ServiceNow can process colons,
+ use RestDocGenUtil#resolveNodesName for creating property name
+ */
+ final String name = node.getQName().getLocalName();
+
+ if (node instanceof LeafSchemaNode leaf) {
+ processLeafNode(leaf, name, properties, JsonNodeFactory.instance.arrayNode(), stack, definitions,
+ definitionNames, oaversion);
+
+ } else if (node instanceof AnyxmlSchemaNode anyxml) {
+ processAnyXMLNode(anyxml, name, properties, JsonNodeFactory.instance.arrayNode());
+
+ } else if (node instanceof AnydataSchemaNode anydata) {
+ processAnydataNode(anydata, name, properties, JsonNodeFactory.instance.arrayNode());
+
+ } else {
+
+ final ObjectNode property;
+ if (node instanceof ListSchemaNode || node instanceof ContainerSchemaNode) {
+ property = processDataNodeContainer((DataNodeContainer) node, parentName, definitions,
+ definitionNames, isConfig, stack, oaversion);
+ if (!isConfig) {
+ processActionNodeContainer(node, parentName, definitions, definitionNames, stack, oaversion);
+ }
+ } else if (node instanceof LeafListSchemaNode leafList) {
+ property = processLeafListNode(leafList, stack, definitions, definitionNames, oaversion);
+
+ } else if (node instanceof ChoiceSchemaNode choice) {
+ for (final CaseSchemaNode variant : choice.getCases()) {
+ stack.enterSchemaTree(variant.getQName());
+ for (final DataSchemaNode childNode : variant.getChildNodes()) {
+ processChildNode(childNode, parentName, definitions, definitionNames, isConfig, stack,
+ properties, oaversion);
+ }
+ stack.exit();
+ }
+ property = null;
+
+ } else {
+ throw new IllegalArgumentException("Unknown DataSchemaNode type: " + node.getClass());
+ }
+ if (property != null) {
+ properties.set(name, property);
+ }
+ }
+
+ stack.exit();
+ }
+
private ObjectNode processLeafListNode(final LeafListSchemaNode listNode, final SchemaInferenceStack stack,
- final ObjectNode definitions, final DefinitionNames definitionNames,
- final OAversion oaversion) {
+ final ObjectNode definitions, final DefinitionNames definitionNames, final OAversion oaversion) {
final ObjectNode props = JsonNodeFactory.instance.objectNode();
props.put(TYPE_KEY, ARRAY_TYPE);
return props;
}
- private void processChoiceNode(
- final Iterable<? extends DataSchemaNode> nodes, final String parentName, final ObjectNode definitions,
- final DefinitionNames definitionNames, final boolean isConfig,
- final SchemaInferenceStack stack, final ObjectNode properties, final OAversion oaversion)
- throws IOException {
- for (final DataSchemaNode node : nodes) {
- stack.enterSchemaTree(node.getQName());
- /*
- Add module name prefix to property name, when needed, when ServiceNow can process colons,
- use RestDocGenUtil#resolveNodesName for creating property name
- */
- final String name = node.getQName().getLocalName();
- final ObjectNode property;
-
- /*
- Ignore mandatoriness(passing unreferenced arrayNode to process...Node), because choice produces multiple
- properties
- */
- if (node instanceof LeafSchemaNode) {
- processLeafNode((LeafSchemaNode) node, name, properties,
- JsonNodeFactory.instance.arrayNode(), stack, definitions, definitionNames, oaversion);
- } else if (node instanceof AnyxmlSchemaNode) {
- processAnyXMLNode((AnyxmlSchemaNode) node, name, properties,
- JsonNodeFactory.instance.arrayNode());
- } else if (node instanceof AnydataSchemaNode) {
- processAnydataNode((AnydataSchemaNode) node, name, properties,
- JsonNodeFactory.instance.arrayNode());
- } else {
- if (node instanceof ListSchemaNode || node instanceof ContainerSchemaNode) {
- property = processDataNodeContainer((DataNodeContainer) node, parentName, definitions,
- definitionNames, isConfig, stack, oaversion);
- if (!isConfig) {
- processActionNodeContainer(node, parentName, definitions, definitionNames, stack,
- oaversion);
- }
- } else if (node instanceof LeafListSchemaNode) {
- property = processLeafListNode((LeafListSchemaNode) node, stack, definitions,
- definitionNames, oaversion);
-
- } else if (node instanceof ChoiceSchemaNode) {
- for (final CaseSchemaNode variant : ((ChoiceSchemaNode) node).getCases()) {
- processChoiceNode(variant.getChildNodes(), parentName, definitions, definitionNames, isConfig,
- stack, properties, oaversion);
- }
- continue;
- } else {
- throw new IllegalArgumentException("Unknown DataSchemaNode type: " + node.getClass());
- }
- properties.set(name, property);
- }
- stack.exit();
- }
- }
-
private static void processElementCount(final Optional<ElementCountConstraint> constraint, final ObjectNode props) {
if (constraint.isPresent()) {
final ElementCountConstraint constr = constraint.get();
}
private ObjectNode processLeafNode(final LeafSchemaNode leafNode, final String jsonLeafName,
- final ObjectNode properties, final ArrayNode required,
- final SchemaInferenceStack stack, final ObjectNode definitions,
- final DefinitionNames definitionNames, final OAversion oaversion) {
+ final ObjectNode properties, final ArrayNode required, final SchemaInferenceStack stack,
+ final ObjectNode definitions, final DefinitionNames definitionNames, final OAversion oaversion) {
final ObjectNode property = JsonNodeFactory.instance.objectNode();
final String leafDescription = leafNode.getDescription().orElse("");
}
private static ObjectNode processAnydataNode(final AnydataSchemaNode leafNode, final String name,
- final ObjectNode properties, final ArrayNode required) {
+ final ObjectNode properties, final ArrayNode required) {
final ObjectNode property = JsonNodeFactory.instance.objectNode();
final String leafDescription = leafNode.getDescription().orElse("");
}
private static ObjectNode processAnyXMLNode(final AnyxmlSchemaNode leafNode, final String name,
- final ObjectNode properties, final ArrayNode required) {
+ final ObjectNode properties, final ArrayNode required) {
final ObjectNode property = JsonNodeFactory.instance.objectNode();
final String leafDescription = leafNode.getDescription().orElse("");
}
private String processTypeDef(final TypeDefinition<?> leafTypeDef, final DataSchemaNode node,
- final ObjectNode property, final SchemaInferenceStack stack,
- final ObjectNode definitions, final DefinitionNames definitionNames,
- final OAversion oaversion) {
+ final ObjectNode property, final SchemaInferenceStack stack, final ObjectNode definitions,
+ final DefinitionNames definitionNames, final OAversion oaversion) {
final String jsonType;
if (leafTypeDef instanceof BinaryTypeDefinition) {
jsonType = processBinaryType(property);
putIfNonNull(property, TYPE_KEY, jsonType);
if (leafTypeDef.getDefaultValue().isPresent()) {
final Object defaultValue = leafTypeDef.getDefaultValue().get();
- if (defaultValue instanceof String) {
- final String stringDefaultValue = (String) defaultValue;
+ if (defaultValue instanceof String stringDefaultValue) {
if (leafTypeDef instanceof BooleanTypeDefinition) {
setDefaultValue(property, Boolean.valueOf(stringDefaultValue));
} else if (leafTypeDef instanceof DecimalTypeDefinition
}
private static String processEnumType(final EnumTypeDefinition enumLeafType,
- final ObjectNode property) {
+ final ObjectNode property) {
final List<EnumPair> enumPairs = enumLeafType.getValues();
final ArrayNode enumNames = new ArrayNode(JsonNodeFactory.instance);
for (final EnumPair enumPair : enumPairs) {
}
private String processIdentityRefType(final IdentityrefTypeDefinition leafTypeDef, final ObjectNode property,
- final ObjectNode definitions, final DefinitionNames definitionNames,
- final OAversion oaversion, final EffectiveModelContext schemaContext) {
+ final ObjectNode definitions, final DefinitionNames definitionNames, final OAversion oaversion,
+ final EffectiveModelContext schemaContext) {
final String definitionName;
if (isImported(leafTypeDef)) {
definitionName = addImportedIdentity(leafTypeDef, definitions, definitionNames, schemaContext);
}
private static String addImportedIdentity(final IdentityrefTypeDefinition leafTypeDef,
- final ObjectNode definitions, final DefinitionNames definitionNames,
- final EffectiveModelContext context) {
+ final ObjectNode definitions, final DefinitionNames definitionNames, final EffectiveModelContext context) {
final IdentitySchemaNode idNode = leafTypeDef.getIdentities().iterator().next();
final String identityName = idNode.getQName().getLocalName();
if (!definitionNames.isListedNode(idNode)) {
return !leafTypeDef.getQName().getModule().equals(topLevelModule.getQNameModule());
}
- private static String processBitsType(final BitsTypeDefinition bitsType,
- final ObjectNode property) {
+ private static String processBitsType(final BitsTypeDefinition bitsType, final ObjectNode property) {
property.put(MIN_ITEMS, 0);
property.put(UNIQUE_ITEMS_KEY, true);
final ArrayNode enumNames = new ArrayNode(JsonNodeFactory.instance);
}
private static String processStringType(final TypeDefinition<?> stringType, final ObjectNode property,
- final String nodeName) {
+ final String nodeName) {
StringTypeDefinition type = (StringTypeDefinition) stringType;
Optional<LengthConstraint> lengthConstraints = ((StringTypeDefinition) stringType).getLengthConstraint();
while (lengthConstraints.isEmpty() && type.getBaseType() != null) {
final PatternConstraint pattern = type.getPatternConstraints().iterator().next();
String regex = pattern.getJavaPatternString();
regex = regex.substring(1, regex.length() - 1);
+ // Escape special characters to prevent issues inside Generex.
+ regex = AUTOMATON_SPECIAL_CHARACTERS.matcher(regex).replaceAll("\\\\$0");
String defaultValue = "";
try {
final Generex generex = new Generex(regex);
private static String processNumberType(final RangeRestrictedTypeDefinition<?, ?> leafTypeDef,
final ObjectNode property) {
- final Optional<Number> maybeLower = ((RangeRestrictedTypeDefinition<?, ?>) leafTypeDef).getRangeConstraint()
+ final Optional<Number> maybeLower = leafTypeDef.getRangeConstraint()
.map(RangeConstraint::getAllowedRanges).map(RangeSet::span).map(Range::lowerEndpoint);
if (isHexadecimalOrOctal(leafTypeDef)) {
}
if (leafTypeDef instanceof DecimalTypeDefinition) {
- maybeLower.ifPresent(number -> setDefaultValue(property, (BigDecimal) number));
+ maybeLower.ifPresent(number -> setDefaultValue(property, ((Decimal64) number).decimalValue()));
return NUMBER_TYPE;
}
if (leafTypeDef instanceof Uint8TypeDefinition
private static boolean isHexadecimalOrOctal(final RangeRestrictedTypeDefinition<?, ?> typeDef) {
final Optional<?> optDefaultValue = typeDef.getDefaultValue();
if (optDefaultValue.isPresent()) {
- final String defaultValue = (String)optDefaultValue.get();
+ final String defaultValue = (String) optDefaultValue.get();
return defaultValue.startsWith("0") || defaultValue.startsWith("-0");
}
return false;
}
private static String processInstanceIdentifierType(final DataSchemaNode node, final ObjectNode property,
- final EffectiveModelContext schemaContext) {
+ final EffectiveModelContext schemaContext) {
// create example instance-identifier to the first container of node's module if exists or leave it empty
final var module = schemaContext.findModule(node.getQName().getModule());
if (module.isPresent()) {