Add ImmutableNormalizedNode implementation 75/81275/1
authorRobert Varga <robert.varga@pantheon.tech>
Thu, 28 Mar 2019 20:41:09 +0000 (21:41 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Thu, 28 Mar 2019 20:43:09 +0000 (21:43 +0100)
This updates the design a bit and adds a builder-driven
implementation.

JIRA: YANGTOOLS-961
Change-Id: I74546d25b045abda23f0fce35bb064178c841c64
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
yang/rfc7952-data-api/src/main/java/org/opendaylight/yangtools/rfc7952/data/api/NormalizedMetadata.java
yang/rfc7952-data-api/src/main/java/org/opendaylight/yangtools/rfc7952/data/api/NormalizedMetadataContainer.java [deleted file]
yang/rfc7952-data-util/src/main/java/org/opendaylight/yangtools/rfc7952/data/util/ImmutableNormalizedMetadata.java [new file with mode: 0644]
yang/rfc7952-data-util/src/main/java/org/opendaylight/yangtools/rfc7952/data/util/NormalizedNodeStreamWriterMetadataDecorator.java

index ad642d80bcd31499d4cfcece7f323802246df269..9ef69672d2749373b18044d872caacd6168724e6 100644 (file)
@@ -7,8 +7,11 @@
  */
 package org.opendaylight.yangtools.rfc7952.data.api;
 
+import static java.util.Objects.requireNonNull;
+
 import com.google.common.annotations.Beta;
 import java.util.Map;
+import java.util.Optional;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.concepts.Identifiable;
 import org.opendaylight.yangtools.concepts.Immutable;
@@ -17,12 +20,14 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgum
 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
 
 /**
  * RFC7952 metadata counterpart to a {@link NormalizedNode}. This interface is meant to be used as a companion to
  * a NormalizedNode instance, hence it does not support iterating over its structure like it is possible with
- * {@link NormalizedNode#getValue()}.
+ * {@link NormalizedNode#getValue()}. Children may be inquired through {@link #getChild(PathArgument)}, similar to
+ * {@link NormalizedNodeContainer}.
  *
  * <p>
  * This model of metadata <em>does not</em> have the RFC7952 restriction on metadata attachment to {@code list}s and
@@ -40,4 +45,16 @@ public interface NormalizedMetadata extends Identifiable<PathArgument>, Immutabl
      * @return The set of annotations attached to the corresponding data node.
      */
     @NonNull Map<QName, Object> getAnnotations();
+
+    /**
+     * Returns child node identified by provided key. Default implementation returns {@link Optional#empty()}.
+     *
+     * @param child Path argument identifying child node
+     * @return Optional with child node if child exists, {@link Optional#empty()} if it does not.
+     * @throws NullPointerException if {@code child} is null
+     */
+    default Optional<NormalizedMetadata> getChild(final PathArgument child) {
+        requireNonNull(child);
+        return Optional.empty();
+    }
 }
