From d72b739886dd6c8db4e42e4a6777e78f46df9131 Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Fri, 27 Apr 2018 16:49:29 +0200 Subject: [PATCH] Clean up DataSchemaContext{Node,Tree} This patch fixes a potential NPE when a YangInstanceIdentifier does not match the schema tree and adds alternative Optional-based methods for finding children based on relative/absolute YangInstanceIdentifier. Change-Id: Icdc08c02817ad9d59434a060b6da27dfe2b5ea67 Signed-off-by: Robert Varga --- .../yang/data/util/DataSchemaContextNode.java | 57 +++++++++++++------ .../yang/data/util/DataSchemaContextTree.java | 37 +++++++++++- 2 files changed, 76 insertions(+), 18 deletions(-) diff --git a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/DataSchemaContextNode.java b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/DataSchemaContextNode.java index e51f1a6061..22b93d8621 100644 --- a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/DataSchemaContextNode.java +++ b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/DataSchemaContextNode.java @@ -9,13 +9,15 @@ package org.opendaylight.yangtools.yang.data.util; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableSet; -import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Optional; import java.util.Set; import javax.annotation.Nullable; +import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.yangtools.concepts.Identifiable; import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode; @@ -34,23 +36,15 @@ import org.opendaylight.yangtools.yang.model.api.SchemaNode; import org.opendaylight.yangtools.yang.model.util.EffectiveAugmentationSchema; /** - * Schema derived data providing necessary information for mapping - * between {@link org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode} - * and serialization format defined in RFC6020, since the mapping - * is not one-to-one. + * Schema derived data providing necessary information for mapping between + * {@link org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode} and serialization format defined in RFC6020, + * since the mapping is not one-to-one. * * @param Path Argument type - * */ public abstract class DataSchemaContextNode implements Identifiable { - - private final T identifier; private final DataSchemaNode dataSchemaNode; - - @Override - public T getIdentifier() { - return identifier; - } + private final T identifier; protected DataSchemaContextNode(final T identifier, final SchemaNode schema) { this.identifier = identifier; @@ -61,6 +55,11 @@ public abstract class DataSchemaContextNode implements I } } + @Override + public T getIdentifier() { + return identifier; + } + public boolean isMixin() { return false; } @@ -69,21 +68,45 @@ public abstract class DataSchemaContextNode implements I return false; } + public abstract boolean isLeaf(); + protected Set getQNameIdentifiers() { - return Collections.singleton(identifier.getNodeType()); + return ImmutableSet.of(identifier.getNodeType()); } + /** + * Find a child node identifier by its {@link PathArgument}. + * + * @param child Child path argument + * @return + */ @Nullable public abstract DataSchemaContextNode getChild(PathArgument child); @Nullable public abstract DataSchemaContextNode getChild(QName child); - public abstract boolean isLeaf(); - - @Nullable public DataSchemaNode getDataSchemaNode() { return dataSchemaNode; } + /** + * Find a child node as identified by a {@link YangInstanceIdentifier} relative to this node. + * + * @param path Path towards the child node + * @return Child node if present, or empty when corresponding child is not found. + * @throws NullPointerException if {@code path} is null + */ + public final @NonNull Optional<@NonNull DataSchemaContextNode> findChild( + final @NonNull YangInstanceIdentifier path) { + DataSchemaContextNode currentOp = this; + for (PathArgument arg : path.getPathArguments()) { + currentOp = currentOp.getChild(arg); + if (currentOp == null) { + return Optional.empty(); + } + } + return Optional.of(currentOp); + } + static DataSchemaNode findChildSchemaNode(final DataNodeContainer parent, final QName child) { DataSchemaNode potential = parent.getDataChildByName(child); if (potential == null) { diff --git a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/DataSchemaContextTree.java b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/DataSchemaContextTree.java index e012e29fef..dc0407afd2 100644 --- a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/DataSchemaContextTree.java +++ b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/DataSchemaContextTree.java @@ -10,11 +10,22 @@ package org.opendaylight.yangtools.yang.data.util; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; +import java.util.Optional; import javax.annotation.Nonnull; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.model.api.SchemaContext; +/** + * Semantic tree binding a {@link SchemaContext} to a {@link NormalizedNode} tree. Since the layout of the schema + * and data has differences, the mapping is not trivial -- which is where this class comes in. + * + * @author Robert Varga + */ +// FIXME: 3.0.0: @NonNullByDefault public final class DataSchemaContextTree { private static final LoadingCache TREES = CacheBuilder.newBuilder() .weakKeys().weakValues().build(new CacheLoader() { @@ -34,10 +45,34 @@ public final class DataSchemaContextTree { return TREES.getUnchecked(ctx); } - public DataSchemaContextNode getChild(final YangInstanceIdentifier path) { + /** + * Find a child node as identified by an absolute {@link YangInstanceIdentifier}. + * + * @param path Path towards the child node + * @return Child node if present, or empty when corresponding child is not found. + * @throws NullPointerException if {@code path} is null + */ + public @NonNull Optional<@NonNull DataSchemaContextNode> findChild(final @NonNull YangInstanceIdentifier path) { + return getRoot().findChild(path); + } + + /** + * Get a child node as identified by an absolute {@link YangInstanceIdentifier}. + * + * @param path Path towards the child node + * @return Child node if present, or null when corresponding child is not found. + * @throws NullPointerException if {@code path} is null + * + * @deprecated Use {@link #findChild(YangInstanceIdentifier)} instead. + */ + @Deprecated + public @Nullable DataSchemaContextNode getChild(final YangInstanceIdentifier path) { DataSchemaContextNode currentOp = root; for (PathArgument arg : path.getPathArguments()) { currentOp = currentOp.getChild(arg); + if (currentOp == null) { + return null; + } } return currentOp; } -- 2.36.6