Add AbstractCodecFactory.LeafrefResolver 66/95166/4
authorRobert Varga <robert.varga@pantheon.tech>
Sun, 14 Feb 2021 13:38:42 +0000 (14:38 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Sun, 14 Feb 2021 14:17:31 +0000 (15:17 +0100)
The context provided by SchemaNode is rather not nice, as it implies
access through SchemaNode.getPath(). The only use case for it is
leafref resolution -- hence encapsulate it, so that users can do their
own thing if need be.

JIRA: YANGTOOLS-1232
Change-Id: I385dceac4796e138130df32a5dad578e9ceceed1
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONCodecFactory.java
yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlCodecFactory.java
yang/yang-data-util/src/main/java/module-info.java
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/codec/AbstractCodecFactory.java

index aaa67301959ca07ec457108de875cd5a8f889889..e3fee0126edc4f5a7349af475b8509a141173c93 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.yangtools.yang.data.codec.gson;
 
+import static com.google.common.base.Verify.verifyNotNull;
+
 import com.google.common.annotations.Beta;
 import java.util.List;
 import org.eclipse.jdt.annotation.NonNull;
@@ -22,6 +24,7 @@ import org.opendaylight.yangtools.yang.data.util.codec.AbstractCodecFactory;
 import org.opendaylight.yangtools.yang.data.util.codec.CodecCache;
 import org.opendaylight.yangtools.yang.data.util.codec.LazyCodecCache;
 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.TypedDataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
@@ -41,6 +44,7 @@ import org.opendaylight.yangtools.yang.model.api.type.Uint64TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.Uint8TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.UnknownTypeDefinition;
+import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
 
 /**
  * Factory for creating JSON equivalents of codecs. Each instance of this object is bound to
@@ -163,4 +167,10 @@ public abstract class JSONCodecFactory extends AbstractCodecFactory<JSONCodec<?>
     abstract JSONCodec<?> wrapDecimalCodec(DecimalStringCodec decimalCodec);
 
     abstract JSONCodec<?> wrapIntegerCodec(AbstractIntegerStringCodec<?, ?> integerCodec);
+
+    final JSONCodec<?> codecFor(final TypedDataSchemaNode currentNode) {
+        return codecFor(currentNode, type -> verifyNotNull(
+            SchemaContextUtil.getBaseTypeForLeafRef(type, getEffectiveModelContext(), currentNode),
+            "Unable to find base type for leafref node %s type %s.", currentNode, type));
+    }
 }
index c63009f8f9f78e5097e6c3e100e5f258ac4df0be..18a2d4c4da3303e92168ccf175196c25c37bdc70 100644 (file)
@@ -8,6 +8,7 @@
 
 package org.opendaylight.yangtools.yang.data.codec.xml;
 
+import static com.google.common.base.Verify.verifyNotNull;
 import static java.util.Objects.requireNonNull;
 
 import com.google.common.annotations.Beta;
@@ -25,6 +26,8 @@ import org.opendaylight.yangtools.yang.data.impl.codec.StringStringCodec;
 import org.opendaylight.yangtools.yang.data.util.codec.AbstractCodecFactory;
 import org.opendaylight.yangtools.yang.data.util.codec.SharedCodecCache;
 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.api.TypeAware;
 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
@@ -44,6 +47,7 @@ import org.opendaylight.yangtools.yang.model.api.type.Uint64TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.Uint8TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.UnknownTypeDefinition;
+import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
 
 /**
  * A thread-safe factory for instantiating {@link XmlCodec}s.
@@ -175,4 +179,10 @@ public final class XmlCodecFactory extends AbstractCodecFactory<XmlCodec<?>> {
     protected XmlCodec<?> unknownCodec(final UnknownTypeDefinition type) {
         return NullXmlCodec.INSTANCE;
     }
+
+    <T extends SchemaNode & TypeAware> XmlCodec<?> codecFor(final T currentNode) {
+        return codecFor(currentNode, type -> verifyNotNull(
+            SchemaContextUtil.getBaseTypeForLeafRef(type, getEffectiveModelContext(), currentNode),
+            "Unable to find base type for leafref node %s type %s.", currentNode, type));
+    }
 }
index 8622745076a6ab8301ae5a93ac0c15f378b3cdff..10d109568735c1b6a287a720898cb18131e24d89 100644 (file)
@@ -13,8 +13,12 @@ module org.opendaylight.yangtools.yang.data.util {
     requires transitive org.opendaylight.yangtools.rfc7952.data.api;
     requires transitive org.opendaylight.yangtools.rfc8528.data.api;
 
+    requires com.google.common;
     requires org.opendaylight.yangtools.yang.model.spi;
     requires org.opendaylight.yangtools.yang.model.util;
     requires org.opendaylight.yangtools.util;
     requires org.slf4j;
+
+    // Annotations
+    requires static org.eclipse.jdt.annotation;
 }
index 22e4d82cbcf49149b04a0de2edbf287dd5e9f08b..d5103ae6a3e83d86d771eec95b39b5a7c2c8f752 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.yangtools.yang.data.util.codec;
 import static com.google.common.base.Verify.verifyNotNull;
 import static java.util.Objects.requireNonNull;
 
+import com.google.common.annotations.Beta;
 import java.util.ArrayList;
 import java.util.List;
 import org.eclipse.jdt.annotation.NonNull;
@@ -39,7 +40,6 @@ import org.opendaylight.yangtools.yang.model.api.type.Uint8TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.UnknownTypeDefinition;
 import org.opendaylight.yangtools.yang.model.spi.AbstractEffectiveModelContextProvider;
-import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -53,6 +53,21 @@ import org.slf4j.LoggerFactory;
  */
 public abstract class AbstractCodecFactory<T extends TypeAwareCodec<?, ?, ?>>
         extends AbstractEffectiveModelContextProvider {
+    /**
+     * Helper interface aiding resolution of leafref chains.
+     */
+    @Beta
+    @FunctionalInterface
+    public interface LeafrefResolver {
+        /**
+         * Resolve specified {@link LeafrefTypeDefinition}.
+         *
+         * @param type leafref definition
+         * @return Resolved type
+         */
+        @NonNull TypeDefinition<?> resolveLeafref(@NonNull LeafrefTypeDefinition type);
+    }
+
     private static final Logger LOG = LoggerFactory.getLogger(AbstractCodecFactory.class);
 
     private final @NonNull CodecCache<T> cache;
@@ -63,7 +78,8 @@ public abstract class AbstractCodecFactory<T extends TypeAwareCodec<?, ?, ?>>
         this.cache = requireNonNull(cache);
     }
 
-    public final <S extends TypeAware & SchemaNode> @NonNull T codecFor(final S schema) {
+    public final <S extends TypeAware & SchemaNode> @NonNull T codecFor(final S schema,
+            final LeafrefResolver resolver) {
         /*
          * There are many trade-offs to be made here. We need the common case being as fast as possible while reusing
          * codecs as much as possible.
@@ -96,7 +112,7 @@ public abstract class AbstractCodecFactory<T extends TypeAwareCodec<?, ?, ?>>
         }
 
         // ... and complex types afterwards
-        ret = createComplexCodecFor(schema, type);
+        ret = createComplexCodecFor(schema, type, resolver);
         LOG.trace("Type {} miss complex {}", type, ret);
         return cache.getComplex(schema, ret);
     }
@@ -208,16 +224,14 @@ public abstract class AbstractCodecFactory<T extends TypeAwareCodec<?, ?, ?>>
         return true;
     }
 
-    private T createComplexCodecFor(final SchemaNode schema, final TypeDefinition<?> type) {
+    private T createComplexCodecFor(final SchemaNode schema, final TypeDefinition<?> type,
+            final LeafrefResolver resolver) {
         if (type instanceof UnionTypeDefinition) {
-            return createComplexUnion(schema, (UnionTypeDefinition) type);
+            return createComplexUnion(schema, (UnionTypeDefinition) type, resolver);
         } else if (type instanceof LeafrefTypeDefinition) {
-            final TypeDefinition<?> target = SchemaContextUtil.getBaseTypeForLeafRef((LeafrefTypeDefinition) type,
-                getEffectiveModelContext(), schema);
-            verifyNotNull(target, "Unable to find base type for leafref node %s type %s.", schema, target);
-
+            final TypeDefinition<?> target = resolver.resolveLeafref((LeafrefTypeDefinition) type);
             final T ret = getSimpleCodecFor(target);
-            return ret != null ? ret : createComplexCodecFor(schema, target);
+            return ret != null ? ret : createComplexCodecFor(schema, target, resolver);
         } else if (type instanceof IdentityrefTypeDefinition) {
             return identityRefCodec((IdentityrefTypeDefinition) type, schema.getQName().getModule());
         } else {
@@ -241,7 +255,8 @@ public abstract class AbstractCodecFactory<T extends TypeAwareCodec<?, ?, ?>>
         return unionCodec(union, codecs);
     }
 
-    private T createComplexUnion(final SchemaNode schema, final UnionTypeDefinition union) {
+    private T createComplexUnion(final SchemaNode schema, final UnionTypeDefinition union,
+            final LeafrefResolver resolver) {
         final List<TypeDefinition<?>> types = union.getTypes();
         final List<T> codecs = new ArrayList<>(types.size());
 
@@ -250,11 +265,11 @@ public abstract class AbstractCodecFactory<T extends TypeAwareCodec<?, ?, ?>>
             if (codec == null) {
                 codec = getSimpleCodecFor(type);
                 if (codec == null) {
-                    codec = createComplexCodecFor(schema, type);
+                    codec = createComplexCodecFor(schema, type, resolver);
                 }
             }
 
-            codecs.add(verifyNotNull(codec, "Schema %s subtype %s has no codec", schema, type));
+            codecs.add(verifyNotNull(codec, "Type %s has no codec", schema, type));
         }
 
         return unionCodec(union, codecs);