diff --git a/yang/rfc7952-data-api/src/main/java/org/opendaylight/yangtools/rfc7952/data/api/NormalizedMetadataContainer.java b/yang/rfc7952-data-api/src/main/java/org/opendaylight/yangtools/rfc7952/data/api/NormalizedMetadataContainer.java
deleted file mode 100644 (file)
index 99b939e..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (c) 2019 PANTHEON.tech, s.r.o. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.yangtools.rfc7952.data.api;
-
-import com.google.common.annotations.Beta;
-import java.util.Optional;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
-
-/**
- * RFC7952 metadata counterpart to a {@link NormalizedNodeContainer}.
- *
- * @author Robert Varga
- */
-@Beta
-public interface NormalizedMetadataContainer extends NormalizedMetadata {
-    /**
-     * Returns child node identified by provided key.
-     *
-     * @param child Path argument identifying child node
-     * @return Optional with child node if child exists, {@link Optional#empty()} if it does not.
-     */
-    Optional<? extends NormalizedMetadata> getChild(PathArgument child);
-}
diff --git a/yang/rfc7952-data-util/src/main/java/org/opendaylight/yangtools/rfc7952/data/util/ImmutableNormalizedMetadata.java b/yang/rfc7952-data-util/src/main/java/org/opendaylight/yangtools/rfc7952/data/util/ImmutableNormalizedMetadata.java
new file mode 100644 (file)
index 0000000..147c24a
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2019 PANTHEON.tech, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.rfc7952.data.util;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableMap;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.rfc7952.data.api.NormalizedMetadata;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+
+/**
+ * Immutable implementation of {@link NormalizedMetadata}.
+ */
+@Beta
+public class ImmutableNormalizedMetadata implements NormalizedMetadata {
+    private static final class Container extends ImmutableNormalizedMetadata {
+        private final ImmutableMap<PathArgument, ImmutableNormalizedMetadata> children;
+
+        Container(final PathArgument identifier, final Map<QName, Object> annotations,
+                final Map<PathArgument, ImmutableNormalizedMetadata> children) {
+            super(identifier, annotations);
+            this.children = ImmutableMap.copyOf(children);
+        }
+
+        @Override
+        public Optional<NormalizedMetadata> getChild(final PathArgument child) {
+            return Optional.ofNullable(children.get(requireNonNull(child)));
+        }
+    }
+
+    private final @NonNull PathArgument identifier;
+    private final @NonNull ImmutableMap<QName, Object> annotations;
+
+    ImmutableNormalizedMetadata(final PathArgument identifier, final Map<QName, Object> annotations) {
+        this.identifier = requireNonNull(identifier);
+        this.annotations = ImmutableMap.copyOf(annotations);
+    }
+
+    /**
+     * Return a new {@link Builder}.
+     *
+     * @return A new Builder.
+     */
+    public static final @NonNull Builder builder() {
+        return new Builder();
+    }
+
+    @Override
+    public final PathArgument getIdentifier() {
+        return identifier;
+    }
+
+    @Override
+    public final ImmutableMap<QName, Object> getAnnotations() {
+        return annotations;
+    }
+
+    /**
+     * {@link org.opendaylight.yangtools.concepts.Builder} of {@link ImmutableNormalizedMetadata} instances.
+     */
+    public static final class Builder
+            implements org.opendaylight.yangtools.concepts.Builder<ImmutableNormalizedMetadata> {
+        private final Map<PathArgument, ImmutableNormalizedMetadata> children = new HashMap<>();
+        private final Map<QName, Object> annotations = new HashMap<>();
+        private PathArgument identifier;
+
+        Builder() {
+            // Hidden to prevent instantiation
+        }
+
+        @SuppressWarnings("checkstyle:hiddenField")
+        public Builder withIdentifier(final PathArgument identifier) {
+            this.identifier = requireNonNull(identifier);
+            return this;
+        }
+
+        public Builder withAnnotation(final QName type, final Object value) {
+            annotations.put(requireNonNull(type, "type"), requireNonNull(value, "value"));
+            return this;
+        }
+
+        @SuppressWarnings("checkstyle:hiddenField")
+        public Builder withAnnotations(final Map<QName, Object> annotations) {
+            annotations.forEach(this::withAnnotation);
+            return this;
+        }
+
+        public Builder withChild(final ImmutableNormalizedMetadata child) {
+            children.put(child.getIdentifier(), child);
+            return this;
+        }
+
+        @SuppressWarnings("checkstyle:hiddenField")
+        public Builder withChildren(final Collection<ImmutableNormalizedMetadata> children) {
+            children.forEach(this::withChild);
+            return this;
+        }
+
+        @Override
+        public ImmutableNormalizedMetadata build() {
+            final PathArgument id = identifier;
+            checkArgument(id != null, "Identifier has not been set");
+            return children.isEmpty() ? new ImmutableNormalizedMetadata(id, annotations)
+                    : new Container(id, annotations, children);
+        }
+    }
+}
index abba3489a3955a649dce023d0dbcbd63148fb1ec..c1996f6ac697624d35538f2855ef191c9cf50803 100644 (file)
@@ -16,7 +16,6 @@ import java.util.Deque;
 import java.util.Map;
 import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.yangtools.rfc7952.data.api.NormalizedMetadata;
-import org.opendaylight.yangtools.rfc7952.data.api.NormalizedMetadataContainer;
 import org.opendaylight.yangtools.rfc7952.data.api.NormalizedMetadataStreamWriter;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
@@ -150,12 +149,11 @@ final class NormalizedNodeStreamWriterMetadataDecorator extends ForwardingNormal
 
     private @Nullable NormalizedMetadata findMetadata(final PathArgument name) {
         final NormalizedMetadata current = stack.peek();
-        if (current instanceof NormalizedMetadataContainer) {
-            return ((NormalizedMetadataContainer) current).getChild(name).orElse(null);
+        if (current == null) {
+            // This may either be the first entry or unattached metadata nesting
+            return stack.isEmpty() ? metadata : null;
         }
-
-        // This may either be the first entry or unattached metadata nesting
-        return stack.isEmpty() ? metadata : null;
+        return current.getChild(name).orElse(null);
     }
 
     private void emitAnnotations(final Map<QName, Object> annotations) throws IOException {