use of org.opendaylight.yangtools.yang.model.api.DataNodeContainer in project netconf by opendaylight.
the class RestconfDocumentedExceptionMapper method toXMLResponseBody.
private static Object toXMLResponseBody(final NormalizedNodeContext errorsNode, final DataNodeContainer errorsSchemaNode) {
final InstanceIdentifierContext<?> pathContext = errorsNode.getInstanceIdentifierContext();
final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
final XMLStreamWriter xmlWriter;
try {
xmlWriter = XML_FACTORY.createXMLStreamWriter(outStream, StandardCharsets.UTF_8.name());
} catch (final XMLStreamException | FactoryConfigurationError e) {
throw new IllegalStateException(e);
}
NormalizedNode data = errorsNode.getData();
SchemaPath schemaPath;
boolean isDataRoot = false;
if (pathContext.getSchemaNode() instanceof SchemaContext) {
isDataRoot = true;
schemaPath = SchemaPath.ROOT;
} else {
final List<QName> qNames = pathContext.getInstanceIdentifier().getPathArguments().stream().filter(arg -> !(arg instanceof NodeIdentifierWithPredicates)).filter(arg -> !(arg instanceof AugmentationIdentifier)).map(PathArgument::getNodeType).collect(Collectors.toList());
schemaPath = SchemaPath.of(Absolute.of(qNames)).getParent();
}
final NormalizedNodeStreamWriter xmlStreamWriter = XMLStreamNormalizedNodeStreamWriter.create(xmlWriter, pathContext.getSchemaContext(), schemaPath);
// We create a delegating writer to special-case error-info as error-info is defined as an empty
// container in the restconf yang schema but we create a leaf node so we can output it. The delegate
// stream writer validates the node type against the schema and thus will expect a LeafSchemaNode but
// the schema has a ContainerSchemaNode so, to avoid an error, we override the leafNode behavior
// for error-info.
final NormalizedNodeStreamWriter streamWriter = new ForwardingNormalizedNodeStreamWriter() {
private boolean inOurLeaf;
@Override
protected NormalizedNodeStreamWriter delegate() {
return xmlStreamWriter;
}
@Override
public void startLeafNode(final NodeIdentifier name) throws IOException {
if (name.getNodeType().equals(RestConfModule.ERROR_INFO_QNAME)) {
String ns = RestConfModule.ERROR_INFO_QNAME.getNamespace().toString();
try {
xmlWriter.writeStartElement(XMLConstants.DEFAULT_NS_PREFIX, RestConfModule.ERROR_INFO_QNAME.getLocalName(), ns);
} catch (XMLStreamException e) {
throw new IOException("Error writing error-info", e);
}
inOurLeaf = true;
} else {
super.startLeafNode(name);
}
}
@Override
public void scalarValue(final Object value) throws IOException {
if (inOurLeaf) {
try {
xmlWriter.writeCharacters(value.toString());
} catch (XMLStreamException e) {
throw new IOException("Error writing error-info", e);
}
} else {
super.scalarValue(value);
}
}
@Override
public void endNode() throws IOException {
if (inOurLeaf) {
try {
xmlWriter.writeEndElement();
} catch (XMLStreamException e) {
throw new IOException("Error writing error-info", e);
}
inOurLeaf = false;
} else {
super.endNode();
}
}
};
final NormalizedNodeWriter nnWriter = NormalizedNodeWriter.forStreamWriter(streamWriter);
try {
if (isDataRoot) {
writeRootElement(xmlWriter, nnWriter, (ContainerNode) data);
} else {
if (data instanceof MapEntryNode) {
// Restconf allows returning one list item. We need to wrap it
// in map node in order to serialize it properly
data = ImmutableNodes.mapNodeBuilder(data.getIdentifier().getNodeType()).addChild((MapEntryNode) data).build();
}
nnWriter.write(data);
nnWriter.flush();
}
} catch (final IOException e) {
LOG.warn("Error writing error response body.", e);
}
return outStream.toString(StandardCharsets.UTF_8);
}
use of org.opendaylight.yangtools.yang.model.api.DataNodeContainer in project netconf by opendaylight.
the class XmlNormalizedNodeBodyReader method findPathToSchemaNodeByName.
private static Deque<Object> findPathToSchemaNodeByName(final DataSchemaNode schemaNode, final String elementName, final String namespace) {
final Deque<Object> result = new ArrayDeque<>();
final ArrayList<ChoiceSchemaNode> choiceSchemaNodes = new ArrayList<>();
for (final DataSchemaNode child : ((DataNodeContainer) schemaNode).getChildNodes()) {
if (child instanceof ChoiceSchemaNode) {
choiceSchemaNodes.add((ChoiceSchemaNode) child);
} else if (child.getQName().getLocalName().equalsIgnoreCase(elementName) && child.getQName().getNamespace().toString().equalsIgnoreCase(namespace)) {
// add child to result
result.push(child);
// find augmentation
if (child.isAugmenting()) {
final AugmentationSchemaNode augment = findCorrespondingAugment(schemaNode, child);
if (augment != null) {
result.push(augment);
}
}
// return result
return result;
}
}
for (final ChoiceSchemaNode choiceNode : choiceSchemaNodes) {
for (final CaseSchemaNode caseNode : choiceNode.getCases()) {
final Deque<Object> resultFromRecursion = findPathToSchemaNodeByName(caseNode, elementName, namespace);
if (!resultFromRecursion.isEmpty()) {
resultFromRecursion.push(choiceNode);
if (choiceNode.isAugmenting()) {
final AugmentationSchemaNode augment = findCorrespondingAugment(schemaNode, choiceNode);
if (augment != null) {
resultFromRecursion.push(augment);
}
}
return resultFromRecursion;
}
}
}
return result;
}
use of org.opendaylight.yangtools.yang.model.api.DataNodeContainer in project netconf by opendaylight.
the class BaseYangSwaggerGenerator method createPath.
private String createPath(final DataSchemaNode schemaNode, final ArrayNode pathParams, final OAversion oaversion, final String localName) {
final StringBuilder path = new StringBuilder();
path.append(localName);
if (schemaNode instanceof ListSchemaNode) {
final ListPathBuilder keyBuilder = newListPathBuilder();
for (final QName listKey : ((ListSchemaNode) schemaNode).getKeyDefinition()) {
final String paramName = createUniquePathParamName(listKey.getLocalName(), pathParams);
final String pathParamIdentifier = keyBuilder.nextParamIdentifier(paramName);
path.append(pathParamIdentifier);
final ObjectNode pathParam = JsonNodeFactory.instance.objectNode();
pathParam.put("name", paramName);
((DataNodeContainer) schemaNode).findDataChildByName(listKey).flatMap(DataSchemaNode::getDescription).ifPresent(desc -> pathParam.put("description", desc));
final ObjectNode typeParent = getTypeParentNode(pathParam, oaversion);
typeParent.put("type", "string");
pathParam.put("in", "path");
pathParam.put("required", true);
pathParams.add(pathParam);
}
}
return path.toString();
}
use of org.opendaylight.yangtools.yang.model.api.DataNodeContainer in project netconf by opendaylight.
the class DefinitionGenerator method processModule.
private void processModule(final Module module, final ObjectNode definitions, final DefinitionNames definitionNames, final EffectiveModelContext schemaContext, final OAversion oaversion) {
final ObjectNode definition = JsonNodeFactory.instance.objectNode();
final ObjectNode properties = JsonNodeFactory.instance.objectNode();
final ArrayNode required = JsonNodeFactory.instance.arrayNode();
final String moduleName = module.getName();
final String definitionName = moduleName + MODULE_NAME_SUFFIX;
final SchemaInferenceStack stack = SchemaInferenceStack.of(schemaContext);
for (final DataSchemaNode node : module.getChildNodes()) {
stack.enterSchemaTree(node.getQName());
final String localName = node.getQName().getLocalName();
if (node.isConfiguration()) {
if (node instanceof ContainerSchemaNode || node instanceof ListSchemaNode) {
for (final DataSchemaNode childNode : ((DataNodeContainer) node).getChildNodes()) {
final ObjectNode childNodeProperties = JsonNodeFactory.instance.objectNode();
final String ref = getAppropriateModelPrefix(oaversion) + moduleName + CONFIG + "_" + localName + definitionNames.getDiscriminator(node);
if (node instanceof ListSchemaNode) {
childNodeProperties.put(TYPE_KEY, ARRAY_TYPE);
final ObjectNode items = JsonNodeFactory.instance.objectNode();
items.put(REF_KEY, ref);
childNodeProperties.set(ITEMS_KEY, items);
childNodeProperties.put(DESCRIPTION_KEY, childNode.getDescription().orElse(""));
childNodeProperties.put(TITLE_KEY, localName + CONFIG);
} else {
/*
Description can't be added, because nothing allowed alongside $ref.
allOf is not an option, because ServiceNow can't parse it.
*/
childNodeProperties.put(REF_KEY, ref);
}
// 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);
}
}
}
stack.exit();
}
definition.put(TITLE_KEY, definitionName);
definition.put(TYPE_KEY, OBJECT_TYPE);
definition.set(PROPERTIES_KEY, properties);
definition.put(DESCRIPTION_KEY, module.getDescription().orElse(""));
setRequiredIfNotEmpty(definition, required);
definitions.set(definitionName, definition);
}
use of org.opendaylight.yangtools.yang.model.api.DataNodeContainer in project netconf by opendaylight.
the class BaseYangSwaggerGenerator method addPaths.
private void addPaths(final DataSchemaNode node, final Optional<String> deviceName, final String moduleName, final ObjectNode paths, final ArrayNode parentPathParams, final EffectiveModelContext schemaContext, final boolean isConfig, final String parentName, final DefinitionNames definitionNames, final URIType uriType, final OAversion oaversion, final String resourcePath) {
LOG.debug("Adding path: [{}]", resourcePath);
final ArrayNode pathParams = JsonUtil.copy(parentPathParams);
Iterable<? extends DataSchemaNode> childSchemaNodes = Collections.emptySet();
if (node instanceof ListSchemaNode || node instanceof ContainerSchemaNode) {
final DataNodeContainer dataNodeContainer = (DataNodeContainer) node;
childSchemaNodes = dataNodeContainer.getChildNodes();
}
final ObjectNode path = JsonNodeFactory.instance.objectNode();
path.setAll(operations(node, moduleName, deviceName, pathParams, isConfig, parentName, definitionNames, uriType, oaversion));
paths.set(resourcePath, path);
if (uriType.equals(URIType.RFC8040)) {
((ActionNodeContainer) node).getActions().forEach(actionDef -> {
final String resolvedPath = "rests/operations" + resourcePath.substring(11) + "/" + resolvePathArgumentsName(actionDef.getQName(), node.getQName(), schemaContext);
addOperations(actionDef, moduleName, deviceName, paths, parentName, definitionNames, oaversion, resolvedPath);
});
}
for (final DataSchemaNode childNode : childSchemaNodes) {
if (childNode instanceof ListSchemaNode || childNode instanceof ContainerSchemaNode) {
final String newParent = parentName + "_" + node.getQName().getLocalName();
final String localName = resolvePathArgumentsName(childNode.getQName(), node.getQName(), schemaContext);
final String newResourcePath = resourcePath + "/" + createPath(childNode, pathParams, oaversion, localName);
if (uriType.equals(URIType.RFC8040)) {
final boolean newIsConfig = isConfig && childNode.isConfiguration();
addPaths(childNode, deviceName, moduleName, paths, pathParams, schemaContext, newIsConfig, newParent, definitionNames, uriType, oaversion, newResourcePath);
} else {
if (!isConfig || childNode.isConfiguration()) {
addPaths(childNode, deviceName, moduleName, paths, pathParams, schemaContext, isConfig, newParent, definitionNames, uriType, oaversion, newResourcePath);
}
}
}
}
}
Aggregations