import com.google.common.base.Splitter;
import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
+import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.Deque;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.ws.rs.core.Response.Status;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
import org.opendaylight.mdsal.dom.api.DOMMountPoint;
import org.opendaylight.mdsal.dom.api.DOMMountPointService;
import org.opendaylight.mdsal.dom.api.DOMSchemaService;
import org.opendaylight.yangtools.yang.common.ErrorTag;
import org.opendaylight.yangtools.yang.common.ErrorType;
import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
import org.opendaylight.yangtools.yang.common.Revision;
import org.opendaylight.yangtools.yang.common.XMLNamespace;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
}
- final InstanceIdentifierBuilder builder = YangInstanceIdentifier.builder();
final Collection<? extends Module> latestModule = globalSchema.findModules(startModule);
-
if (latestModule.isEmpty()) {
throw new RestconfDocumentedException("The module named '" + startModule + "' does not exist.",
ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT);
}
- final InstanceIdentifierContext iiWithSchemaNode =
- collectPathArguments(builder, pathArgs, latestModule.iterator().next(), null, toMountPointIdentifier);
+ final InstanceIdentifierContext iiWithSchemaNode = collectPathArguments(YangInstanceIdentifier.builder(),
+ new ArrayDeque<>(), pathArgs, latestModule.iterator().next(), null, toMountPointIdentifier);
if (iiWithSchemaNode == null) {
throw new RestconfDocumentedException("URI has bad format", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
public String findModuleNameByNamespace(final XMLNamespace namespace) {
checkPreconditions();
- final Module module = this.findModuleByNamespace(namespace);
+ final Module module = findModuleByNamespace(namespace);
return module == null ? null : module.getName();
}
}
public XMLNamespace findNamespaceByModuleName(final String moduleName) {
- final Module module = this.findModuleByName(moduleName);
+ final Module module = findModuleByName(moduleName);
return module == null ? null : module.getNamespace();
}
return findModuleByNameAndRevision(Draft02.RestConfModule.NAME, Revision.of(Draft02.RestConfModule.REVISION));
}
- public DataSchemaNode getRestconfModuleErrorsSchemaNode() {
- final Module restconfModule = getRestconfModule();
- if (restconfModule == null) {
+ public Entry<SchemaInferenceStack, ContainerSchemaNode> getRestconfModuleErrorsSchemaNode() {
+ checkPreconditions();
+
+ final var schema = globalSchema;
+ final var namespace = QNameModule.create(XMLNamespace.of(Draft02.RestConfModule.NAMESPACE),
+ Revision.of(Draft02.RestConfModule.REVISION));
+ if (schema.findModule(namespace).isEmpty()) {
return null;
}
- final Collection<? extends GroupingDefinition> groupings = restconfModule.getGroupings();
-
- final Iterable<? extends GroupingDefinition> filteredGroups = Iterables.filter(groupings,
- g -> RestConfModule.ERRORS_GROUPING_SCHEMA_NODE.equals(g.getQName().getLocalName()));
-
- final GroupingDefinition restconfGrouping = Iterables.getFirst(filteredGroups, null);
-
- final List<DataSchemaNode> instanceDataChildrenByName = findInstanceDataChildrenByName(restconfGrouping,
- RestConfModule.ERRORS_CONTAINER_SCHEMA_NODE);
- return Iterables.getFirst(instanceDataChildrenByName, null);
+ final var stack = SchemaInferenceStack.of(globalSchema);
+ stack.enterGrouping(RestConfModule.ERRORS_QNAME);
+ final var stmt = stack.enterSchemaTree(RestConfModule.ERRORS_QNAME);
+ verify(stmt instanceof ContainerSchemaNode, "Unexpected statement %s", stmt);
+ return Map.entry(stack, (ContainerSchemaNode) stmt);
}
public DataSchemaNode getRestconfModuleRestConfSchemaNode(final Module inRestconfModule,
g -> RestConfModule.RESTCONF_GROUPING_SCHEMA_NODE.equals(g.getQName().getLocalName()));
final GroupingDefinition restconfGrouping = Iterables.getFirst(filteredGroups, null);
- final List<DataSchemaNode> instanceDataChildrenByName = findInstanceDataChildrenByName(restconfGrouping,
+ final var instanceDataChildrenByName = findInstanceDataChildrenByName(restconfGrouping,
RestConfModule.RESTCONF_CONTAINER_SCHEMA_NODE);
- final DataSchemaNode restconfContainer = Iterables.getFirst(instanceDataChildrenByName, null);
+ final DataSchemaNode restconfContainer = getFirst(instanceDataChildrenByName);
- if (RestConfModule.OPERATIONS_CONTAINER_SCHEMA_NODE.equals(schemaNodeName)) {
- final List<DataSchemaNode> instances = findInstanceDataChildrenByName(
- (DataNodeContainer) restconfContainer, RestConfModule.OPERATIONS_CONTAINER_SCHEMA_NODE);
- return Iterables.getFirst(instances, null);
- } else if (RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE.equals(schemaNodeName)) {
- final List<DataSchemaNode> instances = findInstanceDataChildrenByName(
+ if (RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE.equals(schemaNodeName)) {
+ final var instances = findInstanceDataChildrenByName(
(DataNodeContainer) restconfContainer, RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE);
- return Iterables.getFirst(instances, null);
+ return getFirst(instances);
} else if (RestConfModule.STREAM_LIST_SCHEMA_NODE.equals(schemaNodeName)) {
- List<DataSchemaNode> instances = findInstanceDataChildrenByName(
+ var instances = findInstanceDataChildrenByName(
(DataNodeContainer) restconfContainer, RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE);
- final DataSchemaNode modules = Iterables.getFirst(instances, null);
+ final DataSchemaNode modules = getFirst(instances);
instances = findInstanceDataChildrenByName((DataNodeContainer) modules,
RestConfModule.STREAM_LIST_SCHEMA_NODE);
- return Iterables.getFirst(instances, null);
+ return getFirst(instances);
} else if (RestConfModule.MODULES_CONTAINER_SCHEMA_NODE.equals(schemaNodeName)) {
- final List<DataSchemaNode> instances = findInstanceDataChildrenByName(
+ final var instances = findInstanceDataChildrenByName(
(DataNodeContainer) restconfContainer, RestConfModule.MODULES_CONTAINER_SCHEMA_NODE);
- return Iterables.getFirst(instances, null);
+ return getFirst(instances);
} else if (RestConfModule.MODULE_LIST_SCHEMA_NODE.equals(schemaNodeName)) {
- List<DataSchemaNode> instances = findInstanceDataChildrenByName(
+ var instances = findInstanceDataChildrenByName(
(DataNodeContainer) restconfContainer, RestConfModule.MODULES_CONTAINER_SCHEMA_NODE);
- final DataSchemaNode modules = Iterables.getFirst(instances, null);
+ final DataSchemaNode modules = getFirst(instances);
instances = findInstanceDataChildrenByName((DataNodeContainer) modules,
RestConfModule.MODULE_LIST_SCHEMA_NODE);
- return Iterables.getFirst(instances, null);
+ return getFirst(instances);
} else if (RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE.equals(schemaNodeName)) {
- final List<DataSchemaNode> instances = findInstanceDataChildrenByName(
+ final var instances = findInstanceDataChildrenByName(
(DataNodeContainer) restconfContainer, RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE);
- return Iterables.getFirst(instances, null);
+ return getFirst(instances);
}
return null;
}
+ public static @Nullable DataSchemaNode getFirst(final List<FoundChild> children) {
+ return children.isEmpty() ? null : children.get(0).child;
+ }
+
private static DataSchemaNode childByQName(final ChoiceSchemaNode container, final QName name) {
for (final CaseSchemaNode caze : container.getCases()) {
final DataSchemaNode ret = childByQName(caze, name);
@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) {
+ final Deque<QName> schemaPath, final List<String> strings, final DataNodeContainer parentNode,
+ final DOMMountPoint mountPoint, final boolean returnJustMountPoint) {
requireNonNull(strings);
if (parentNode == null) {
if (head.isEmpty()) {
final List<String> remaining = strings.subList(1, strings.size());
- return collectPathArguments(builder, remaining, parentNode, mountPoint, returnJustMountPoint);
+ return collectPathArguments(builder, schemaPath, remaining, parentNode, mountPoint, returnJustMountPoint);
}
final String nodeName = toNodeName(head);
}
final List<String> subList = strings.subList(1, strings.size());
- return collectPathArguments(YangInstanceIdentifier.builder(), subList, it.next(), mount,
- returnJustMountPoint);
+ return collectPathArguments(YangInstanceIdentifier.builder(), new ArrayDeque<>(), subList, it.next(),
+ mount, returnJustMountPoint);
}
Module module = null;
}
}
- 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) {
- final var ctx = mountPoint == null ? globalSchema : getModelContext(mountPoint);
- return InstanceIdentifierContext.ofRpcInput(ctx, rpc, mountPoint);
+ final var found = findInstanceDataChildByNameAndNamespace(parentNode, nodeName, module.getNamespace());
+ if (found == null) {
+ if (parentNode instanceof Module) {
+ final RpcDefinition rpc;
+ if (mountPoint == null) {
+ rpc = getRpcDefinition(head, module.getRevision());
+ } else {
+ rpc = getRpcDefinition(module, toNodeName(head));
+ }
+ if (rpc != null) {
+ final var ctx = mountPoint == null ? globalSchema : getModelContext(mountPoint);
+ return InstanceIdentifierContext.ofRpcInput(ctx, rpc, mountPoint);
+ }
}
- }
-
- 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);
+ + "\" 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);
}
+
+ targetNode = found.child;
+ schemaPath.addAll(found.intermediate);
+ schemaPath.add(targetNode.getQName());
} else {
- final List<DataSchemaNode> potentialSchemaNodes = findInstanceDataChildrenByName(parentNode, nodeName);
+ final var 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");
+ for (var potentialNodeSchema : potentialSchemaNodes) {
+ strBuilder.append(" ").append(potentialNodeSchema.child.getQName().getNamespace()).append("\n");
}
throw new RestconfDocumentedException(
ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT);
}
- targetNode = potentialSchemaNodes.iterator().next();
+ final var found = potentialSchemaNodes.get(0);
+ targetNode = found.child;
+ schemaPath.addAll(found.intermediate);
+ schemaPath.add(targetNode.getQName());
}
if (!isListOrContainer(targetNode)) {
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++;
+ 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);
}
+
+ final var keyChild = listNode.getDataChildByName(key);
+ schemaPath.addLast(keyChild.getQName());
+ addKeyValue(keyValues, schemaPath, keyChild, uriKeyValue, mountPoint);
+ schemaPath.removeLast();
+ index++;
}
consumed = consumed + index;
if (targetNode instanceof DataNodeContainer) {
final List<String> remaining = strings.subList(consumed, strings.size());
- return collectPathArguments(builder, remaining, (DataNodeContainer) targetNode, mountPoint,
+ return collectPathArguments(builder, schemaPath, remaining, (DataNodeContainer) targetNode, mountPoint,
returnJustMountPoint);
}
final DataSchemaNode dataSchemaNode, final DOMMountPoint mountPoint,
final EffectiveModelContext schemaContext) {
final var normalized = new DataNormalizer(schemaContext).toNormalized(instance);
-
- // FIXME: Verification before we trust this
- final var stack = normalized.getValue();
- if (!stack.isEmpty()) {
- final var stackPath = stack.toSchemaPath();
- final var nodePath = dataSchemaNode.getPath();
- verify(stackPath.equals(nodePath), "Mismatched path: expected %s got %s", nodePath, stackPath);
- } else {
- verify(dataSchemaNode.equals(schemaContext), "Unexpected node %s", dataSchemaNode);
- }
-
return InstanceIdentifierContext.ofPath(normalized.getValue(), dataSchemaNode, normalized.getKey(), mountPoint);
}
- public static DataSchemaNode findInstanceDataChildByNameAndNamespace(final DataNodeContainer container,
+ public static @Nullable FoundChild findInstanceDataChildByNameAndNamespace(final DataNodeContainer container,
final String name, final XMLNamespace namespace) {
requireNonNull(namespace);
- final Iterable<DataSchemaNode> result = Iterables.filter(findInstanceDataChildrenByName(container, name),
- node -> namespace.equals(node.getQName().getNamespace()));
- return Iterables.getFirst(result, null);
+ for (var node : findInstanceDataChildrenByName(container, name)) {
+ if (namespace.equals(node.child.getQName().getNamespace())) {
+ return node;
+ }
+ }
+ return null;
}
- public static List<DataSchemaNode> findInstanceDataChildrenByName(final DataNodeContainer container,
+ public static List<FoundChild> findInstanceDataChildrenByName(final DataNodeContainer container,
final String name) {
- final List<DataSchemaNode> instantiatedDataNodeContainers = new ArrayList<>();
+ final List<FoundChild> instantiatedDataNodeContainers = new ArrayList<>();
collectInstanceDataNodeContainers(instantiatedDataNodeContainers, requireNonNull(container),
- requireNonNull(name));
+ requireNonNull(name), List.of());
return instantiatedDataNodeContainers;
}
- private static void collectInstanceDataNodeContainers(final List<DataSchemaNode> potentialSchemaNodes,
- final DataNodeContainer container, final String name) {
-
- final Iterable<? extends DataSchemaNode> nodes = Iterables.filter(container.getChildNodes(),
- node -> name.equals(node.getQName().getLocalName()));
-
- // Can't combine this loop with the filter above because the filter is
- // lazily-applied by Iterables.filter.
- for (final DataSchemaNode potentialNode : nodes) {
- if (isInstantiatedDataSchema(potentialNode)) {
- potentialSchemaNodes.add(potentialNode);
+ private static void collectInstanceDataNodeContainers(final List<FoundChild> potentialSchemaNodes,
+ final DataNodeContainer container, final String name, final List<QName> intermediate) {
+ // We perform two iterations to retain breadth-first ordering
+ for (var child : container.getChildNodes()) {
+ if (name.equals(child.getQName().getLocalName()) && isInstantiatedDataSchema(child)) {
+ potentialSchemaNodes.add(new FoundChild(child, intermediate));
}
}
- final Iterable<ChoiceSchemaNode> choiceNodes = Iterables.filter(container.getChildNodes(),
- ChoiceSchemaNode.class);
- final Iterable<Collection<? extends CaseSchemaNode>> map = Iterables.transform(choiceNodes,
- ChoiceSchemaNode::getCases);
- for (final CaseSchemaNode caze : Iterables.concat(map)) {
- collectInstanceDataNodeContainers(potentialSchemaNodes, caze, name);
+ for (var child : container.getChildNodes()) {
+ if (child instanceof ChoiceSchemaNode) {
+ for (var caze : ((ChoiceSchemaNode) child).getCases()) {
+ collectInstanceDataNodeContainers(potentialSchemaNodes, caze, name,
+ ImmutableList.<QName>builderWithExpectedSize(intermediate.size() + 2)
+ .addAll(intermediate).add(child.getQName()).add(caze.getQName())
+ .build());
+ }
+ }
}
}
|| node instanceof AnyxmlSchemaNode;
}
- private void addKeyValue(final HashMap<QName, Object> map, final DataSchemaNode node, final String uriValue,
- final DOMMountPoint mountPoint) {
+ private void addKeyValue(final HashMap<QName, Object> map, final Deque<QName> schemaPath, final DataSchemaNode node,
+ final String uriValue, final DOMMountPoint mountPoint) {
checkArgument(node instanceof LeafSchemaNode);
final EffectiveModelContext schemaContext = mountPoint == null ? globalSchema : getModelContext(mountPoint);
TypeDefinition<?> typedef = ((LeafSchemaNode) node).getType();
final TypeDefinition<?> baseType = RestUtil.resolveBaseTypeFrom(typedef);
if (baseType instanceof LeafrefTypeDefinition) {
- typedef = SchemaInferenceStack.ofInstantiatedPath(schemaContext, node.getPath())
- .resolveLeafref((LeafrefTypeDefinition) baseType);
+ final var stack = SchemaInferenceStack.of(schemaContext);
+ schemaPath.forEach(stack::enterSchemaTree);
+ typedef = stack.resolveLeafref((LeafrefTypeDefinition) baseType);
}
final IllegalArgumentCodec<Object, Object> codec = RestCodec.from(typedef, mountPoint, this);
Object decoded = codec.deserialize(urlDecoded);
return URLDecoder.decode(pathArg, StandardCharsets.UTF_8);
}
- private CharSequence convertToRestconfIdentifier(final PathArgument argument, final DataSchemaNode node,
+ private String convertToRestconfIdentifier(final PathArgument argument, final DataSchemaNode node,
final DOMMountPoint mount) {
if (argument instanceof NodeIdentifier) {
return convertToRestconfIdentifier((NodeIdentifier) argument, mount);
}
}
- private CharSequence convertToRestconfIdentifier(final NodeIdentifier argument, final DOMMountPoint node) {
- return "/" + toRestconfIdentifier(argument.getNodeType(),node);
+ private String convertToRestconfIdentifier(final NodeIdentifier argument, final DOMMountPoint node) {
+ return "/" + toRestconfIdentifier(argument.getNodeType(), node);
}
- private CharSequence convertToRestconfIdentifierWithPredicates(final NodeIdentifierWithPredicates argument,
+ private String convertToRestconfIdentifierWithPredicates(final NodeIdentifierWithPredicates argument,
final ListSchemaNode node, final DOMMountPoint mount) {
final QName nodeType = argument.getNodeType();
- final CharSequence nodeIdentifier = this.toRestconfIdentifier(nodeType, mount);
+ final String nodeIdentifier = toRestconfIdentifier(nodeType, mount);
final StringBuilder builder = new StringBuilder().append('/').append(nodeIdentifier).append('/');
}
public YangInstanceIdentifier toXpathRepresentation(final YangInstanceIdentifier instanceIdentifier) {
+ if (dataNormalizer == null) {
+ throw new RestconfDocumentedException("Data normalizer isn't set. Normalization isn't possible");
+ }
+
try {
return dataNormalizer.toLegacy(instanceIdentifier);
- } catch (final NullPointerException e) {
- throw new RestconfDocumentedException("Data normalizer isn't set. Normalization isn't possible", e);
} catch (final DataNormalizationException e) {
throw new RestconfDocumentedException("Data normalizer failed. Normalization isn't possible", e);
}
.flatMap(svc -> Optional.ofNullable(svc.getGlobalContext()))
.orElse(null);
}
+
+ public static final class FoundChild {
+ // Intermediate schema tree children, usually empty
+ public final @NonNull List<QName> intermediate;
+ public final @NonNull DataSchemaNode child;
+
+ private FoundChild(final DataSchemaNode child, final List<QName> intermediate) {
+ this.child = requireNonNull(child);
+ this.intermediate = requireNonNull(intermediate);
+ }
+ }
}