Refactor ImmutableMapEntryNodeSchemaAwareBuilder 14/78114/1
authorRobert Varga <robert.varga@pantheon.tech>
Thu, 22 Nov 2018 23:43:32 +0000 (00:43 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Sun, 25 Nov 2018 16:57:10 +0000 (17:57 +0100)
This builder's logic is not entirely efficient, as it can constructs
unnecessary NodeIdentifierWithPredicates purely for checking purposes.

Furthermore we can side-step child validation when we are switching
by available children, as we have the entryset available.

JIRA: YANGTOOLS-917
Change-Id: I57d0a156ced3abce7e61403c2b390c074850d612
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
(cherry picked from commit c43197e66be08a0ffaa00bbe8405fa4ba23b8656)

yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/builder/impl/ImmutableMapEntryNodeSchemaAwareBuilder.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/builder/impl/valid/DataValidationException.java

index f5165cea603be46c5f30e662ec61b6a84d47f1d2..b68d7621b57897c5bfd13ced38e2dee5d5fdc7ba 100644 (file)
@@ -7,17 +7,21 @@
  */
 package org.opendaylight.yangtools.yang.data.impl.schema.builder.impl;
 
-import com.google.common.base.Preconditions;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.collect.ImmutableMap;
 import java.util.Collection;
-import java.util.LinkedHashMap;
 import java.util.Map;
+import java.util.Map.Entry;
+import org.opendaylight.yangtools.util.ImmutableMapTemplate;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.valid.DataNodeContainerValidator;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.valid.DataValidationException;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.valid.DataValidationException.IllegalListKeyException;
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
 
 public final class ImmutableMapEntryNodeSchemaAwareBuilder extends ImmutableMapEntryNodeBuilder {
@@ -26,7 +30,7 @@ public final class ImmutableMapEntryNodeSchemaAwareBuilder extends ImmutableMapE
     private final DataNodeContainerValidator validator;
 
     ImmutableMapEntryNodeSchemaAwareBuilder(final ListSchemaNode schema) {
-        this.schema = Preconditions.checkNotNull(schema);
+        this.schema = requireNonNull(schema);
         this.validator = new DataNodeContainerValidator(schema);
     }
 
@@ -48,29 +52,50 @@ public final class ImmutableMapEntryNodeSchemaAwareBuilder extends ImmutableMapE
         return super.build();
     }
 
+    public static DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> create(
+            final ListSchemaNode schema) {
+        return new ImmutableMapEntryNodeSchemaAwareBuilder(schema);
+    }
+
     /**
      * Build map entry node identifier from schema and provided children.
      */
     private NodeIdentifierWithPredicates constructNodeIdentifier() {
-        Collection<QName> keys = schema.getKeyDefinition();
+        final Map<QName, Object> predicates;
+        final Collection<QName> keys = schema.getKeyDefinition();
+        if (!keys.isEmpty()) {
+            predicates = keyDefToPredicates(keys);
+        } else if (!childrenQNamesToPaths.isEmpty()) {
+            predicates = childrenToPredicates();
+        } else {
+            predicates = ImmutableMap.of();
+        }
+        return new NodeIdentifierWithPredicates(schema.getQName(), predicates);
+    }
 
-        if (keys.isEmpty()) {
-            keys = childrenQNamesToPaths.keySet();
+    private Map<QName, Object> childrenToPredicates() {
+        final Object[] values = new Object[childrenQNamesToPaths.size()];
+        int offset = 0;
+        for (Entry<QName, PathArgument> entry : childrenQNamesToPaths.entrySet()) {
+            values[offset++] = nonnullKeyValue(entry.getKey(), getChild(entry.getValue())).getValue();
         }
+        return ImmutableMapTemplate.ordered(childrenQNamesToPaths.keySet()).instantiateWithValues(values);
+    }
 
-        final Map<QName, Object> keysToValues = new LinkedHashMap<>();
+    private Map<QName, Object> keyDefToPredicates(final Collection<QName> keys) {
+        final Object[] values = new Object[keys.size()];
+        int offset = 0;
         for (QName key : keys) {
-            final DataContainerChild<?, ?> valueForKey = getChild(childrenQNamesToPaths.get(key));
-            DataValidationException.checkListKey(valueForKey, key, new NodeIdentifierWithPredicates(
-                schema.getQName(), keysToValues));
-            keysToValues.put(key, valueForKey.getValue());
+            values[offset++] = nonnullKeyValue(key, getChild(childrenQNamesToPaths.get(key))).getValue();
         }
-
-        return new NodeIdentifierWithPredicates(schema.getQName(), keysToValues);
+        return ImmutableMapTemplate.ordered(keys).instantiateWithValues(values);
     }
 
-    public static DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> create(
-            final ListSchemaNode schema) {
-        return new ImmutableMapEntryNodeSchemaAwareBuilder(schema);
+    private DataContainerChild<?, ?> nonnullKeyValue(final QName key, final DataContainerChild<?, ?> value) {
+        if (value != null) {
+            return value;
+        }
+        throw new IllegalListKeyException("Key value not present for key: %s, in: %s values %s", key, schema.getQName(),
+            buildValue());
     }
 }
index e79cefb6164e399e748d7f1d83d88ef4ec1e515f..0b3a7f4fc52e7f74e9a93febf1867893472115bd 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.valid;
 
+import com.google.common.annotations.Beta;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
@@ -98,17 +99,22 @@ public class DataValidationException extends RuntimeException {
         }
     }
 
-    private static final class IllegalListKeyException extends DataValidationException {
+    @Beta
+    public static final class IllegalListKeyException extends DataValidationException {
         private static final long serialVersionUID = 1L;
 
+        public IllegalListKeyException(final String format, final Object... args) {
+            super(String.format(format, args));
+        }
+
         IllegalListKeyException(final QName keyQName, final NodeIdentifierWithPredicates id) {
-            super(String.format("Key value not present for key: %s, in: %s", keyQName, id));
+            this("Key value not present for key: %s, in: %s", keyQName, id);
         }
 
         IllegalListKeyException(final QName keyQName, final NodeIdentifierWithPredicates id, final Object actualValue,
                 final Object expectedValue) {
-            super(String.format("Illegal value for key: %s, in: %s, actual value: %s, expected value from key: %s",
-                keyQName, id, actualValue, expectedValue));
+            this("Illegal value for key: %s, in: %s, actual value: %s, expected value from key: %s",
+                keyQName, id, actualValue, expectedValue);
         }
     }
 }