Add AbstractCodecFactory.LeafrefResolver
[yangtools.git] / yang / yang-data-util / src / main / java / org / opendaylight / yangtools / yang / data / util / codec / AbstractCodecFactory.java
index 1d89e855d96ec7f4295948c9045e8f5c63af72b2..d5103ae6a3e83d86d771eec95b39b5a7c2c8f752 100644 (file)
@@ -7,15 +7,18 @@
  */
 package org.opendaylight.yangtools.yang.data.util.codec;
 
-import com.google.common.base.Preconditions;
-import com.google.common.base.Verify;
+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 javax.annotation.concurrent.ThreadSafe;
+import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.yang.common.QNameModule;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+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.TypeDefinition;
-import org.opendaylight.yangtools.yang.model.api.TypedSchemaNode;
 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;
@@ -24,42 +27,59 @@ import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
-import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.Int16TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.Int32TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.Int64TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.Int8TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.Uint16TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.Uint32TypeDefinition;
+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.api.type.UnsignedIntegerTypeDefinition;
-import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
+import org.opendaylight.yangtools.yang.model.spi.AbstractEffectiveModelContextProvider;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
  * A type-to-codec factory base class with logic to efficiently lookup and cache codec instances,
- * also dealing with union type composition.
- *
- * @author Robert Varga
+ * also dealing with union type composition. This class is thread-safe as long as its underlying {@link CodecCache}
+ * is thread-safe
  *
  * @param <T> Codec type
+ * @author Robert Varga
  */
-@ThreadSafe
-public abstract class AbstractCodecFactory<T extends TypeAwareCodec<?, ?, ?>> {
-    private static final Logger LOG = LoggerFactory.getLogger(AbstractCodecFactory.class);
-
-    private final CodecCache<T> cache;
+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 final SchemaContext schemaContext;
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractCodecFactory.class);
 
-    protected AbstractCodecFactory(final SchemaContext schemaContext, final CodecCache<T> cache) {
-        this.schemaContext = Preconditions.checkNotNull(schemaContext);
-        this.cache = Preconditions.checkNotNull(cache);
-    }
+    private final @NonNull CodecCache<T> cache;
 
