Centralize AugmentationIdentifier instantiation
[yangtools.git] / yang / yang-data-util / src / main / java / org / opendaylight / yangtools / yang / data / util / DataSchemaContextNode.java
index b777c59a2e85ea21e9029a83c96b18df22a748a4..a83373457e9bca4df43f653b9418076c03a9b0c3 100644 (file)
@@ -7,22 +7,23 @@
  */
 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 java.util.stream.Collectors;
 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;
-import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
-import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
@@ -35,26 +36,17 @@ 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 <T> Path Argument type
- *
  */
 public abstract class DataSchemaContextNode<T extends PathArgument> implements Identifiable<T> {
-
-    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) {
-        super();
         this.identifier = identifier;
         if (schema instanceof DataSchemaNode) {
             this.dataSchemaNode = (DataSchemaNode) schema;
@@ -63,6 +55,11 @@ public abstract class DataSchemaContextNode<T extends PathArgument> implements I
         }
     }
 
+    @Override
+    public T getIdentifier() {
+        return identifier;
+    }
+
     public boolean isMixin() {
         return false;
     }
@@ -71,22 +68,46 @@ public abstract class DataSchemaContextNode<T extends PathArgument> implements I
         return false;
     }
 
+    public abstract boolean isLeaf();
+
     protected Set<QName> getQNameIdentifiers() {
-        return Collections.singleton(identifier.getNodeType());
+        return ImmutableSet.of(identifier.getNodeType());
     }
 
-    public abstract @Nullable DataSchemaContextNode<?> getChild(final PathArgument child);
-
-    public abstract @Nullable DataSchemaContextNode<?> getChild(QName child);
-
-    public abstract boolean isLeaf();
+    /**
+     * Find a child node identifier by its {@link PathArgument}.
+     *
+     * @param child Child path argument
+     * @return A child node, or null if not found
+     */
+    @Nullable public abstract DataSchemaContextNode<?> getChild(PathArgument child);
 
+    @Nullable public abstract DataSchemaContextNode<?> getChild(QName child);
 
-    public @Nullable DataSchemaNode getDataSchemaNode() {
+    @Nullable public DataSchemaNode getDataSchemaNode() {
         return dataSchemaNode;
     }
 
-    static final DataSchemaNode findChildSchemaNode(final DataNodeContainer parent, final QName child) {
+    /**
+     * 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) {
             Iterable<ChoiceSchemaNode> choices = FluentIterable.from(
@@ -99,60 +120,65 @@ public abstract class DataSchemaContextNode<T extends PathArgument> implements I
     static DataSchemaContextNode<?> fromSchemaAndQNameChecked(final DataNodeContainer schema, final QName child) {
         DataSchemaNode result = findChildSchemaNode(schema, child);
         // We try to look up if this node was added by augmentation
-        if ((schema instanceof DataSchemaNode) && result.isAugmenting()) {
+        if (result != null && schema instanceof DataSchemaNode && result.isAugmenting()) {
             return fromAugmentation(schema, (AugmentationTarget) schema, result);
         }
         return fromDataSchemaNode(result);
     }
 
+    // FIXME: this looks like it should be a Predicate on a stream with findFirst()
     private static ChoiceSchemaNode findChoice(final Iterable<ChoiceSchemaNode> choices, final QName child) {
-        ChoiceSchemaNode foundChoice = null;
-        choiceLoop: for (ChoiceSchemaNode choice : choices) {
-            for (ChoiceCaseNode caze : choice.getCases()) {
+        for (ChoiceSchemaNode choice : choices) {
+            // FIXME: this looks weird: what are we looking for again?
+            for (CaseSchemaNode caze : choice.getCases().values()) {
                 if (findChildSchemaNode(caze, child) != null) {
-                    foundChoice = choice;
-                    break choiceLoop;
+                    return choice;
                 }
             }
         }
-        return foundChoice;
+        return null;
     }
 
-    public static AugmentationIdentifier augmentationIdentifierFrom(final AugmentationSchema augmentation) {
-        ImmutableSet.Builder<QName> potentialChildren = ImmutableSet.builder();
-        for (DataSchemaNode child : augmentation.getChildNodes()) {
-            potentialChildren.add(child.getQName());
-        }
-        return new AugmentationIdentifier(potentialChildren.build());
+    /**
+     * Create AugmentationIdentifier from an AugmentationSchemaNode.
+     *
+     * @param schema Augmentation schema
+     * @return AugmentationIdentifier for the schema
+     * @throws NullPointerException if {@code schema} is null
+     */
+    public static AugmentationIdentifier augmentationIdentifierFrom(final AugmentationSchemaNode schema) {
+        return new AugmentationIdentifier(schema.getChildNodes().stream().map(DataSchemaNode::getQName)
+            .collect(Collectors.toSet()));
     }
 
-    static DataNodeContainer augmentationProxy(final AugmentationSchema augmentation,
-            final DataNodeContainer schema) {
-        Set<DataSchemaNode> children = new HashSet<>();
-        for (DataSchemaNode augNode : augmentation.getChildNodes()) {
-            children.add(schema.getDataChildByName(augNode.getQName()));
-        }
-        return new EffectiveAugmentationSchema(augmentation, children);
+    /**
+     * Returns an AugmentationSchemaNode as effective in a parent node.
+     *
+     * @param schema Augmentation schema
+     * @param parent Parent schema
+     * @return Adjusted Augmentation schema
+     * @throws NullPointerException if any of the arguments is null
+     * @deprecated Use {@link EffectiveAugmentationSchema#create(AugmentationSchemaNode, DataNodeContainer)} instead.
+     */
+    @Deprecated
+    public static AugmentationSchemaNode augmentationProxy(final AugmentationSchemaNode schema,
+            final DataNodeContainer parent) {
+        return EffectiveAugmentationSchema.create(schema, parent);
     }
 
     /**
      * Returns a DataContextNodeOperation for provided child node
      *
+     * <p>
      * If supplied child is added by Augmentation this operation returns a
      * DataContextNodeOperation for augmentation, otherwise returns a
      * DataContextNodeOperation for child as call for
      * {@link #fromDataSchemaNode(DataSchemaNode)}.
-     *
-     *
-     * @param parent
-     * @param parentAug
-     * @param child
-     * @return
      */
-    static @Nullable DataSchemaContextNode<?> fromAugmentation(final DataNodeContainer parent,
+    @Nullable static DataSchemaContextNode<?> fromAugmentation(final DataNodeContainer parent,
             final AugmentationTarget parentAug, final DataSchemaNode child) {
-        AugmentationSchema augmentation = null;
-        for (AugmentationSchema aug : parentAug.getAvailableAugmentations()) {
+        AugmentationSchemaNode augmentation = null;
+        for (AugmentationSchemaNode aug : parentAug.getAvailableAugmentations()) {
             DataSchemaNode potential = aug.getDataChildByName(child.getQName());
             if (potential != null) {
                 augmentation = aug;
@@ -165,7 +191,7 @@ public abstract class DataSchemaContextNode<T extends PathArgument> implements I
         return fromDataSchemaNode(child);
     }
 
-    public static @Nullable DataSchemaContextNode<?> fromDataSchemaNode(final DataSchemaNode potential) {
+    @Nullable public static DataSchemaContextNode<?> fromDataSchemaNode(final DataSchemaNode potential) {
         if (potential instanceof ContainerSchemaNode) {
             return new ContainerContextNode((ContainerSchemaNode) potential);
         } else if (potential instanceof ListSchemaNode) {