use of org.opendaylight.restconf.common.context.InstanceIdentifierContext in project netconf by opendaylight.
the class XmlNormalizedNodeBodyWriter method writeNormalizedNode.
private static void writeNormalizedNode(final XMLStreamWriter xmlWriter, final InstanceIdentifierContext<?> pathContext, final NormalizedNode data, final DepthParam depth, final List<Set<QName>> fields) throws IOException {
final RestconfNormalizedNodeWriter nnWriter;
final EffectiveModelContext schemaCtx = pathContext.getSchemaContext();
if (pathContext.getSchemaNode() instanceof RpcDefinition) {
/*
* RpcDefinition is not supported as initial codec in XMLStreamWriter,
* so we need to emit initial output declaration..
*/
final RpcDefinition rpc = (RpcDefinition) pathContext.getSchemaNode();
final SchemaPath rpcPath = SchemaPath.of(Absolute.of(rpc.getQName(), rpc.getOutput().getQName()));
nnWriter = createNormalizedNodeWriter(xmlWriter, schemaCtx, rpcPath, depth, fields);
writeElements(xmlWriter, nnWriter, (ContainerNode) data);
} else if (pathContext.getSchemaNode() instanceof ActionDefinition) {
/*
* ActionDefinition is not supported as initial codec in XMLStreamWriter,
* so we need to emit initial output declaration..
*/
final ActionDefinition actDef = (ActionDefinition) pathContext.getSchemaNode();
final List<QName> qNames = pathContext.getInstanceIdentifier().getPathArguments().stream().filter(arg -> !(arg instanceof YangInstanceIdentifier.NodeIdentifierWithPredicates)).filter(arg -> !(arg instanceof YangInstanceIdentifier.AugmentationIdentifier)).map(PathArgument::getNodeType).collect(Collectors.toList());
qNames.add(actDef.getQName());
qNames.add(actDef.getOutput().getQName());
final SchemaPath actPath = SchemaPath.of(Absolute.of(qNames));
nnWriter = createNormalizedNodeWriter(xmlWriter, schemaCtx, actPath, depth, fields);
writeElements(xmlWriter, nnWriter, (ContainerNode) data);
} else {
final boolean isRoot = pathContext.getInstanceIdentifier().isEmpty();
if (isRoot) {
nnWriter = createNormalizedNodeWriter(xmlWriter, schemaCtx, SchemaPath.ROOT, depth, fields);
} else {
final List<QName> qNames = pathContext.getInstanceIdentifier().getPathArguments().stream().filter(arg -> !(arg instanceof YangInstanceIdentifier.NodeIdentifierWithPredicates)).filter(arg -> !(arg instanceof YangInstanceIdentifier.AugmentationIdentifier)).map(PathArgument::getNodeType).collect(Collectors.toList());
final SchemaPath path = SchemaPath.of(Absolute.of(qNames));
nnWriter = createNormalizedNodeWriter(xmlWriter, schemaCtx, path.getParent(), depth, fields);
}
if (data instanceof MapEntryNode) {
// Restconf allows returning one list item. We need to wrap it
// in map node in order to serialize it properly
nnWriter.write(ImmutableNodes.mapNodeBuilder(data.getIdentifier().getNodeType()).addChild((MapEntryNode) data).build());
} else if (isRoot) {
if (data instanceof ContainerNode && ((ContainerNode) data).isEmpty()) {
writeEmptyDataNode(xmlWriter, data);
} else {
writeAndWrapInDataNode(xmlWriter, nnWriter, data);
}
} else {
nnWriter.write(data);
}
}
nnWriter.flush();
}
use of org.opendaylight.restconf.common.context.InstanceIdentifierContext in project netconf by opendaylight.
the class JsonPatchBodyReader method readEditDefinition.
/**
* Read one patch edit object from Json input.
*
* @param edit PatchEdit instance to be filled with read data
* @param in JsonReader reader
* @param path InstanceIdentifierContext path context
* @throws IOException if operation fails
*/
private void readEditDefinition(@NonNull final PatchEdit edit, @NonNull final JsonReader in, @NonNull final InstanceIdentifierContext<?> path) throws IOException {
String deferredValue = null;
in.beginObject();
while (in.hasNext()) {
final String editDefinition = in.nextName();
switch(editDefinition) {
case "edit-id":
edit.setId(in.nextString());
break;
case "operation":
edit.setOperation(PatchEditOperation.valueOf(in.nextString().toUpperCase(Locale.ROOT)));
break;
case "target":
// target can be specified completely in request URI
final String target = in.nextString();
final SchemaInferenceStack stack = SchemaInferenceStack.of(path.getSchemaContext());
if (target.equals("/")) {
edit.setTarget(path.getInstanceIdentifier());
edit.setTargetInference(stack.toInference());
} else {
edit.setTarget(ParserIdentifier.parserPatchTarget(path, target));
edit.getTarget().getPathArguments().stream().filter(arg -> !(arg instanceof YangInstanceIdentifier.NodeIdentifierWithPredicates)).filter(arg -> !(arg instanceof YangInstanceIdentifier.AugmentationIdentifier)).forEach(p -> stack.enterSchemaTree(p.getNodeType()));
stack.exit();
edit.setTargetInference(stack.toInference());
}
break;
case "value":
checkArgument(edit.getData() == null && deferredValue == null, "Multiple value entries found");
if (edit.getTargetInference() == null) {
// save data defined in value node for next (later) processing, because target needs to be read
// always first and there is no ordering in Json input
deferredValue = readValueNode(in);
} else {
// We have a target schema node, reuse this reader without buffering the value.
edit.setData(readEditData(in, edit.getTargetInference(), path));
}
break;
default:
// FIXME: this does not look right, as it can wreck our logic
break;
}
}
in.endObject();
if (deferredValue != null) {
// read saved data to normalized node when target schema is already known
edit.setData(readEditData(new JsonReader(new StringReader(deferredValue)), edit.getTargetInference(), path));
}
}
use of org.opendaylight.restconf.common.context.InstanceIdentifierContext in project netconf by opendaylight.
the class XmlPatchBodyReader method parse.
private static PatchContext parse(final InstanceIdentifierContext<?> pathContext, final Document doc) throws XMLStreamException, IOException, ParserConfigurationException, SAXException, URISyntaxException {
final List<PatchEntity> resultCollection = new ArrayList<>();
final String patchId = doc.getElementsByTagName("patch-id").item(0).getFirstChild().getNodeValue();
final NodeList editNodes = doc.getElementsByTagName("edit");
for (int i = 0; i < editNodes.getLength(); i++) {
DataSchemaNode schemaNode = (DataSchemaNode) pathContext.getSchemaNode();
final Element element = (Element) editNodes.item(i);
final String operation = element.getElementsByTagName("operation").item(0).getFirstChild().getNodeValue();
final PatchEditOperation oper = PatchEditOperation.valueOf(operation.toUpperCase(Locale.ROOT));
final String editId = element.getElementsByTagName("edit-id").item(0).getFirstChild().getNodeValue();
final String target = element.getElementsByTagName("target").item(0).getFirstChild().getNodeValue();
final List<Element> values = readValueNodes(element, oper);
final Element firstValueElement = values != null ? values.get(0) : null;
// find complete path to target and target schema node
// target can be also empty (only slash)
YangInstanceIdentifier targetII;
final SchemaNode targetNode;
final Inference inference;
if (target.equals("/")) {
targetII = pathContext.getInstanceIdentifier();
targetNode = pathContext.getSchemaContext();
inference = Inference.ofDataTreePath(pathContext.getSchemaContext(), schemaNode.getQName());
} else {
// interpret as simple context
targetII = ParserIdentifier.parserPatchTarget(pathContext, target);
// move schema node
schemaNode = verifyNotNull(DataSchemaContextTree.from(pathContext.getSchemaContext()).findChild(targetII).orElseThrow().getDataSchemaNode());
final SchemaInferenceStack stack = SchemaInferenceStack.of(pathContext.getSchemaContext());
targetII.getPathArguments().stream().filter(arg -> !(arg instanceof YangInstanceIdentifier.NodeIdentifierWithPredicates)).filter(arg -> !(arg instanceof YangInstanceIdentifier.AugmentationIdentifier)).forEach(p -> stack.enterSchemaTree(p.getNodeType()));
final EffectiveStatement<?, ?> parentStmt = stack.exit();
verify(parentStmt instanceof SchemaNode, "Unexpected parent %s", parentStmt);
targetNode = (SchemaNode) parentStmt;
inference = stack.toInference();
}
if (targetNode == null) {
LOG.debug("Target node {} not found in path {} ", target, pathContext.getSchemaNode());
throw new RestconfDocumentedException("Error parsing input", ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE);
}
if (oper.isWithValue()) {
final NormalizedNode parsed;
if (schemaNode instanceof ContainerSchemaNode || schemaNode instanceof ListSchemaNode) {
final NormalizedNodeResult resultHolder = new NormalizedNodeResult();
final NormalizedNodeStreamWriter writer = ImmutableNormalizedNodeStreamWriter.from(resultHolder);
final XmlParserStream xmlParser = XmlParserStream.create(writer, inference);
xmlParser.traverse(new DOMSource(firstValueElement));
parsed = resultHolder.getResult();
} else {
parsed = null;
}
// for lists allow to manipulate with list items through their parent
if (targetII.getLastPathArgument() instanceof NodeIdentifierWithPredicates) {
targetII = targetII.getParent();
}
resultCollection.add(new PatchEntity(editId, oper, targetII, parsed));
} else {
resultCollection.add(new PatchEntity(editId, oper, targetII));
}
}
return new PatchContext(pathContext, ImmutableList.copyOf(resultCollection), patchId);
}
use of org.opendaylight.restconf.common.context.InstanceIdentifierContext in project netconf by opendaylight.
the class RestconfStreamsSubscriptionServiceImpl method prepareIIDSubsStreamOutput.
/**
* Prepare InstanceIdentifierContext for Location leaf.
*
* @param schemaHandler Schema context handler.
* @return InstanceIdentifier of Location leaf.
*/
private static InstanceIdentifierContext<?> prepareIIDSubsStreamOutput(final SchemaContextHandler schemaHandler) {
final Optional<Module> module = schemaHandler.get().findModule(NOTIFI_QNAME.getModule());
checkState(module.isPresent());
final DataSchemaNode notify = module.get().dataChildByName(NOTIFI_QNAME);
checkState(notify instanceof ContainerSchemaNode, "Unexpected non-container %s", notify);
final DataSchemaNode location = ((ContainerSchemaNode) notify).dataChildByName(LOCATION_QNAME);
checkState(location != null, "Missing location");
return new InstanceIdentifierContext<SchemaNode>(LOCATION_PATH, location, null, schemaHandler.get());
}
use of org.opendaylight.restconf.common.context.InstanceIdentifierContext in project netconf by opendaylight.
the class ControllerContext method collectPathArguments.
@SuppressFBWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE", justification = "Unrecognised NullableDecl")
private InstanceIdentifierContext<?> collectPathArguments(final InstanceIdentifierBuilder builder, final List<String> strings, final DataNodeContainer parentNode, final DOMMountPoint mountPoint, final boolean returnJustMountPoint) {
requireNonNull(strings);
if (parentNode == null) {
return null;
}
if (strings.isEmpty()) {
return createContext(builder.build(), (DataSchemaNode) parentNode, mountPoint, mountPoint != null ? getModelContext(mountPoint) : globalSchema);
}
final String head = strings.iterator().next();
if (head.isEmpty()) {
final List<String> remaining = strings.subList(1, strings.size());
return collectPathArguments(builder, remaining, parentNode, mountPoint, returnJustMountPoint);
}
final String nodeName = toNodeName(head);
final String moduleName = toModuleName(head);
DataSchemaNode targetNode = null;
if (!Strings.isNullOrEmpty(moduleName)) {
if (MOUNT_MODULE.equals(moduleName) && MOUNT_NODE.equals(nodeName)) {
if (mountPoint != null) {
throw new RestconfDocumentedException("Restconf supports just one mount point in URI.", ErrorType.APPLICATION, ErrorTag.OPERATION_NOT_SUPPORTED);
}
if (mountService == null) {
throw new RestconfDocumentedException("MountService was not found. Finding behind mount points does not work.", ErrorType.APPLICATION, ErrorTag.OPERATION_NOT_SUPPORTED);
}
final YangInstanceIdentifier partialPath = dataNormalizer.toNormalized(builder.build());
final Optional<DOMMountPoint> mountOpt = mountService.getMountPoint(partialPath);
if (mountOpt.isEmpty()) {
LOG.debug("Instance identifier to missing mount point: {}", partialPath);
throw new RestconfDocumentedException("Mount point does not exist.", ErrorType.PROTOCOL, ErrorTag.DATA_MISSING);
}
final DOMMountPoint mount = mountOpt.get();
final EffectiveModelContext mountPointSchema = getModelContext(mount);
if (mountPointSchema == null) {
throw new RestconfDocumentedException("Mount point does not contain any schema with modules.", ErrorType.APPLICATION, ErrorTag.UNKNOWN_ELEMENT);
}
if (returnJustMountPoint || strings.size() == 1) {
return new InstanceIdentifierContext<>(YangInstanceIdentifier.empty(), mountPointSchema, mount, mountPointSchema);
}
final String moduleNameBehindMountPoint = toModuleName(strings.get(1));
if (moduleNameBehindMountPoint == null) {
throw new RestconfDocumentedException("First node after mount point in URI has to be in format \"moduleName:nodeName\"", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
}
final Iterator<? extends Module> it = mountPointSchema.findModules(moduleNameBehindMountPoint).iterator();
if (!it.hasNext()) {
throw new RestconfDocumentedException("\"" + moduleNameBehindMountPoint + "\" module does not exist in mount point.", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT);
}
final List<String> subList = strings.subList(1, strings.size());
return collectPathArguments(YangInstanceIdentifier.builder(), subList, it.next(), mount, returnJustMountPoint);
}
Module module = null;
if (mountPoint == null) {
checkPreconditions();
module = globalSchema.findModules(moduleName).stream().findFirst().orElse(null);
if (module == null) {
throw new RestconfDocumentedException("\"" + moduleName + "\" module does not exist.", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT);
}
} else {
final EffectiveModelContext schemaContext = getModelContext(mountPoint);
if (schemaContext != null) {
module = schemaContext.findModules(moduleName).stream().findFirst().orElse(null);
} else {
module = null;
}
if (module == null) {
throw new RestconfDocumentedException("\"" + moduleName + "\" module does not exist in mount point.", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT);
}
}
targetNode = findInstanceDataChildByNameAndNamespace(parentNode, nodeName, module.getNamespace());
if (targetNode == null && parentNode instanceof Module) {
final RpcDefinition rpc;
if (mountPoint == null) {
rpc = getRpcDefinition(head, module.getRevision());
} else {
final String rpcName = toNodeName(head);
rpc = getRpcDefinition(module, rpcName);
}
if (rpc != null) {
return new InstanceIdentifierContext<>(builder.build(), rpc, mountPoint, mountPoint != null ? getModelContext(mountPoint) : globalSchema);
}
}
if (targetNode == null) {
throw new RestconfDocumentedException("URI has bad format. Possible reasons:\n" + " 1. \"" + head + "\" was not found in parent data node.\n" + " 2. \"" + head + "\" is behind mount point. Then it should be in format \"/" + MOUNT + "/" + head + "\".", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
}
} else {
final List<DataSchemaNode> potentialSchemaNodes = findInstanceDataChildrenByName(parentNode, nodeName);
if (potentialSchemaNodes.size() > 1) {
final StringBuilder strBuilder = new StringBuilder();
for (final DataSchemaNode potentialNodeSchema : potentialSchemaNodes) {
strBuilder.append(" ").append(potentialNodeSchema.getQName().getNamespace()).append("\n");
}
throw new RestconfDocumentedException("URI has bad format. Node \"" + nodeName + "\" is added as augment from more than one module. " + "Therefore the node must have module name " + "and it has to be in format \"moduleName:nodeName\"." + "\nThe node is added as augment from modules with namespaces:\n" + strBuilder.toString(), ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
}
if (potentialSchemaNodes.isEmpty()) {
throw new RestconfDocumentedException("\"" + nodeName + "\" in URI was not found in parent data node", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT);
}
targetNode = potentialSchemaNodes.iterator().next();
}
if (!isListOrContainer(targetNode)) {
throw new RestconfDocumentedException("URI has bad format. Node \"" + head + "\" must be Container or List yang type.", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
}
int consumed = 1;
if (targetNode instanceof ListSchemaNode) {
final ListSchemaNode listNode = (ListSchemaNode) targetNode;
final int keysSize = listNode.getKeyDefinition().size();
if (strings.size() - consumed < keysSize) {
throw new RestconfDocumentedException("Missing key for list \"" + listNode.getQName().getLocalName() + "\".", ErrorType.PROTOCOL, ErrorTag.DATA_MISSING);
}
final List<String> uriKeyValues = strings.subList(consumed, consumed + keysSize);
final HashMap<QName, Object> keyValues = new HashMap<>();
int index = 0;
for (final QName key : listNode.getKeyDefinition()) {
{
final String uriKeyValue = uriKeyValues.get(index);
if (uriKeyValue.equals(NULL_VALUE)) {
throw new RestconfDocumentedException("URI has bad format. List \"" + listNode.getQName().getLocalName() + "\" cannot contain \"null\" value as a key.", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
}
addKeyValue(keyValues, listNode.getDataChildByName(key), uriKeyValue, mountPoint);
index++;
}
}
consumed = consumed + index;
builder.nodeWithKey(targetNode.getQName(), keyValues);
} else {
builder.node(targetNode.getQName());
}
if (targetNode instanceof DataNodeContainer) {
final List<String> remaining = strings.subList(consumed, strings.size());
return collectPathArguments(builder, remaining, (DataNodeContainer) targetNode, mountPoint, returnJustMountPoint);
}
return createContext(builder.build(), targetNode, mountPoint, mountPoint != null ? getModelContext(mountPoint) : globalSchema);
}
Aggregations