-    public final SchemaContext getSchemaContext() {
-        return schemaContext;
+    protected AbstractCodecFactory(final @NonNull EffectiveModelContext schemaContext,
+            final @NonNull CodecCache<T> cache) {
+        super(schemaContext);
+        this.cache = requireNonNull(cache);
     }
 
-    public final T codecFor(final TypedSchemaNode 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.
@@ -70,7 +90,7 @@ public abstract class AbstractCodecFactory<T extends TypeAwareCodec<?, ?, ?>> {
          * - null codec, which does not depend on anything
          * - instance identifier codec, which is based on namespace mapping
          *
-         * We assume prevalence is in above order and that caching is effective. We therefore
+         * We assume prevalence is in above order and that caching is effective.
          */
         final TypeDefinition<?> type = schema.getType();
         T ret = cache.lookupSimple(type);
@@ -92,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);
     }
@@ -109,15 +129,29 @@ public abstract class AbstractCodecFactory<T extends TypeAwareCodec<?, ?, ?>> {
 
     protected abstract T identityRefCodec(IdentityrefTypeDefinition type, QNameModule module);
 
+    // FIXME: there really are two favors, as 'require-instance true' needs to be validated. In order to deal
+    //        with that, though, we need access to the current data store.
     protected abstract T instanceIdentifierCodec(InstanceIdentifierTypeDefinition type);
 
-    protected abstract T intCodec(IntegerTypeDefinition type);
+    protected abstract T int8Codec(Int8TypeDefinition type);
+
+    protected abstract T int16Codec(Int16TypeDefinition type);
+
+    protected abstract T int32Codec(Int32TypeDefinition type);
+
+    protected abstract T int64Codec(Int64TypeDefinition type);
 
     protected abstract T decimalCodec(DecimalTypeDefinition type);
 
     protected abstract T stringCodec(StringTypeDefinition type);
 
-    protected abstract T uintCodec(UnsignedIntegerTypeDefinition type);
+    protected abstract T uint8Codec(Uint8TypeDefinition type);
+
+    protected abstract T uint16Codec(Uint16TypeDefinition type);
+
+    protected abstract T uint32Codec(Uint32TypeDefinition type);
+
+    protected abstract T uint64Codec(Uint64TypeDefinition type);
 
     protected abstract T unionCodec(UnionTypeDefinition type, List<T> codecs);
 
@@ -136,10 +170,22 @@ public abstract class AbstractCodecFactory<T extends TypeAwareCodec<?, ?, ?>> {
         final T ret;
         if (type instanceof StringTypeDefinition) {
             ret = stringCodec((StringTypeDefinition) type);
-        } else if (type instanceof IntegerTypeDefinition) {
-            ret = intCodec((IntegerTypeDefinition) type);
-        } else if (type instanceof UnsignedIntegerTypeDefinition) {
-            ret = uintCodec((UnsignedIntegerTypeDefinition) type);
+        } else if (type instanceof Int8TypeDefinition) {
+            ret = int8Codec((Int8TypeDefinition) type);
+        } else if (type instanceof Int16TypeDefinition) {
+            ret = int16Codec((Int16TypeDefinition) type);
+        } else if (type instanceof Int32TypeDefinition) {
+            ret = int32Codec((Int32TypeDefinition) type);
+        } else if (type instanceof Int64TypeDefinition) {
+            ret = int64Codec((Int64TypeDefinition) type);
+        } else if (type instanceof Uint8TypeDefinition) {
+            ret = uint8Codec((Uint8TypeDefinition) type);
+        } else if (type instanceof Uint16TypeDefinition) {
+            ret = uint16Codec((Uint16TypeDefinition) type);
+        } else if (type instanceof Uint32TypeDefinition) {
+            ret = uint32Codec((Uint32TypeDefinition) type);
+        } else if (type instanceof Uint64TypeDefinition) {
+            ret = uint64Codec((Uint64TypeDefinition) type);
         } else if (type instanceof BooleanTypeDefinition) {
             ret = booleanCodec((BooleanTypeDefinition) type);
         } else if (type instanceof DecimalTypeDefinition) {
@@ -162,13 +208,13 @@ public abstract class AbstractCodecFactory<T extends TypeAwareCodec<?, ?, ?>> {
             return null;
         }
 
-        return cache.getSimple(type, Verify.verifyNotNull(ret));
+        return cache.getSimple(type, verifyNotNull(ret));
     }
 
     private static boolean isSimpleUnion(final UnionTypeDefinition union) {
         for (TypeDefinition<?> t : union.getTypes()) {
             if (t instanceof IdentityrefTypeDefinition || t instanceof LeafrefTypeDefinition
-                    || (t instanceof UnionTypeDefinition && !isSimpleUnion((UnionTypeDefinition) t))) {
+                    || t instanceof UnionTypeDefinition && !isSimpleUnion((UnionTypeDefinition) t)) {
                 LOG.debug("Type {} has non-simple subtype", t);
                 return false;
             }
@@ -178,17 +224,14 @@ public abstract class AbstractCodecFactory<T extends TypeAwareCodec<?, ?, ?>> {
         return true;
     }
 
-    private T createComplexCodecFor(final TypedSchemaNode 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,
-                schemaContext, schema);
-            Verify.verifyNotNull(target, "Unable to find base type for leafref node %s type %s.", schema.getPath(),
-                    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 {
@@ -203,8 +246,7 @@ public abstract class AbstractCodecFactory<T extends TypeAwareCodec<?, ?, ?>> {
         for (TypeDefinition<?> type : types) {
             T codec = cache.lookupSimple(type);
             if (codec == null) {
-                codec = Verify.verifyNotNull(getSimpleCodecFor(type), "Type %s did not resolve to a simple codec",
-                    type);
+                codec = verifyNotNull(getSimpleCodecFor(type), "Type %s did not resolve to a simple codec", type);
             }
 
             codecs.add(codec);
@@ -213,7 +255,8 @@ public abstract class AbstractCodecFactory<T extends TypeAwareCodec<?, ?, ?>> {
         return unionCodec(union, codecs);
     }
 
-    private T createComplexUnion(final TypedSchemaNode 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());
 
@@ -222,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(Verify.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);