Rework AugmentRuntimeType and Choice/Case linkage 22/100122/11
authorRobert Varga <robert.varga@pantheon.tech>
Mon, 14 Mar 2022 19:36:49 +0000 (20:36 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Thu, 17 Mar 2022 21:07:33 +0000 (22:07 +0100)
Augmentations and their interactions with runtime linkage are a strange
beast. Not through YANG semantics, which is very simple. The
complication is Binding Specification reusing statement interfaces
across 'grouping'/'uses' boundaries. This poses distinct challenges as
for a particular GeneratedType we may have multiple augmentations,
which:
- may be completely unrelated. Binding Spec does not provide its usual
  compile-time safety guarantees because it basically says transporting
  anything across grouping boundaries is mostly okay as long as you
  augment all instantiations of the grouping the same way. That is a
  very sensible trade-off, as it allows, for example, no-frills movement
  of data from RPC 'input'/'output' and 'notification' structures to
  and from the datastore. More importantly it allows transportation
  across datastore subtrees, which enables very easy derivation
  pipelines
- but they have to obey YANG namespacing rules, which means that when we
  are interfacing towards yang.data.api (or any YANG-conforming
  projection), we have to make sure the constructs are aligned and also
  perform automated repair & recovery based on Binding Spec assumptions.

Current code behaves incorrectly in this respect, as it does not perform
correct expanstion of 'uses/augments' in one part, and then considers
all augments in when trying to look up a statement -- easily wandering
off into augments which are not appropriate through the YANG scope.

Fix this by correctly tracking with augments are valid in a particular
scope and carefully resolving them.

As a further side-effect of this, the choice/case relationship is
reworked to prevent potential recursion problems and rather expose the
ambiguos linkages in BindingRuntimeTypes.

We also separate CompositeRuntimeType from AugmentableRuntimeType, so
there is a clear distinction which types can be targeted by Augmentable
interfaces and which cannot.

JIRA: MDSAL-731
Change-Id: I027bbfa4ea8315b11b9348f5e0928626de3103a0
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
57 files changed:
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ChoiceNodeCodecContext.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectCodecContext.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/BindingRuntimeTypesFactory.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractAugmentGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractCompositeGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractExplicitGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractTypeObjectGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ActionGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/CaseGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ChildLookup.java [new file with mode: 0644]
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ChoiceGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/CompositeRuntimeTypeBuilder.java [new file with mode: 0644]
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ContainerGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/GroupingGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/IdentityGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/InputGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/KeyGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/LeafGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/LeafListGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ListGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ModuleGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/NotificationGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/OpaqueObjectGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/OutputGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/RpcGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/TargetAugmentEffectiveStatement.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/TypedefGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/UsesAugmentGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/AbstractAugmentableRuntimeType.java [new file with mode: 0644]
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/AbstractCompositeRuntimeType.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/AbstractRuntimeType.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultActionRuntimeType.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultAugmentRuntimeType.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultBindingRuntimeTypes.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultCaseRuntimeType.java [moved from binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/AbstractCaseRuntimeType.java with 78% similarity]
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultChoiceRuntimeType.java [moved from binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/AbstractChoiceRuntimeType.java with 67% similarity]
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultContainerRuntimeType.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultGroupingRuntimeType.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultInputRuntimeType.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultListRuntimeType.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultModuleRuntimeType.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultNotificationRuntimeType.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultOutputRuntimeType.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DerivedCaseRuntimeType.java [deleted file]
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DerivedChoiceRuntimeType.java [deleted file]
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/OriginalCaseRuntimeType.java [deleted file]
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/OriginalChoiceRuntimeType.java [deleted file]
binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/AugmentableRuntimeType.java [new file with mode: 0644]
binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/BindingRuntimeTypes.java
binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/CaseRuntimeType.java
binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/ChoiceRuntimeType.java
binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/CompositeRuntimeType.java
binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/ContainerLikeRuntimeType.java
binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/ListRuntimeType.java
binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/NotificationRuntimeType.java
binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/RuntimeTypeContainer.java
binding/mdsal-binding-spec-util/src/main/java/org/opendaylight/mdsal/binding/spec/reflect/BindingReflections.java

index 6100d4db209e08b715689758243ce6da79fef5f3..6566f9e07dac7f68eaff534394febf69ace6f1f2 100644 (file)
@@ -29,10 +29,9 @@ import java.util.Map.Entry;
 import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
+import org.opendaylight.mdsal.binding.runtime.api.BindingRuntimeContext;
 import org.opendaylight.mdsal.binding.runtime.api.CaseRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.ChoiceRuntimeType;
 import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
@@ -113,46 +112,38 @@ final class ChoiceNodeCodecContext<D extends DataObject> extends DataContainerCo
         final Map<Class<?>, DataContainerCodecPrototype<?>> byClassBuilder = new HashMap<>();
         final SetMultimap<Class<?>, DataContainerCodecPrototype<?>> childToCase =
             SetMultimapBuilder.hashKeys().hashSetValues().build();
-        final Set<Class<?>> potentialSubstitutions = new HashSet<>();
-        // Walks all cases for supplied choice in current runtime context
-        // FIXME: 9.0.0: factory short-circuits to prototype, just as getBindingClass() does
-        for (final Class<?> caze : loadCaseClasses()) {
-            // We try to load case using exact match thus name
-            // and original schema must equals
-            final DataContainerCodecPrototype<CaseRuntimeType> cazeDef = loadCase(caze);
-            // If we have case definition, this case is instantiated
-            // at current location and thus is valid in context of parent choice
-            if (cazeDef != null) {
-                byClassBuilder.put(cazeDef.getBindingClass(), cazeDef);
-                // Updates collection of case children
-                @SuppressWarnings("unchecked")
-                final Class<? extends DataObject> cazeCls = (Class<? extends DataObject>) caze;
-                for (final Class<? extends DataObject> cazeChild : BindingReflections.getChildrenClasses(cazeCls)) {
-                    childToCase.put(cazeChild, cazeDef);
-                }
-                // Updates collection of YANG instance identifier to case
-                for (var stmt : cazeDef.getType().statement().effectiveSubstatements()) {
-                    if (stmt instanceof DataSchemaNode) {
-                        final DataSchemaNode cazeChild = (DataSchemaNode) stmt;
-                        if (cazeChild.isAugmenting()) {
-                            final AugmentationSchemaNode augment = NormalizedNodeSchemaUtils.findCorrespondingAugment(
-                                // FIXME: bad cast
-                                (DataSchemaNode) cazeDef.getType().statement(), cazeChild);
-                            if (augment != null) {
-                                byYangCaseChildBuilder.put(DataSchemaContextNode.augmentationIdentifierFrom(augment),
-                                    cazeDef);
-                                continue;
-                            }
+
+        // Load case statements valid in this choice and keep track of their names
+        final var choiceType = prototype.getType();
+        final var factory = prototype.getFactory();
+        final var localCases = new HashSet<JavaTypeName>();
+        for (var caseType : choiceType.validCaseChildren()) {
+            final var cazeDef = loadCase(factory, caseType);
+            localCases.add(caseType.getIdentifier());
+            byClassBuilder.put(cazeDef.getBindingClass(), cazeDef);
+
+            // Updates collection of case children
+            @SuppressWarnings("unchecked")
+            final Class<? extends DataObject> cazeCls = (Class<? extends DataObject>) cazeDef.getBindingClass();
+            for (final Class<? extends DataObject> cazeChild : BindingReflections.getChildrenClasses(cazeCls)) {
+                childToCase.put(cazeChild, cazeDef);
+            }
+            // Updates collection of YANG instance identifier to case
+            for (var stmt : cazeDef.getType().statement().effectiveSubstatements()) {
+                if (stmt instanceof DataSchemaNode) {
+                    final DataSchemaNode cazeChild = (DataSchemaNode) stmt;
+                    if (cazeChild.isAugmenting()) {
+                        final AugmentationSchemaNode augment = NormalizedNodeSchemaUtils.findCorrespondingAugment(
+                            // FIXME: bad cast
+                            (DataSchemaNode) cazeDef.getType().statement(), cazeChild);
+                        if (augment != null) {
+                            byYangCaseChildBuilder.put(DataSchemaContextNode.augmentationIdentifierFrom(augment),
+                                cazeDef);
+                            continue;
                         }
-                        byYangCaseChildBuilder.put(NodeIdentifier.create(cazeChild.getQName()), cazeDef);
                     }
+                    byYangCaseChildBuilder.put(NodeIdentifier.create(cazeChild.getQName()), cazeDef);
                 }
-            } else {
-                /*
-                 * If case definition is not available, we store it for
-                 * later check if it could be used as substitution of existing one.
-                 */
-                potentialSubstitutions.add(caze);
             }
         }
         byYangCaseChild = ImmutableMap.copyOf(byYangCaseChildBuilder);
@@ -179,40 +170,49 @@ final class ChoiceNodeCodecContext<D extends DataObject> extends DataContainerCo
         ambiguousByCaseChildWarnings = ambiguousByCaseChildClass.isEmpty() ? ImmutableSet.of()
                 : ConcurrentHashMap.newKeySet();
 
-        final Map<Class<?>, DataContainerCodecPrototype<?>> bySubstitutionBuilder = new HashMap<>();
         /*
-         * Walks all cases which are not directly instantiated and
-         * tries to match them to instantiated cases - represent same data as instantiated case,
-         * only case name or schema path is different. This is required due property of
-         * binding specification, that if choice is in grouping schema path location is lost,
-         * and users may use incorrect case class using copy builders.
+         * Choice/Case mapping across groupings is compile-time unsafe and we therefore need to also track any
+         * CaseRuntimeTypes added to the choice in other contexts. This is necessary to discover when a case represents
+         * equivalent data in a different instantiation context.
+         *
+         * This is required due property of binding specification, that if choice is in grouping schema path location is
+         * lost, and users may use incorrect case class using copy builders.
          */
-        for (final Class<?> substitution : potentialSubstitutions) {
-            search: for (final Entry<Class<?>, DataContainerCodecPrototype<?>> real : byClassBuilder.entrySet()) {
-                if (BindingReflections.isSubstitutionFor(substitution, real.getKey())) {
-                    bySubstitutionBuilder.put(substitution, real.getValue());
-                    break search;
+        final Map<Class<?>, DataContainerCodecPrototype<?>> bySubstitutionBuilder = new HashMap<>();
+        final var context = factory.getRuntimeContext();
+        for (var caseType : context.getTypes().allCaseChildren(choiceType)) {
+            final var caseName = caseType.getIdentifier();
+            if (!localCases.contains(caseName)) {
+                // FIXME: do not rely on class loading here, the check we are performing should be possible on
+                //        GeneratedType only -- or it can be provided by BindingRuntimeTypes -- i.e. rather than
+                //        'allCaseChildren()' it would calculate additional mappings we can use off-the-bat.
+                final Class<?> substitution = loadCase(context, caseType);
+
+                search: for (final Entry<Class<?>, DataContainerCodecPrototype<?>> real : byClassBuilder.entrySet()) {
+                    if (BindingReflections.isSubstitutionFor(substitution, real.getKey())) {
+                        bySubstitutionBuilder.put(substitution, real.getValue());
+                        break search;
+                    }
                 }
             }
         }
+
         byClassBuilder.putAll(bySubstitutionBuilder);
         byClass = ImmutableMap.copyOf(byClassBuilder);
     }
 
-    private List<Class<?>> loadCaseClasses() {
-        final var context = factory().getRuntimeContext();
-        final var type = getType();
+    private static DataContainerCodecPrototype<CaseRuntimeType> loadCase(final CodecContextFactory factory,
+            final CaseRuntimeType caseType) {
+        return DataContainerCodecPrototype.from(loadCase(factory.getRuntimeContext(), caseType), caseType, factory);
+    }
 
-        return Stream.concat(type.validCaseChildren().stream(), type.additionalCaseChildren().stream())
-            .map(caseChild -> {
-                final var caseName = caseChild.getIdentifier();
-                try {
-                    return context.loadClass(caseName);
-                } catch (ClassNotFoundException e) {
-                    throw new IllegalStateException("Failed to load class for " + caseName, e);
-                }
-            })
-            .collect(Collectors.toUnmodifiableList());
+    private static Class<?> loadCase(final BindingRuntimeContext context, final CaseRuntimeType caseType) {
+        final var className = caseType.getIdentifier();
+        try {
+            return context.loadClass(className);
+        } catch (ClassNotFoundException e) {
+            throw new LinkageError("Failed to load class for " + className, e);
+        }
     }
 
     @Override
@@ -244,16 +244,6 @@ final class ChoiceNodeCodecContext<D extends DataObject> extends DataContainerCo
         return Iterables.concat(byCaseChildClass.keySet(), ambiguousByCaseChildClass.keySet());
     }
 
-    protected DataContainerCodecPrototype<CaseRuntimeType> loadCase(final Class<?> childClass) {
-        final var child = getType().bindingCaseChild(JavaTypeName.create(childClass));
-        if (child == null) {
-            LOG.debug("Supplied class {} is not valid case in schema {}", childClass, getSchema());
-            return null;
-        }
-
-        return DataContainerCodecPrototype.from(childClass, child, factory());
-    }
-
     @Override
     public NodeCodecContext yangPathArgumentChild(final YangInstanceIdentifier.PathArgument arg) {
         final DataContainerCodecPrototype<?> cazeProto;
index 52a7b06be46e728825533b2e1108251549d81ae8..47575f9321d707a46eeb43a1276d983e76127bb5 100644 (file)
@@ -15,7 +15,6 @@ import com.google.common.base.Throwables;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableMap.Builder;
 import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
@@ -33,6 +32,7 @@ import org.opendaylight.mdsal.binding.model.api.GeneratedType;
 import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
 import org.opendaylight.mdsal.binding.model.api.Type;
 import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
+import org.opendaylight.mdsal.binding.runtime.api.AugmentableRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.BindingRuntimeContext;
 import org.opendaylight.mdsal.binding.runtime.api.ChoiceRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType;
@@ -158,10 +158,13 @@ public abstract class DataObjectCodecContext<D extends DataObject, T extends Com
         this.byBindingArgClass = byStreamClassBuilder.equals(byBindingArgClassBuilder) ? this.byStreamClass
                 : ImmutableMap.copyOf(byBindingArgClassBuilder);
 
-        final Iterable<AugmentRuntimeType> possibleAugmentations;
+        final List<AugmentRuntimeType> possibleAugmentations;
         if (Augmentable.class.isAssignableFrom(bindingClass)) {
+            // Verify we have the appropriate backing runtimeType
             final var type = getType();
-            possibleAugmentations = Iterables.concat(type.augments(), type.mismatchedAugments());
+            verify(type instanceof AugmentableRuntimeType, "Unexpected type %s backing augmenable %s", type,
+                bindingClass);
+            possibleAugmentations = ((AugmentableRuntimeType) type).augments();
             generatedClass = CodecDataObjectGenerator.generateAugmentable(prototype.getFactory().getLoader(),
                 bindingClass, tmpLeaves, tmpDataObjects, keyMethod);
         } else {
@@ -433,7 +436,8 @@ public abstract class DataObjectCodecContext<D extends DataObject, T extends Com
             final var augClass = value.getBindingClass();
             // Do not perform duplicate deserialization if we have already created the corresponding augmentation
             // and validate whether the proposed augmentation is valid ion this instantiation context.
-            if (!map.containsKey(augClass) && getType().augments().contains(value.getType())) {
+            if (!map.containsKey(augClass)
+                && ((AugmentableRuntimeType) getType()).augments().contains(value.getType())) {
                 final NormalizedNode augData = data.childByArg(value.getYangArg());
                 if (augData != null) {
                     // ... make sure we do not replace an e
index a3b8807c62f8c1d12849108a1fae3659176af4cb..29df37b4041173fc2b01ff806bb55266e922880a 100644 (file)
@@ -10,6 +10,8 @@ package org.opendaylight.mdsal.binding.generator.impl;
 import static com.google.common.base.Verify.verify;
 
 import com.google.common.base.Stopwatch;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.SetMultimap;
 import java.util.HashMap;
 import java.util.Map;
 import org.eclipse.jdt.annotation.NonNull;
@@ -26,6 +28,7 @@ import org.opendaylight.mdsal.binding.generator.impl.rt.DefaultBindingRuntimeTyp
 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
 import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
 import org.opendaylight.mdsal.binding.runtime.api.BindingRuntimeTypes;
+import org.opendaylight.mdsal.binding.runtime.api.CaseRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.IdentityRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.InputRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.ModuleRuntimeType;
@@ -51,6 +54,8 @@ final class BindingRuntimeTypesFactory implements Mutable {
     private final Map<QName, OutputRuntimeType> rpcOutputs = new HashMap<>();
     // All RpcInputs, indexed by their RPC's QName
     private final Map<QName, InputRuntimeType> rpcInputs = new HashMap<>();
+    // All known 'choice's to their corresponding cases
+    private final SetMultimap<JavaTypeName, CaseRuntimeType> choiceToCases = HashMultimap.create();
 
     private BindingRuntimeTypesFactory() {
         // Hidden on purpose
@@ -65,7 +70,7 @@ final class BindingRuntimeTypesFactory implements Mutable {
         LOG.debug("Indexed {} generators in {}", moduleGens.size(), sw);
 
         return new DefaultBindingRuntimeTypes(context, factory.modules, factory.allTypes, factory.identities,
-            factory.rpcInputs, factory.rpcOutputs);
+            factory.rpcInputs, factory.rpcOutputs, factory.choiceToCases);
     }
 
     private void indexModules(final Map<QNameModule, ModuleGenerator> moduleGens) {
@@ -111,6 +116,17 @@ final class BindingRuntimeTypesFactory implements Mutable {
                     final var prev = allTypes.put(name, type);
                     verify(prev == null || prev == type, "Conflict on runtime type mapping of %s between %s and %s",
                         name, prev, type);
+
+                    // Global indexing of cases generated for a particular choice. We look at the Generated type
+                    // and make assumptions about its shape -- which works just fine without touching the
+                    // ChoiceRuntimeType for cases.
+                    if (type instanceof CaseRuntimeType) {
+                        final var ifaces = ((GeneratedType) javaType).getImplements();
+                        // The appropriate choice and DataObject at the very least. The choice interface is the first
+                        // one mentioned.
+                        verify(ifaces.size() >= 2, "Unexpected implemented interfaces %s", ifaces);
+                        choiceToCases.put(ifaces.get(0).getIdentifier(), (CaseRuntimeType) type);
+                    }
                 }
             }
             indexRuntimeTypes(gen);
index 5a018acdb50257cf2d33f860b10bdd25190deded..d52d09632b0ace7f9401967a1b4611f5db1b165f 100644 (file)
@@ -11,10 +11,13 @@ import static com.google.common.base.Verify.verify;
 import static com.google.common.base.Verify.verifyNotNull;
 import static java.util.Objects.requireNonNull;
 
+import com.google.common.collect.ImmutableList;
 import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Optional;
 import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.mdsal.binding.generator.impl.reactor.CollisionDomain.Member;
 import org.opendaylight.mdsal.binding.generator.impl.rt.DefaultAugmentRuntimeType;
 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
@@ -22,13 +25,17 @@ import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilde
 import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilderBase;
 import org.opendaylight.mdsal.binding.model.ri.BindingTypes;
 import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
+import org.opendaylight.mdsal.binding.runtime.api.CaseRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
 import org.opendaylight.yangtools.odlext.model.api.AugmentIdentifierEffectiveStatement;
 import org.opendaylight.yangtools.yang.common.AbstractQName;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.AugmentEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ChoiceEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeAwareEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeAwareEffectiveStatement.SchemaTreeNamespace;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
 
 /**
@@ -85,8 +92,9 @@ abstract class AbstractAugmentGenerator
         return otherIt.hasNext() ? -1 : 0;
     };
 
-    private AugmentEffectiveStatement effectiveStatement;
+    private SchemaTreeAwareEffectiveStatement<?, ?> targetStatement;
     private AbstractCompositeGenerator<?, ?> targetGen;
+    private Optional<AugmentRuntimeType> internalRuntimeType;
 
     AbstractAugmentGenerator(final AugmentEffectiveStatement statement, final AbstractCompositeGenerator<?, ?> parent) {
         super(statement, parent);
@@ -147,17 +155,52 @@ abstract class AbstractAugmentGenerator
         return builder.build();
     }
 
-    @Override
-    final AugmentEffectiveStatement effectiveStatement() {
-        return verifyNotNull(effectiveStatement, "Effective statement not set in %s", this);
+    @NonNull List<CaseRuntimeType> augmentedCasesIn(final ChildLookup lookup, final ChoiceEffectiveStatement stmt) {
+        final var target = verifyNotNull(targetStatement);
+        if (!stmt.equals(target)) {
+            return List.of();
+        }
+
+        final var result = createBuilder(effectiveStatement(statement(), target))
+            .fillTypes(ChildLookup.of(target), this)
+            .getCaseChilden();
+        internalRuntimeType = Optional.empty();
+        return result;
     }
 
-    @Override
-    final AugmentRuntimeType createRuntimeType(final GeneratedType type, final AugmentEffectiveStatement statement,
-            final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
-        verify(statement instanceof TargetAugmentEffectiveStatement, "Unexpected statement %s", statement);
-        return new DefaultAugmentRuntimeType(type, ((TargetAugmentEffectiveStatement) statement).delegate(), children,
-            augments);
+    @Nullable AugmentRuntimeType runtimeTypeIn(final ChildLookup lookup, final EffectiveStatement<?, ?> stmt) {
+        final var target = verifyNotNull(targetStatement);
+        if (!stmt.equals(target)) {
+            return null;
+        }
+        if (internalRuntimeType != null) {
+            return internalRuntimeType.orElseThrow();
+        }
+
+        final var result = verifyNotNull(createInternalRuntimeType(ChildLookup.of(target),
+            effectiveStatement(statement(), target)));
+        internalRuntimeType = Optional.of(result);
+        return result;
+    }
+
+    private static @NonNull AugmentEffectiveStatement effectiveStatement(final AugmentEffectiveStatement augment,
+            final SchemaTreeAwareEffectiveStatement<?, ?> target) {
+        final var stmts = augment.effectiveSubstatements();
+        final var builder = ImmutableList.<EffectiveStatement<?, ?>>builderWithExpectedSize(stmts.size());
+        for (var child : stmts) {
+            if (child instanceof SchemaTreeEffectiveStatement) {
+                final var qname = ((SchemaTreeEffectiveStatement<?>) child).getIdentifier();
+                // FIXME: orElseThrow()?
+                target.get(SchemaTreeNamespace.class, qname).ifPresent(builder::add);
+            } else {
+                builder.add(child);
+            }
+        }
+        return new TargetAugmentEffectiveStatement(augment, target, builder.build());
+    }
+
+    final @Nullable AugmentRuntimeType getInternalRuntimeType() {
+        return verifyNotNull(internalRuntimeType, "Internal runtime not resolved in %s", this).orElse(null);
     }
 
     @Override
@@ -165,6 +208,20 @@ abstract class AbstractAugmentGenerator
         // Augments are never added as getters, as they are handled via Augmentable mechanics
     }
 
+    @Override
+    CompositeRuntimeTypeBuilder<AugmentEffectiveStatement, AugmentRuntimeType> createBuilder(
+            final AugmentEffectiveStatement statement) {
+        return new CompositeRuntimeTypeBuilder<>(statement) {
+            @Override
+            AugmentRuntimeType build(final GeneratedType type, final AugmentEffectiveStatement statement,
+                    final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
+                // 'augment' cannot be targeted by augment
+                verify(augments.isEmpty(), "Unexpected augments %s", augments);
+                return new DefaultAugmentRuntimeType(type, statement, children);
+            }
+        };
+    }
+
     final void setTargetGenerator(final AbstractCompositeGenerator<?, ?> targetGenerator) {
         verify(targetGen == null, "Attempted to relink %s, already have target %s", this, targetGen);
         targetGen = requireNonNull(targetGenerator);
@@ -177,7 +234,6 @@ abstract class AbstractAugmentGenerator
     final void setTargetStatement(final EffectiveStatement<?, ?> targetStatement) {
         verify(targetStatement instanceof SchemaTreeAwareEffectiveStatement, "Unexpected target statement %s",
             targetStatement);
-        effectiveStatement = new TargetAugmentEffectiveStatement(statement(),
-            (SchemaTreeAwareEffectiveStatement<?, ?>) targetStatement);
+        this.targetStatement = (SchemaTreeAwareEffectiveStatement<?, ?>) targetStatement;
     }
 }
index e88739a72ce0a4dc9012a12fa7700a7cd6c1c4ee..769830433f7ff6ebd94c6e29b5ef573818c9cdbc 100644 (file)
@@ -11,20 +11,18 @@ import static com.google.common.base.Verify.verify;
 import static com.google.common.base.Verify.verifyNotNull;
 import static java.util.Objects.requireNonNull;
 
-import com.google.common.collect.ImmutableList;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Optional;
 import java.util.stream.Collectors;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.mdsal.binding.model.api.Enumeration;
 import org.opendaylight.mdsal.binding.model.api.GeneratedTransferObject;
 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
+import org.opendaylight.mdsal.binding.model.api.Type;
 import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilder;
 import org.opendaylight.mdsal.binding.model.ri.BindingTypes;
-import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -162,77 +160,38 @@ public abstract class AbstractCompositeGenerator<S extends EffectiveStatement<?,
         return childGenerators.iterator();
     }
 
-    @NonNull S effectiveStatement() {
-        return statement();
-    }
-
     @Override
-    public final R createRuntimeType() {
-        return generatedType()
-            .map(type -> {
-                final var stmt = effectiveStatement();
-                return createRuntimeType(type, stmt, indexChildren(stmt), augmentRuntimeTypes());
-            })
-            .orElse(null);
+    final GeneratedType runtimeJavaType() {
+        return generatedType().orElse(null);
     }
 
-    abstract @NonNull R createRuntimeType(@NonNull GeneratedType type, @NonNull S statement,
-        @NonNull List<RuntimeType> children, @NonNull List<AugmentRuntimeType> augments);
-
-    @Override
-    final R rebaseRuntimeType(final R type, final S statement) {
-        return createRuntimeType(type.javaType(), statement, indexChildren(statement), augmentRuntimeTypes());
+    final @NonNull List<AbstractAugmentGenerator> augments() {
+        return augments;
     }
 
-    private @NonNull List<RuntimeType> indexChildren(final @NonNull S statement) {
-        final var childMap = new ArrayList<RuntimeType>();
-
-        for (var stmt : statement.effectiveSubstatements()) {
-            if (stmt instanceof SchemaTreeEffectiveStatement) {
-                final var child = (SchemaTreeEffectiveStatement<?>) stmt;
-                final var qname = child.getIdentifier();
-
-                // Note: getOriginal() is needed for augments of cases
-                @SuppressWarnings("rawtypes")
-                final AbstractExplicitGenerator childGen = getOriginal().resolveRuntimeChild(statement.argument(),
-                    qname);
-                @SuppressWarnings("unchecked")
-                final Optional<RuntimeType> rt = childGen.runtimeTypeOf(child);
-                rt.ifPresent(childMap::add);
-            }
-        }
-
-        return childMap;
+    final @NonNull List<GroupingGenerator> groupings() {
+        return verifyNotNull(groupings, "Groupings not initialized in %s", this);
     }
 
-    private @NonNull AbstractExplicitGenerator<?, ?> resolveRuntimeChild(final Object parentArg, final QName qname) {
-        final var exact = findSchemaTreeGenerator(qname);
-        if (exact != null) {
-            return exact;
-        }
-
-        // TODO: this is quite hacky: what we are trying to do is rebase the lookup QName to parent QName, as the only
-        //       way we should be arriving here is through uses -> grouping squash
-        verify(parentArg instanceof QName, "Cannot deal with parent argument %s", parentArg);
-        final var namespace = ((QName) parentArg).getModule();
+    @Override
+    final R createExternalRuntimeType(final Type type) {
+        verify(type instanceof GeneratedType, "Unexpected type %s", type);
 
-        verify(namespace.equals(qname.getModule()), "Cannot deal with %s in namespace %s", qname, namespace);
-        final var local = qname.bindTo(getQName().getModule());
-        return verifyNotNull(findSchemaTreeGenerator(local), "Failed to find %s as %s in %s", qname, local, this);
+        // FIXME: we should be able to use internal cache IFF when all augments end up being local to our statement
+        final var statement = statement();
+        return createBuilder(statement)
+            .fillTypes(ChildLookup.of(statement), this)
+            .build((GeneratedType) type);
     }
 
-    final @NonNull List<AbstractAugmentGenerator> augments() {
-        return augments;
-    }
+    abstract @NonNull CompositeRuntimeTypeBuilder<S, R> createBuilder(S statement);
 
-    private @NonNull List<AugmentRuntimeType> augmentRuntimeTypes() {
-        // Augments are attached to original instance: at least CaseGenerator is instantiated in non-original place
-        // and thus we need to go back to original
-        return getOriginal().augments.stream()
-            .map(AbstractAugmentGenerator::runtimeType)
-            .filter(Optional::isPresent)
-            .map(Optional::orElseThrow)
-            .collect(ImmutableList.toImmutableList());
+    @Override
+    final R createInternalRuntimeType(final ChildLookup lookup, final S statement, final Type type) {
+        verify(type instanceof GeneratedType, "Unexpected type %s", type);
+        return createBuilder(statement)
+            .fillTypes(lookup.inStatement(statement), this)
+            .build((GeneratedType) type);
     }
 
     @Override
index 67883f3f94d382f3cb9ad94428b978e07c7ddb1b..5219378e39fdb1535008934212492f9cdf149410 100644 (file)
@@ -79,35 +79,81 @@ public abstract class AbstractExplicitGenerator<S extends EffectiveStatement<?,
     }
 
     /**
-     * Return the {@link RuntimeType} associated with this object, of applicable.
+     * Return the {@link RuntimeType} associated with this object, if applicable. This represents the
+     * externally-accessible view of this object when considered outside the schema tree or binding tree hierarchy.
      *
      * @return Associated run-time type, or empty
      */
     public final Optional<R> runtimeType() {
         if (!runtimeTypeInitialized) {
-            runtimeType = createRuntimeType();
+            final var type = runtimeJavaType();
+            if (type != null) {
+                runtimeType = createExternalRuntimeType(type);
+            }
             runtimeTypeInitialized = true;
         }
         return Optional.ofNullable(runtimeType);
     }
 
-    final Optional<R> runtimeTypeOf(final @NonNull S stmt) {
+    /**
+     * Return the {@link Type} associated with this object at run-time, if applicable. This method often synonymous
+     * with {@code generatedType().orElseNull()}, but not always. For example
+     * <pre>
+     *   <code>
+     *     leaf foo {
+     *       type string;
+     *     }
+     *   </code>
+     * </pre>
+     * Results in an empty {@link #generatedType()}, but still produces a {@code java.lang.String}-based
+     * {@link RuntimeType}.
+     *
+     * @return Associated {@link Type}
+     */
+    // FIXME: this should be a generic class argument
+    // FIXME: this needs a better name, but 'runtimeType' is already taken.
+    abstract @Nullable Type runtimeJavaType();
+
+    /**
+     * Create the externally-accessible {@link RuntimeType} view of this object. The difference between
+     * this method and {@link #createInternalRuntimeType(EffectiveStatement)} is that this method represents the view
+     * attached to {@link #statement()} and contains a separate global view of all available augmentations attached to
+     * the GeneratedType.
+     *
+     * @param type {@link Type} associated with this object, as returned by {@link #runtimeJavaType()}
+     * @return Externally-accessible RuntimeType
+     */
+    abstract @NonNull R createExternalRuntimeType(@NonNull Type type);
+
+    /**
+     * Create the internally-accessible {@link RuntimeType} view of this object, if applicable. The difference between
+     * this method and {@link #createExternalRuntimeType()} is that this represents the view attached to the specified
+     * {@code stmt}, which is supplied by the parent statement. The returned {@link RuntimeType} always reports the
+     * global view of attached augmentations as empty.
+     *
+     * @param lookup context to use when looking up child statements
+     * @param stmt Statement for which to create the view
+     * @return Internally-accessible RuntimeType, or {@code null} if not applicable
+     */
+    final @Nullable R createInternalRuntimeType(final @NonNull ChildLookup lookup, final @NonNull S stmt) {
+        // FIXME: cache requests: if we visited this statement, we obviously know what it entails. Note that we walk
+        //        towards the original definition. As such, the cache may have to live in the generator we look up,
+        //        but should operate on this statement to reflect lookups. This needs a bit of figuring out.
         var gen = this;
         do {
-            final var ret = gen.runtimeType();
-            if (ret.isPresent()) {
-                return Optional.of(rebaseRuntimeType(ret.orElseThrow(), stmt));
+            final var type = gen.runtimeJavaType();
+            if (type != null) {
+                return createInternalRuntimeType(lookup, stmt, type);
             }
 
             gen = gen.previous();
         } while (gen != null);
 
-        return Optional.empty();
+        return null;
     }
 
-    abstract @Nullable R createRuntimeType();
-
-    abstract @NonNull R rebaseRuntimeType(@NonNull R type, @NonNull S statement);
+    abstract @NonNull R createInternalRuntimeType(@NonNull ChildLookup lookup, @NonNull S statement,
+        @NonNull Type type);
 
     @Override
     public final boolean isAddedByUses() {
index 2c41edb80b4ef86274aa392810fbae5e96c936ea..845fb0dcba8b4f785f946ff92d50966b9c676581 100644 (file)
@@ -457,20 +457,18 @@ abstract class AbstractTypeObjectGenerator<S extends EffectiveStatement<?, ?>, R
     }
 
     @Override
-    final R createRuntimeType() {
+    final Type runtimeJavaType() {
         if (methodReturnTypeElement != null) {
-            return createRuntimeType(methodReturnTypeElement);
+            return methodReturnTypeElement;
         }
         final var genType = generatedType();
         if (genType.isPresent()) {
-            return createRuntimeType(genType.orElseThrow());
+            return genType.orElseThrow();
         }
         final var prev = verifyNotNull(previous(), "No previous generator for %s", this);
-        return prev.runtimeType().orElse(null);
+        return prev.runtimeJavaType();
     }
 
-    abstract @NonNull R createRuntimeType(Type type);
-
     final @NonNull Type methodReturnElementType(final @NonNull TypeBuilderFactory builderFactory) {
         var local = methodReturnTypeElement;
         if (local == null) {
index 8b0c9b9b22c7ddd97084fee0cf5119e1eea0ddda..19cca901a5e8cce304992671d1f0d0fab1203e15 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.mdsal.binding.generator.impl.reactor;
 
+import static com.google.common.base.Verify.verify;
+
 import java.util.List;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.mdsal.binding.generator.impl.rt.DefaultActionRuntimeType;
@@ -60,12 +62,6 @@ final class ActionGenerator extends CompositeSchemaTreeGenerator<ActionEffective
         return builder.build();
     }
 
-    @Override
-    ActionRuntimeType createRuntimeType(final GeneratedType type, final ActionEffectiveStatement statement,
-            final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
-        return new DefaultActionRuntimeType(type, statement, children, augments);
-    }
-
     private @NonNull Type implementedType(final TypeBuilderFactory builderFactory) {
         final GeneratedType input = getChild(this, InputEffectiveStatement.class).getOriginal()
             .getGeneratedType(builderFactory);
@@ -88,4 +84,17 @@ final class ActionGenerator extends CompositeSchemaTreeGenerator<ActionEffective
     void addAsGetterMethod(final GeneratedTypeBuilderBase<?> builder, final TypeBuilderFactory builderFactory) {
         // actions are a separate concept
     }
+
+    @Override
+    CompositeRuntimeTypeBuilder<ActionEffectiveStatement, ActionRuntimeType> createBuilder(
+            final ActionEffectiveStatement statement) {
+        return new CompositeRuntimeTypeBuilder<>(statement) {
+            @Override
+            ActionRuntimeType build(final GeneratedType generatedType, final ActionEffectiveStatement statement,
+                    final List<RuntimeType> childTypes, final List<AugmentRuntimeType> augmentTypes) {
+                verify(augmentTypes.isEmpty(), "Unexpected augments %s", augmentTypes);
+                return new DefaultActionRuntimeType(generatedType, statement, childTypes);
+            }
+        };
+    }
 }
index 1b3bc495db6487f65e8d42dbdc235f69e9129166..f49f371aca0c755d401c1b94959ca2aa80bdfa10 100644 (file)
@@ -10,8 +10,7 @@ package org.opendaylight.mdsal.binding.generator.impl.reactor;
 import static com.google.common.base.Verify.verify;
 
 import java.util.List;
-import org.opendaylight.mdsal.binding.generator.impl.rt.DerivedCaseRuntimeType;
-import org.opendaylight.mdsal.binding.generator.impl.rt.OriginalCaseRuntimeType;
+import org.opendaylight.mdsal.binding.generator.impl.rt.DefaultCaseRuntimeType;
 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
 import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilder;
 import org.opendaylight.mdsal.binding.model.ri.BindingTypes;
@@ -36,8 +35,6 @@ final class CaseGenerator extends CompositeSchemaTreeGenerator<CaseEffectiveStat
 
     @Override
     GeneratedType createTypeImpl(final TypeBuilderFactory builderFactory) {
-        final GeneratedTypeBuilder builder = builderFactory.newGeneratedTypeBuilder(typeName());
-        builder.addImplementsType(BindingTypes.DATA_OBJECT);
 
         // We also are implementing target choice's type. This is tricky, as we need to cover two distinct cases:
         // - being a child of a choice (i.e. normal definition)
@@ -55,8 +52,13 @@ final class CaseGenerator extends CompositeSchemaTreeGenerator<CaseEffectiveStat
 
         // Most generators have a parent->child dependency due to parent methods' return types and therefore children
         // must not request parent's type. That is not true for choice->case relationship and hence we do not need to
-        // go through DefaultType here.
+        // go through DefaultType here
+        final GeneratedTypeBuilder builder = builderFactory.newGeneratedTypeBuilder(typeName());
+        // Note: this needs to be the first type we mention as we are relying on that fact for global runtime type
+        //       choice/case indexing.
         builder.addImplementsType(choice.getGeneratedType(builderFactory));
+
+        builder.addImplementsType(BindingTypes.DATA_OBJECT);
         addAugmentable(builder);
         addUsesInterfaces(builder, builderFactory);
         addConcreteInterfaceMethods(builder);
@@ -74,11 +76,14 @@ final class CaseGenerator extends CompositeSchemaTreeGenerator<CaseEffectiveStat
     }
 
     @Override
-    CaseRuntimeType createRuntimeType(final GeneratedType type, final CaseEffectiveStatement statement,
-            final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
-        final var original = getOriginal();
-        return statement.equals(original.statement())
-            ? new OriginalCaseRuntimeType(type, statement, children, augments)
-                : new DerivedCaseRuntimeType(type, statement, children, augments, original.runtimeType().orElseThrow());
+    CompositeRuntimeTypeBuilder<CaseEffectiveStatement, CaseRuntimeType> createBuilder(
+            final CaseEffectiveStatement statement) {
+        return new CompositeRuntimeTypeBuilder<>(statement) {
+            @Override
+            CaseRuntimeType build(final GeneratedType generatedType, final CaseEffectiveStatement statement,
+                    final List<RuntimeType> childTypes, final List<AugmentRuntimeType> augmentTypes) {
+                return new DefaultCaseRuntimeType(generatedType, statement, childTypes, augmentTypes);
+            }
+        };
     }
 }
diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ChildLookup.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ChildLookup.java
new file mode 100644 (file)
index 0000000..083bf08
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2022 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.mdsal.binding.generator.impl.reactor;
+
+import static com.google.common.base.Verify.verify;
+import static com.google.common.base.Verify.verifyNotNull;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableSet;
+import java.util.stream.Stream;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.AugmentEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.UsesEffectiveStatement;
+
+/**
+ * Lookup context for dealing with namespace translation during execution of {@link AbstractCompositeGenerator}'s
+ * createInternalRuntimeType(). It tracks which namespaces should be translated on account of crossing into source
+ * {@code grouping} statement.
+ */
+final class ChildLookup implements Immutable {
+    private final ImmutableSet<AugmentEffectiveStatement> validUsesAugments;
+    private final ImmutableSet<QNameModule> squashNamespaces;
+    private final QNameModule localNamespace;
+
+    private ChildLookup(final ImmutableSet<AugmentEffectiveStatement> validUsesAugments,
+            final ImmutableSet<QNameModule> squashNamespaces, final QNameModule localNamespace) {
+        this.validUsesAugments = requireNonNull(validUsesAugments);
+        this.squashNamespaces = requireNonNull(squashNamespaces);
+        this.localNamespace = localNamespace;
+        verify(localNamespace == null == squashNamespaces.isEmpty(), "Unexpected lookup state %s", this);
+    }
+
+    public static @NonNull ChildLookup of(final EffectiveStatement<?, ?> statement) {
+        return new ChildLookup(streamUsesAugments(statement).collect(ImmutableSet.toImmutableSet()), ImmutableSet.of(),
+            null);
+    }
+
+    @NonNull QName adjustQName(final @NonNull QName qname) {
+        return squashNamespaces.contains(qname.getModule()) ? qname.bindTo(verifyNotNull(localNamespace)) : qname;
+    }
+
+    boolean contains(final AugmentEffectiveStatement augment) {
+        return validUsesAugments.contains(augment);
+    }
+
+    @NonNull ChildLookup inStatement(final EffectiveStatement<?, ?> statememt) {
+        return hasUsesAugments(statememt)
+            ? new ChildLookup(concatUsesAugments(statememt), squashNamespaces, localNamespace) : this;
+    }
+
+    @NonNull ChildLookup inGrouping(final QName qname, final GroupingGenerator grouping) {
+        final var statement = grouping.statement();
+        final var grpNamespace = statement.argument().getModule();
+        final var itemNamespace = qname.getModule();
+
+        final ImmutableSet<QNameModule> newSquashNamespaces;
+        if (squashNamespaces.contains(itemNamespace)) {
+            newSquashNamespaces = squashNamespaces;
+        } else {
+            newSquashNamespaces = ImmutableSet.<QNameModule>builderWithExpectedSize(squashNamespaces.size() + 1)
+                .addAll(squashNamespaces).add(itemNamespace).build();
+        }
+
+        return new ChildLookup(hasUsesAugments(statement) ? concatUsesAugments(statement) : validUsesAugments,
+            newSquashNamespaces, grpNamespace);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this).omitNullValues()
+            .add("augments", validUsesAugments)
+            .add("squash", squashNamespaces)
+            .add("local", localNamespace)
+            .toString();
+    }
+
+    private ImmutableSet<AugmentEffectiveStatement> concatUsesAugments(final EffectiveStatement<?, ?> stmt) {
+        final var concat = ImmutableSet.<AugmentEffectiveStatement>builder().addAll(validUsesAugments);
+        streamUsesAugments(stmt).forEach(concat::add);
+        return concat.build();
+    }
+
+    private static boolean hasUsesAugments(final EffectiveStatement<?, ?> stmt) {
+        return streamUsesAugments(stmt).findAny().isPresent();
+    }
+
+    private static Stream<AugmentEffectiveStatement> streamUsesAugments(final EffectiveStatement<?, ?> stmt) {
+        return stmt.streamEffectiveSubstatements(UsesEffectiveStatement.class)
+            .flatMap(uses -> uses.streamEffectiveSubstatements(AugmentEffectiveStatement.class));
+    }
+}
index 1a6ac7fe5bc4146853c54ec5b0d8bebdf0e0b55f..1b73a7d4d55be018dd55f98437c46d0770e0a535 100644 (file)
@@ -7,11 +7,11 @@
  */
 package org.opendaylight.mdsal.binding.generator.impl.reactor;
 
-import com.google.common.collect.Iterables;
-import java.util.ArrayList;
+import static com.google.common.base.Verify.verify;
+
+import com.google.common.collect.ImmutableList;
 import java.util.List;
-import org.opendaylight.mdsal.binding.generator.impl.rt.DerivedChoiceRuntimeType;
-import org.opendaylight.mdsal.binding.generator.impl.rt.OriginalChoiceRuntimeType;
+import org.opendaylight.mdsal.binding.generator.impl.rt.DefaultChoiceRuntimeType;
 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
 import org.opendaylight.mdsal.binding.model.api.Type;
 import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilder;
@@ -20,6 +20,7 @@ import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.CaseRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.ChoiceRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
+import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.stmt.ChoiceEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
 
@@ -27,6 +28,48 @@ import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
  * Generator corresponding to a {@code choice} statement.
  */
 final class ChoiceGenerator extends CompositeSchemaTreeGenerator<ChoiceEffectiveStatement, ChoiceRuntimeType> {
+    static final class ChoiceBuilder extends CompositeRuntimeTypeBuilder<ChoiceEffectiveStatement, ChoiceRuntimeType> {
+        private ImmutableList<CaseRuntimeType> augmentedCases;
+
+        ChoiceBuilder(final ChoiceEffectiveStatement statement) {
+            super(statement);
+        }
+
+        @Override
+        CompositeRuntimeTypeBuilder<ChoiceEffectiveStatement, ChoiceRuntimeType> fillTypes(
+                final ChildLookup lookup,
+                final AbstractCompositeGenerator<ChoiceEffectiveStatement, ChoiceRuntimeType> generator) {
+            fillAugmentedCases(lookup, generator.augments());
+            return super.fillTypes(lookup, generator);
+        }
+
+        @Override
+        boolean isAugmentedChild(final ChildLookup lookup, final QName qname) {
+            for (var augmented : augmentedCases) {
+                if (qname.equals(augmented.statement().argument())) {
+                    return true;
+                }
+            }
+            return super.isAugmentedChild(lookup, qname);
+        }
+
+        @Override
+        ChoiceRuntimeType build(final GeneratedType type, final ChoiceEffectiveStatement statement,
+                final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
+            verify(augments.isEmpty(), "Unexpected augments %s", augments);
+            children.addAll(augmentedCases);
+            return new DefaultChoiceRuntimeType(type, statement, children);
+        }
+
+        private void fillAugmentedCases(final ChildLookup lookup, final List<AbstractAugmentGenerator> augments) {
+            final var builder = ImmutableList.<CaseRuntimeType>builder();
+            for (var augment : augments) {
+                builder.addAll(augment.augmentedCasesIn(lookup, statement()));
+            }
+            augmentedCases = builder.build();
+        }
+    }
+
     ChoiceGenerator(final ChoiceEffectiveStatement statement, final AbstractCompositeGenerator<?, ?> parent) {
         super(statement, parent);
     }
@@ -53,38 +96,7 @@ final class ChoiceGenerator extends CompositeSchemaTreeGenerator<ChoiceEffective
     }
 
     @Override
-    ChoiceRuntimeType createRuntimeType(final GeneratedType type, final ChoiceEffectiveStatement statement,
-            final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
-        final var original = getOriginal();
-        if (!statement.equals(original.statement())) {
-            return new DerivedChoiceRuntimeType(type, statement, children, augments,
-                original.runtimeType().orElseThrow());
-        }
-
-        // Pick up any case statements added by augments which are not reflected in our children. This can happen when
-        // a choice is added via uses into two different places and then augmented. Since groupings are reused, validity
-        // of such use is not guarded by compile-time checks.
-        //
-        // Furthermore such case statements can be freely propagated via copy builders and thus can occur in unexpected
-        // places. If that happens, though, the two case statements can be equivalent, e.g. by having the exact same
-        // shape -- in which case Binding -> DOM translation needs to correct this mishap and play pretend the correct
-        // case was used.
-        final var augmentedCases = new ArrayList<CaseRuntimeType>();
-        for (var augment : original.augments()) {
-            for (var gen : augment) {
-                if (gen instanceof CaseGenerator) {
-                    ((CaseGenerator) gen).runtimeType().ifPresent(augmented -> {
-                        for (var child : Iterables.concat(children, augmentedCases)) {
-                            if (child instanceof CaseRuntimeType && child.javaType().equals(augmented.javaType())) {
-                                return;
-                            }
-                        }
-                        augmentedCases.add(augmented);
-                    });
-                }
-            }
-        }
-
-        return new OriginalChoiceRuntimeType(type, statement, children, augments, augmentedCases);
+    ChoiceBuilder createBuilder(final ChoiceEffectiveStatement statement) {
+        return new ChoiceBuilder(statement);
     }
 }
diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/CompositeRuntimeTypeBuilder.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/CompositeRuntimeTypeBuilder.java
new file mode 100644 (file)
index 0000000..57af558
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2022 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.mdsal.binding.generator.impl.reactor;
+
+import static com.google.common.base.Verify.verify;
+import static com.google.common.base.Verify.verifyNotNull;
+import static java.util.Objects.requireNonNull;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.mdsal.binding.model.api.GeneratedType;
+import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
+import org.opendaylight.mdsal.binding.runtime.api.CaseRuntimeType;
+import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType;
+import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
+
+abstract class CompositeRuntimeTypeBuilder<S extends EffectiveStatement<?, ?>, R extends CompositeRuntimeType> {
+    private final List<AugmentRuntimeType> augmentTypes = new ArrayList<>();
+    private final List<RuntimeType> childTypes = new ArrayList<>();
+    private final @NonNull S statement;
+
+    CompositeRuntimeTypeBuilder(final S statement) {
+        this.statement = requireNonNull(statement);
+    }
+
+    final @NonNull S statement() {
+        return statement;
+    }
+
+    final @NonNull List<CaseRuntimeType> getCaseChilden() {
+        return childTypes.stream()
+            .map(child -> {
+                verify(child instanceof CaseRuntimeType, "Unexpected child %s in %s", child, statement);
+                return (CaseRuntimeType) child;
+            })
+            .collect(Collectors.toUnmodifiableList());
+    }
+
+    final @NonNull R build(final @NonNull GeneratedType generatedType) {
+        return build(generatedType, statement, childTypes, augmentTypes);
+    }
+
+    abstract @NonNull R build(GeneratedType type, S statement, List<RuntimeType> children,
+        List<AugmentRuntimeType> augments);
+
+    CompositeRuntimeTypeBuilder<S, R> fillTypes(final ChildLookup lookup,
+            final AbstractCompositeGenerator<S, R> generator) {
+        // Figure out which augments are valid in target statement and record their RuntimeTypes.
+        // We will pass the latter to create method. We will use the former to perform replacement lookups instead
+        // of 'this.augments'. That is necessary because 'this.augments' holds all augments targeting the GeneratedType,
+        // hence equivalent augmentations from differing places would match our lookup and the reverse search would be
+        // lead astray.
+        //
+        // Augments targeting 'choice' statement are handled by a separate class and need to be skipped here
+        if (!(generator instanceof ChoiceGenerator)) {
+            for (var augment : generator.augments()) {
+                final var augmentRuntimeType = augment.runtimeTypeIn(lookup, statement);
+                if (augmentRuntimeType != null) {
+                    augmentTypes.add(augmentRuntimeType);
+                }
+            }
+        }
+
+        // Now construct RuntimeTypes for each schema tree child of stmt
+        for (var stmt : statement.effectiveSubstatements()) {
+            if (stmt instanceof SchemaTreeEffectiveStatement) {
+                final var child = (SchemaTreeEffectiveStatement<?>) stmt;
+                final var qname = child.getIdentifier();
+
+                // Try valid augments first: they should be empty most of the time and filter all the cases where we
+                // would not find the streamChild among our local and grouping statements. Note that unlike all others,
+                // such matches are not considered to be children in Binding DataObject tree, they are only considered
+                // such in the schema tree.
+                if (isAugmentedChild(lookup, qname)) {
+                    continue;
+                }
+
+                final var childRuntimeType = findChildRuntimeType(lookup, generator, child);
+                if (childRuntimeType != null) {
+                    childTypes.add(childRuntimeType);
+                }
+            }
+        }
+
+        return this;
+    }
+
+    @SuppressWarnings("unchecked")
+    final <X extends SchemaTreeEffectiveStatement<?>> @Nullable RuntimeType findChildRuntimeType(
+            final @NonNull ChildLookup lookup, final AbstractCompositeGenerator<?, ?> parent, final @NonNull X stmt) {
+        final var qname = stmt.getIdentifier();
+        // First try our local items without adjustment ...
+        @SuppressWarnings("rawtypes")
+        AbstractExplicitGenerator childGen = findChild(parent, qname);
+        if (childGen == null) {
+            // No luck, let's see if any of the groupings can find it
+            for (GroupingGenerator grouping : parent.groupings()) {
+                final var gen = grouping.findSchemaTreeGenerator(
+                    qname.bindTo(grouping.statement().argument().getModule()));
+                if (gen != null) {
+                    return findChildRuntimeType(lookup.inGrouping(qname, grouping), grouping, stmt);
+                }
+            }
+
+            // Finally attempt to find adjusted QName: this has to succeed
+            final var adjusted = lookup.adjustQName(qname);
+            childGen = verifyNotNull(findChild(parent, adjusted),
+                "Failed to find %s as %s in %s", stmt, adjusted, this);
+        }
+
+        return childGen.createInternalRuntimeType(lookup, stmt);
+    }
+
+    boolean isAugmentedChild(final ChildLookup lookup, final QName qname) {
+        // Note we are dealing with two different kinds of augments and they behave differently with respect
+        // to namespaces. Top-level augments do not make an adjustment, while uses-augments do.
+        return augmentTypes.stream().anyMatch(augment -> augment.schemaTreeChild(qname) != null);
+    }
+
+    private static @Nullable AbstractExplicitGenerator<?, ?> findChild(final AbstractCompositeGenerator<?, ?> parent,
+            final QName qname) {
+        for (var child : parent) {
+            if (child instanceof AbstractExplicitGenerator) {
+                final AbstractExplicitGenerator<?, ?> gen = (AbstractExplicitGenerator<?, ?>) child;
+                final EffectiveStatement<?, ?> stmt = gen.statement();
+                if (stmt instanceof SchemaTreeEffectiveStatement && qname.equals(stmt.argument())) {
+                    return gen;
+                }
+            }
+        }
+        return null;
+    }
+}
index 6a8b7e3029fa042d4b7bba72c7163e2dbbd2db61..8e905ea9382fe1561922a106d589be31ee7ad43e 100644 (file)
@@ -52,8 +52,14 @@ final class ContainerGenerator extends CompositeSchemaTreeGenerator<ContainerEff
     }
 
     @Override
-    ContainerRuntimeType createRuntimeType(final GeneratedType type, final ContainerEffectiveStatement statement,
-            final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
-        return new DefaultContainerRuntimeType(type, statement, children, augments);
+    CompositeRuntimeTypeBuilder<ContainerEffectiveStatement, ContainerRuntimeType> createBuilder(
+            final ContainerEffectiveStatement statement) {
+        return new CompositeRuntimeTypeBuilder<>(statement) {
+            @Override
+            ContainerRuntimeType build(final GeneratedType type, final ContainerEffectiveStatement statement,
+                    final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
+                return new DefaultContainerRuntimeType(type, statement, children, augments);
+            }
+        };
     }
 }
index d789413cacfd0afda7f2b730c7e47f5619be27ee..74ca6074c03b72a935c311b20e84a3ef5d67883d 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.mdsal.binding.generator.impl.reactor;
 
+import static com.google.common.base.Verify.verify;
+
 import java.util.List;
 import org.opendaylight.mdsal.binding.generator.impl.rt.DefaultGroupingRuntimeType;
 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
@@ -55,13 +57,22 @@ final class GroupingGenerator extends AbstractCompositeGenerator<GroupingEffecti
     }
 
     @Override
-    GroupingRuntimeType createRuntimeType(final GeneratedType type, final GroupingEffectiveStatement statement,
-            final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
-        return new DefaultGroupingRuntimeType(type, statement, children, augments);
+    void addAsGetterMethod(final GeneratedTypeBuilderBase<?> builder, final TypeBuilderFactory builderFactory) {
+        // groupings are a separate concept
     }
 
     @Override
-    void addAsGetterMethod(final GeneratedTypeBuilderBase<?> builder, final TypeBuilderFactory builderFactory) {
-        // groupings are a separate concept
+    CompositeRuntimeTypeBuilder<GroupingEffectiveStatement, GroupingRuntimeType> createBuilder(
+            final GroupingEffectiveStatement statement) {
+        return new CompositeRuntimeTypeBuilder<>(statement) {
+            @Override
+            GroupingRuntimeType build(final GeneratedType type, final GroupingEffectiveStatement statement,
+                    final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
+                // Groupings cannot be targeted by 'augment'
+                verify(augments.isEmpty(), "Unexpected augments %s", augments);
+                return new DefaultGroupingRuntimeType(type, statement, children);
+            }
+        };
     }
+
 }
index e5fc913e726ecafd17000914ead935643879a740..ccd88efc57a6b49cc249e194e50f0fc76e315edf 100644 (file)
@@ -7,12 +7,14 @@
  */
 package org.opendaylight.mdsal.binding.generator.impl.reactor;
 
+import static com.google.common.base.Verify.verify;
 import static org.opendaylight.mdsal.binding.model.ri.BindingTypes.BASE_IDENTITY;
 
 import java.util.List;
 import java.util.stream.Collectors;
 import org.opendaylight.mdsal.binding.generator.impl.rt.DefaultIdentityRuntimeType;
 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
+import org.opendaylight.mdsal.binding.model.api.Type;
 import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilder;
 import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilderBase;
 import org.opendaylight.mdsal.binding.runtime.api.IdentityRuntimeType;
@@ -71,13 +73,21 @@ public final class IdentityGenerator
     }
 
     @Override
-    IdentityRuntimeType createRuntimeType() {
-        return generatedType().map(type -> new DefaultIdentityRuntimeType(type, statement())).orElse(null);
+    GeneratedType runtimeJavaType() {
+        return generatedType().orElse(null);
     }
 
     @Override
-    IdentityRuntimeType rebaseRuntimeType(final IdentityRuntimeType type, final IdentityEffectiveStatement statement) {
-        return new DefaultIdentityRuntimeType(type.javaType(), statement);
+    IdentityRuntimeType createExternalRuntimeType(final Type type) {
+        verify(type instanceof GeneratedType, "Unexpected type %s", type);
+        return new DefaultIdentityRuntimeType((GeneratedType) type, statement());
+    }
+
+    @Override
+    IdentityRuntimeType createInternalRuntimeType(final ChildLookup lookup, final IdentityEffectiveStatement statement,
+            final Type type) {
+        // 'identity' statements are not part of schema tree and hence should never an internal reference
+        throw new UnsupportedOperationException("Should never be called");
     }
 
     @Override
index 2400b4a9ee51eeaccae6e70c118c2bd4e42bd6ce..08e4da9b3ad8b6cbeeeb63c6cbe7f90ecafa2beb 100644 (file)
@@ -25,8 +25,14 @@ class InputGenerator extends OperationContainerGenerator<InputEffectiveStatement
     }
 
     @Override
-    final InputRuntimeType createRuntimeType(final GeneratedType type, final InputEffectiveStatement statement,
-            final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
-        return new DefaultInputRuntimeType(type, statement, children, augments);
+    final CompositeRuntimeTypeBuilder<InputEffectiveStatement, InputRuntimeType> createBuilder(
+            final InputEffectiveStatement statement) {
+        return new CompositeRuntimeTypeBuilder<>(statement) {
+            @Override
+            InputRuntimeType build(final GeneratedType type, final InputEffectiveStatement statement,
+                    final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
+                return new DefaultInputRuntimeType(type, statement, children, augments);
+            }
+        };
     }
 }
index 4a28b410f16cc7aef0cf9253e8e105b6364fa233..a45c1dcb35c8d74f920b9135e2af0271a4c02363 100644 (file)
@@ -14,6 +14,7 @@ import java.util.Set;
 import org.opendaylight.mdsal.binding.generator.impl.reactor.CollisionDomain.Member;
 import org.opendaylight.mdsal.binding.generator.impl.rt.DefaultKeyRuntimeType;
 import org.opendaylight.mdsal.binding.model.api.GeneratedTransferObject;
+import org.opendaylight.mdsal.binding.model.api.GeneratedType;
 import org.opendaylight.mdsal.binding.model.api.Type;
 import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedPropertyBuilder;
 import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTOBuilder;
@@ -77,16 +78,21 @@ final class KeyGenerator extends AbstractExplicitGenerator<KeyEffectiveStatement
     }
 
     @Override
-    KeyRuntimeType createRuntimeType() {
-        return generatedType().map(type -> {
-            verify(type instanceof GeneratedTransferObject, "Unexpected type %s", type);
-            return new DefaultKeyRuntimeType((GeneratedTransferObject) type, statement());
-        }).orElse(null);
+    GeneratedType runtimeJavaType() {
+        return generatedType().orElse(null);
     }
 
     @Override
-    KeyRuntimeType rebaseRuntimeType(final KeyRuntimeType type, final KeyEffectiveStatement statement) {
-        return new DefaultKeyRuntimeType(type.javaType(), statement);
+    KeyRuntimeType createExternalRuntimeType(final Type type) {
+        verify(type instanceof GeneratedTransferObject, "Unexpected type %s", type);
+        return new DefaultKeyRuntimeType((GeneratedTransferObject) type, statement());
+    }
+
+    @Override
+    KeyRuntimeType createInternalRuntimeType(final ChildLookup lookup,final KeyEffectiveStatement statement,
+            final Type type) {
+        // The only reference to this runtime type is from ListGenerator which is always referencing the external type
+        throw new UnsupportedOperationException("Should never be called");
     }
 
     @Override
index 53aadbed255ccee4ce785dfc592f167bda414fbb..233b785917f4b725c52fb64acbc78f526555efc4 100644 (file)
@@ -21,12 +21,13 @@ final class LeafGenerator extends AbstractTypeAwareGenerator<LeafEffectiveStatem
     }
 
     @Override
-    LeafRuntimeType createRuntimeType(final Type type) {
+    LeafRuntimeType createExternalRuntimeType(final Type type) {
         return new DefaultLeafRuntimeType(type, statement());
     }
 
     @Override
-    LeafRuntimeType rebaseRuntimeType(final LeafRuntimeType type, final LeafEffectiveStatement statement) {
-        return new DefaultLeafRuntimeType(type.javaType(), statement);
+    LeafRuntimeType createInternalRuntimeType(final ChildLookup lookup, final LeafEffectiveStatement statement,
+            final Type type) {
+        return new DefaultLeafRuntimeType(type, statement);
     }
 }
index ee9cef9df6e92cbd9fa28b293789ff70de157cf1..aa6263a192696b724237e364020118151b64c883 100644 (file)
@@ -37,12 +37,13 @@ final class LeafListGenerator
     }
 
     @Override
-    LeafListRuntimeType createRuntimeType(final Type type) {
+    LeafListRuntimeType createExternalRuntimeType(final Type type) {
         return new DefaultLeafListRuntimeType(type, statement());
     }
 
     @Override
-    LeafListRuntimeType rebaseRuntimeType(final LeafListRuntimeType type, final LeafListEffectiveStatement statement) {
-        return new DefaultLeafListRuntimeType(type.javaType(), statement);
+    LeafListRuntimeType createInternalRuntimeType(final ChildLookup lookup, final LeafListEffectiveStatement statement,
+            final Type type) {
+        return new DefaultLeafListRuntimeType(type, statement);
     }
 }
index 9bc44ba413f641c280165fcfa3f2a9aa49595bbc..07b2c5382fa63725ad7e37894a806000bcf30c32 100644 (file)
@@ -20,6 +20,7 @@ import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilde
 import org.opendaylight.mdsal.binding.model.api.type.builder.MethodSignatureBuilder;
 import org.opendaylight.mdsal.binding.model.ri.Types;
 import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
+import org.opendaylight.mdsal.binding.runtime.api.KeyRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.ListRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
 import org.opendaylight.mdsal.binding.spec.naming.BindingMapping;
@@ -80,11 +81,9 @@ final class ListGenerator extends CompositeSchemaTreeGenerator<ListEffectiveStat
         return builder.build();
     }
 
-    @Override
-    ListRuntimeType createRuntimeType(final GeneratedType type, final ListEffectiveStatement statement,
-            final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
-        return new DefaultListRuntimeType(type, statement, children, augments,
-            keyGen != null ? keyGen.runtimeType().orElseThrow() : null);
+    private @Nullable KeyRuntimeType keyRuntimeType() {
+        final var gen = keyGen;
+        return gen != null ? gen.runtimeType().orElseThrow() : null;
     }
 
     @Override
@@ -111,4 +110,17 @@ final class ListGenerator extends CompositeSchemaTreeGenerator<ListEffectiveStat
 
         return ret;
     }
+
+    @Override
+    CompositeRuntimeTypeBuilder<ListEffectiveStatement, ListRuntimeType> createBuilder(
+            final ListEffectiveStatement statement) {
+        return new CompositeRuntimeTypeBuilder<>(statement) {
+            @Override
+            ListRuntimeType build(final GeneratedType type, final ListEffectiveStatement statement,
+                    final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
+                // FIXME: the key here is not rebased correctly :(
+                return new DefaultListRuntimeType(type, statement, children, augments, keyRuntimeType());
+            }
+        };
+    }
 }
index 4607f9b437b41e3cdd9819faa75b102f79625b47..edb1aee7dde9b5a2aab2e0c68ee9c84302dbcade 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.mdsal.binding.generator.impl.reactor;
 
+import static com.google.common.base.Verify.verify;
 import static com.google.common.base.Verify.verifyNotNull;
 
 import java.util.List;
@@ -99,12 +100,6 @@ public final class ModuleGenerator extends AbstractCompositeGenerator<ModuleEffe
         return builder.build();
     }
 
-    @Override
-    ModuleRuntimeType createRuntimeType(final GeneratedType type, final ModuleEffectiveStatement statement,
-            final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
-        return new DefaultModuleRuntimeType(type, statement, children, augments);
-    }
-
     @NonNull Member getPrefixMember() {
         return verifyNotNull(prefixMember);
     }
@@ -113,4 +108,17 @@ public final class ModuleGenerator extends AbstractCompositeGenerator<ModuleEffe
         builder.addConstant(BindingTypes.QNAME, BindingMapping.QNAME_STATIC_FIELD_NAME,
             Map.entry(yangModuleInfo, localName.getLocalName()));
     }
+
+    @Override
+    CompositeRuntimeTypeBuilder<ModuleEffectiveStatement, ModuleRuntimeType> createBuilder(
+            final ModuleEffectiveStatement statement) {
+        return new CompositeRuntimeTypeBuilder<>(statement) {
+            @Override
+            ModuleRuntimeType build(final GeneratedType type, final ModuleEffectiveStatement statement,
+                    final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
+                verify(augments.isEmpty(), "Unexpected augments %s", augments);
+                return new DefaultModuleRuntimeType(type, statement, children);
+            }
+        };
+    }
 }
index c2d4a3827564d33e8e7a0b53dab15d853e536af2..cc49b1d45516d4331fed3f62f1b096e09a132048 100644 (file)
@@ -58,14 +58,20 @@ final class NotificationGenerator
     }
 
     @Override
-    NotificationRuntimeType createRuntimeType(final GeneratedType type, final NotificationEffectiveStatement statement,
-            final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
-        return new DefaultNotificationRuntimeType(type, statement, children, augments);
+    void addAsGetterMethod(final GeneratedTypeBuilderBase<?> builder, final TypeBuilderFactory builderFactory) {
+        // Notifications are a distinct concept
     }
 
     @Override
-    void addAsGetterMethod(final GeneratedTypeBuilderBase<?> builder, final TypeBuilderFactory builderFactory) {
-        // Notifications are a distinct concept
+    CompositeRuntimeTypeBuilder<NotificationEffectiveStatement, NotificationRuntimeType> createBuilder(
+            final NotificationEffectiveStatement statement) {
+        return new CompositeRuntimeTypeBuilder<>(statement) {
+            @Override
+            NotificationRuntimeType build(final GeneratedType type, final NotificationEffectiveStatement statement,
+                    final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
+                return new DefaultNotificationRuntimeType(type, statement, children, augments);
+            }
+        };
     }
 
     private Type notificationType(final GeneratedTypeBuilder builder, final TypeBuilderFactory builderFactory) {
index 63564ce2f621105e56dede5f9434625890fd83c1..2e7da2abbb7cb98a78ec4d4ff54ff7b5e1636dc8 100644 (file)
@@ -7,6 +7,9 @@
  */
 package org.opendaylight.mdsal.binding.generator.impl.reactor;
 
+import static com.google.common.base.Verify.verify;
+
+import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.mdsal.binding.generator.impl.rt.DefaultAnydataRuntimeType;
 import org.opendaylight.mdsal.binding.generator.impl.rt.DefaultAnyxmlRuntimeType;
 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
@@ -33,13 +36,14 @@ abstract class OpaqueObjectGenerator<S extends DataTreeEffectiveStatement<?>, R
         }
 
         @Override
-        AnydataRuntimeType createRuntimeType() {
-            return generatedType().map(type -> new DefaultAnydataRuntimeType(type, statement())).orElse(null);
+        AnydataRuntimeType createExternalRuntimeType(final GeneratedType type) {
+            return new DefaultAnydataRuntimeType(type, statement());
         }
 
         @Override
-        AnydataRuntimeType rebaseRuntimeType(final AnydataRuntimeType type, final AnydataEffectiveStatement statement) {
-            return new DefaultAnydataRuntimeType(type.javaType(), statement);
+        AnydataRuntimeType createInternalRuntimeType(final AnydataEffectiveStatement statement,
+                final GeneratedType type) {
+            return new DefaultAnydataRuntimeType(type, statement);
         }
     }
 
@@ -49,13 +53,14 @@ abstract class OpaqueObjectGenerator<S extends DataTreeEffectiveStatement<?>, R
         }
 
         @Override
-        AnyxmlRuntimeType createRuntimeType() {
-            return generatedType().map(type -> new DefaultAnyxmlRuntimeType(type, statement())).orElse(null);
+        AnyxmlRuntimeType createExternalRuntimeType(final GeneratedType type) {
+            return new DefaultAnyxmlRuntimeType(type, statement());
         }
 
         @Override
-        AnyxmlRuntimeType rebaseRuntimeType(final AnyxmlRuntimeType type, final AnyxmlEffectiveStatement statement) {
-            return new DefaultAnyxmlRuntimeType(type.javaType(), statement);
+        AnyxmlRuntimeType createInternalRuntimeType(final AnyxmlEffectiveStatement statement,
+                final GeneratedType type) {
+            return new DefaultAnyxmlRuntimeType(type, statement);
         }
     }
 
@@ -90,4 +95,25 @@ abstract class OpaqueObjectGenerator<S extends DataTreeEffectiveStatement<?>, R
     void constructRequire(final GeneratedTypeBuilderBase<?> builder, final Type returnType) {
         constructRequireImpl(builder, returnType);
     }
+
+    @Override
+    final GeneratedType runtimeJavaType() {
+        return generatedType().orElse(null);
+    }
+
+    @Override
+    final @NonNull R createExternalRuntimeType(final Type type) {
+        verify(type instanceof GeneratedType, "Unexpected type %s", type);
+        return createExternalRuntimeType((GeneratedType) type);
+    }
+
+    abstract @NonNull R createExternalRuntimeType(@NonNull GeneratedType type);
+
+    @Override
+    final R createInternalRuntimeType(final ChildLookup lookup, final S statement, final Type type) {
+        verify(type instanceof GeneratedType, "Unexpected type %s", type);
+        return createInternalRuntimeType(statement, (GeneratedType) type);
+    }
+
+    abstract @NonNull R createInternalRuntimeType(@NonNull S statement, @NonNull GeneratedType type);
 }
index 320593d7e6d61e8ce29431969c4d38107c0ac25e..83c48d26348fe1c9d184b2f8cf4fb6609a1eddc6 100644 (file)
@@ -25,8 +25,14 @@ class OutputGenerator extends OperationContainerGenerator<OutputEffectiveStateme
     }
 
     @Override
-    final OutputRuntimeType createRuntimeType(final GeneratedType type, final OutputEffectiveStatement statement,
-            final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
-        return new DefaultOutputRuntimeType(type, statement, children, augments);
+    final CompositeRuntimeTypeBuilder<OutputEffectiveStatement, OutputRuntimeType> createBuilder(
+            final OutputEffectiveStatement statement) {
+        return new CompositeRuntimeTypeBuilder<>(statement) {
+            @Override
+            OutputRuntimeType build(final GeneratedType type, final OutputEffectiveStatement statement,
+                    final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
+                return new DefaultOutputRuntimeType(type, statement, children, augments);
+            }
+        };
     }
 }
index 985ac81dd3f581a828171aee1e06cb7753c81a9d..e0ae6b4151ad12c8985f6256539a8c464a798930 100644 (file)
@@ -7,12 +7,9 @@
  */
 package org.opendaylight.mdsal.binding.generator.impl.reactor;
 
-import java.util.List;
 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
 import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilderBase;
-import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.RpcRuntimeType;
-import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
 import org.opendaylight.yangtools.yang.model.api.stmt.RpcEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
 
@@ -42,13 +39,14 @@ public final class RpcGenerator extends CompositeSchemaTreeGenerator<RpcEffectiv
     }
 
     @Override
-    RpcRuntimeType createRuntimeType(final GeneratedType type, final RpcEffectiveStatement statement,
-            final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
-        throw new UnsupportedOperationException();
+    void addAsGetterMethod(final GeneratedTypeBuilderBase<?> builder, final TypeBuilderFactory builderFactory) {
+        // RPCs are a separate concept
     }
 
     @Override
-    void addAsGetterMethod(final GeneratedTypeBuilderBase<?> builder, final TypeBuilderFactory builderFactory) {
-        // RPCs are a separate concept
+    CompositeRuntimeTypeBuilder<RpcEffectiveStatement, RpcRuntimeType> createBuilder(
+            final RpcEffectiveStatement statement) {
+        // RPCs do not have a dedicated interface
+        throw new UnsupportedOperationException("Should never be called");
     }
 }
index 65544db7f25e464ff7d6c0bf8fcd1ed6d17e529c..0a800380221a844b22e08ca457254707e1942378 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.mdsal.binding.generator.impl.reactor;
 import static com.google.common.base.Verify.verify;
 import static java.util.Objects.requireNonNull;
 
+import com.google.common.base.MoreObjects;
 import com.google.common.collect.Collections2;
 import com.google.common.collect.ImmutableList;
 import java.util.Collection;
@@ -33,7 +34,6 @@ import org.opendaylight.yangtools.yang.model.api.stmt.AugmentEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.AugmentStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeAwareEffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
 import org.opendaylight.yangtools.yang.xpath.api.YangXPathExpression.QualifiedBound;
 
 final class TargetAugmentEffectiveStatement implements AugmentEffectiveStatement, AugmentationSchemaNode {
@@ -42,23 +42,12 @@ final class TargetAugmentEffectiveStatement implements AugmentEffectiveStatement
     private final @NonNull AugmentationSchemaNode schemaDelegate;
 
     TargetAugmentEffectiveStatement(final AugmentEffectiveStatement augment,
-            final SchemaTreeAwareEffectiveStatement<?, ?> target) {
+            final SchemaTreeAwareEffectiveStatement<?, ?> target,
+            final ImmutableList<EffectiveStatement<?, ?>> substatements) {
         delegate = requireNonNull(augment);
         verify(augment instanceof AugmentationSchemaNode, "Unsupported augment implementation %s", augment);
         schemaDelegate = (AugmentationSchemaNode) augment;
-
-        final var stmts = augment.effectiveSubstatements();
-        final var builder = ImmutableList.<EffectiveStatement<?, ?>>builderWithExpectedSize(stmts.size());
-        for (var stmt : stmts) {
-            if (stmt instanceof SchemaTreeEffectiveStatement) {
-                final var qname = ((SchemaTreeEffectiveStatement<?>) stmt).getIdentifier();
-                target.get(SchemaTreeNamespace.class, qname).ifPresent(builder::add);
-            } else {
-                builder.add(stmt);
-            }
-        }
-
-        substatements = builder.build();
+        this.substatements = requireNonNull(substatements);
     }
 
     @NonNull AugmentEffectiveStatement delegate() {
@@ -157,4 +146,12 @@ final class TargetAugmentEffectiveStatement implements AugmentEffectiveStatement
     public AugmentEffectiveStatement asEffectiveStatement() {
         return this;
     }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+            .add("delegate", delegate)
+            .add("substatements", substatements.size())
+            .toString();
+    }
 }
index 3267b83aa530c022fa0b9d46dde9c0f9f82792f1..e3cfd4d5949e3399ba2d3966a8361e1c185447bb 100644 (file)
@@ -95,14 +95,16 @@ final class TypedefGenerator extends AbstractTypeObjectGenerator<TypedefEffectiv
     }
 
     @Override
-    TypedefRuntimeType createRuntimeType(final Type type) {
+    TypedefRuntimeType createExternalRuntimeType(final Type type) {
         verify(type instanceof GeneratedType, "Unexpected type %s", type);
         return new DefaultTypedefRuntimeType((GeneratedType) type, statement());
     }
 
     @Override
-    TypedefRuntimeType rebaseRuntimeType(final TypedefRuntimeType type, final TypedefEffectiveStatement statement) {
-        return new DefaultTypedefRuntimeType(type.javaType(), statement);
+    TypedefRuntimeType createInternalRuntimeType(final ChildLookup lookup, final TypedefEffectiveStatement statement,
+            final Type type) {
+        // 'typedef' statements are not schema tree statements, they should not have internal references
+        throw new UnsupportedOperationException("Should never be called");
     }
 
     @Override
index e933dbaaed7a20b35acaa0524700e18ff9f09841..06c841d430043cc75bb140b449ca06eeb101dd86 100644 (file)
@@ -11,8 +11,16 @@ import static com.google.common.base.Verify.verify;
 import static com.google.common.base.Verify.verifyNotNull;
 import static java.util.Objects.requireNonNull;
 
+import com.google.common.collect.ImmutableList;
+import java.util.List;
 import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
+import org.opendaylight.mdsal.binding.runtime.api.CaseRuntimeType;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.AugmentEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ChoiceEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeAwareEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeAwareEffectiveStatement.SchemaTreeNamespace;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.UsesEffectiveStatement;
 
@@ -58,4 +66,58 @@ final class UsesAugmentGenerator extends AbstractAugmentGenerator {
         // Our parent here is *not* the 'uses' statement, but rather the statement which contains it.
         return new AugmentRequirement(this, verifyNotNull(grouping, "Unresolved grouping in %s", this));
     }
+
+    @Override
+    List<CaseRuntimeType> augmentedCasesIn(final ChildLookup lookup, final ChoiceEffectiveStatement stmt) {
+        final var result = super.augmentedCasesIn(lookup, stmt);
+        if (result != null) {
+            return result;
+        }
+        final var augment = statement();
+        if (!lookup.contains(augment)) {
+            return List.of();
+        }
+
+        final var effectiveStatement = effectiveStatement(augment, stmt);
+        return createBuilder(effectiveStatement)
+            .fillTypes(lookup.inStatement(effectiveStatement), this)
+            .getCaseChilden();
+    }
+
+    @Override
+    AugmentRuntimeType runtimeTypeIn(final ChildLookup lookup, final EffectiveStatement<?, ?> target) {
+        final var result = super.runtimeTypeIn(lookup, target);
+        if (result != null) {
+            return result;
+        }
+        final var augment = statement();
+        if (!lookup.contains(augment)) {
+            return null;
+        }
+
+        verify(target instanceof SchemaTreeAwareEffectiveStatement && target instanceof SchemaTreeEffectiveStatement,
+            "Unexpected statement %s", target);
+        final var effectiveStatement = effectiveStatement(augment, (SchemaTreeAwareEffectiveStatement<?, ?>) target);
+        return verifyNotNull(createInternalRuntimeType(lookup.inStatement(effectiveStatement), effectiveStatement));
+    }
+
+    private static @NonNull AugmentEffectiveStatement effectiveStatement(final AugmentEffectiveStatement augment,
+            final SchemaTreeAwareEffectiveStatement<?, ?> target) {
+        verify(target instanceof SchemaTreeEffectiveStatement, "Unexpected statement %s", target);
+        // 'uses'/'augment': our children are binding to target's namespace
+        final var targetNamespace = ((SchemaTreeEffectiveStatement<?>) target).argument().getModule();
+
+        final var stmts = augment.effectiveSubstatements();
+        final var builder = ImmutableList.<EffectiveStatement<?, ?>>builderWithExpectedSize(stmts.size());
+        for (var stmt : stmts) {
+            if (stmt instanceof SchemaTreeEffectiveStatement) {
+                final var qname = ((SchemaTreeEffectiveStatement<?>) stmt).getIdentifier().bindTo(targetNamespace);
+                target.get(SchemaTreeNamespace.class, qname).ifPresent(builder::add);
+            } else {
+                builder.add(stmt);
+            }
+        }
+
+        return new TargetAugmentEffectiveStatement(augment, target, builder.build());
+    }
 }
diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/AbstractAugmentableRuntimeType.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/AbstractAugmentableRuntimeType.java
new file mode 100644 (file)
index 0000000..a3dd7f2
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2022 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.mdsal.binding.generator.impl.rt;
+
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.mdsal.binding.model.api.GeneratedType;
+import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
+import org.opendaylight.mdsal.binding.runtime.api.AugmentableRuntimeType;
+import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+
+/**
+ * Abstract base class for {@link AbstractCompositeRuntimeType}s which support augmentations.
+ */
+abstract class AbstractAugmentableRuntimeType<S extends EffectiveStatement<?, ?>>
+        extends AbstractCompositeRuntimeType<S> implements AugmentableRuntimeType {
+    private final @NonNull ImmutableList<AugmentRuntimeType> augments;
+
+    AbstractAugmentableRuntimeType(final GeneratedType bindingType, final S statement, final List<RuntimeType> children,
+            final List<AugmentRuntimeType> augments) {
+        super(bindingType, statement, children);
+        this.augments = ImmutableList.copyOf(augments);
+    }
+
+    @Override
+    public final List<AugmentRuntimeType> augments() {
+        return augments;
+    }
+}
index d67f1cf94c7ed0f57eb17f9c2af684dbc7f1dfe1..85ecec6148b4279d5a04ee97cda338b8ae2ca89b 100644 (file)
@@ -11,13 +11,11 @@ import static java.util.Objects.requireNonNull;
 
 import com.google.common.base.Functions;
 import com.google.common.collect.ImmutableCollection;
-import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import java.util.List;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
 import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
-import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.GeneratedRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
@@ -29,26 +27,10 @@ abstract class AbstractCompositeRuntimeType<S extends EffectiveStatement<?, ?>>
         extends AbstractRuntimeType<S, GeneratedType> implements CompositeRuntimeType {
     private final ImmutableMap<JavaTypeName, GeneratedRuntimeType> byClass;
     private final ImmutableMap<QName, RuntimeType> bySchemaTree;
-    private final @NonNull ImmutableList<AugmentRuntimeType> augments;
-    private final @NonNull ImmutableList<AugmentRuntimeType> mismatchedAugments;
 
-    AbstractCompositeRuntimeType(final GeneratedType bindingType, final S statement, final List<RuntimeType> children,
-            final List<AugmentRuntimeType> augments) {
+    AbstractCompositeRuntimeType(final GeneratedType bindingType, final S statement, final List<RuntimeType> children) {
         super(bindingType, statement);
 
-        final var substatements = statement.effectiveSubstatements();
-        final var correctBuilder = ImmutableList.<AugmentRuntimeType>builder();
-        final var mismatchedBuilder = ImmutableList.<AugmentRuntimeType>builder();
-        for (var aug : augments) {
-            if (substatements.contains(aug.statement())) {
-                correctBuilder.add(aug);
-            } else {
-                mismatchedBuilder.add(aug);
-            }
-        }
-        this.augments = correctBuilder.build();
-        this.mismatchedAugments = mismatchedBuilder.build();
-
         byClass = children.stream()
             .filter(GeneratedRuntimeType.class::isInstance)
             .map(GeneratedRuntimeType.class::cast)
@@ -65,16 +47,6 @@ abstract class AbstractCompositeRuntimeType<S extends EffectiveStatement<?, ?>>
         bySchemaTree = builder.build();
     }
 
-    @Override
-    public final List<AugmentRuntimeType> augments() {
-        return augments;
-    }
-
-    @Override
-    public final List<AugmentRuntimeType> mismatchedAugments() {
-        return mismatchedAugments;
-    }
-
     @Override
     public final RuntimeType schemaTreeChild(final QName qname) {
         return bySchemaTree.get(requireNonNull(qname));
index c2cb51fec642702bf1f5d98257dc5ade24c661d6..6bb4d1287f2c0b643ddd80ce78050be97ee8b1b6 100644 (file)
@@ -36,6 +36,9 @@ abstract class AbstractRuntimeType<S extends EffectiveStatement<?, ?>, T extends
 
     @Override
     public final String toString() {
-        return MoreObjects.toStringHelper(this).add("javaType", javaType).add("statement", statement).toString();
+        return MoreObjects.toStringHelper(this)
+            .add("javaType", javaType.getIdentifier())
+            .add("statement", statement)
+            .toString();
     }
 }
index 84af4cc2f841084bdaa9652e79614a2325819bd2..32aff37f7e8062b2bec1e8f935e27750ba8a0037 100644 (file)
@@ -12,7 +12,6 @@ import java.util.List;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
 import org.opendaylight.mdsal.binding.runtime.api.ActionRuntimeType;
-import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.InputRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.OutputRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
@@ -25,8 +24,8 @@ public final class DefaultActionRuntimeType extends AbstractCompositeRuntimeType
     private final @NonNull OutputRuntimeType output;
 
     public DefaultActionRuntimeType(final GeneratedType bindingType, final ActionEffectiveStatement statement,
-            final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
-        super(bindingType, statement, children, augments);
+            final List<RuntimeType> children) {
+        super(bindingType, statement, children);
         input = child(children, InputRuntimeType.class);
         output = child(children, OutputRuntimeType.class);
     }
index 3a0de76f95c2f929038fa133f98d7a2e1db7caa7..3ee15b72795c278d74d918145e83f86cabd55985 100644 (file)
@@ -18,7 +18,7 @@ import org.opendaylight.yangtools.yang.model.api.stmt.AugmentEffectiveStatement;
 public final class DefaultAugmentRuntimeType extends AbstractCompositeRuntimeType<AugmentEffectiveStatement>
         implements AugmentRuntimeType {
     public DefaultAugmentRuntimeType(final GeneratedType bindingType, final AugmentEffectiveStatement statement,
-            final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
-        super(bindingType, statement, children, augments);
+            final List<RuntimeType> children) {
+        super(bindingType, statement, children);
     }
 }
index 9bd748f7ddb1933c88cc94e9e75e51a2cef149e4..9222de82662bb49b7876b2ed0c98a510ff7da4f1 100644 (file)
@@ -11,13 +11,18 @@ import static java.util.Objects.requireNonNull;
 
 import com.google.common.base.MoreObjects;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSetMultimap;
 import com.google.common.collect.ImmutableSortedMap;
 import com.google.common.collect.Maps;
+import com.google.common.collect.SetMultimap;
 import java.util.Map;
 import java.util.Optional;
+import java.util.Set;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
 import org.opendaylight.mdsal.binding.runtime.api.BindingRuntimeTypes;
+import org.opendaylight.mdsal.binding.runtime.api.CaseRuntimeType;
+import org.opendaylight.mdsal.binding.runtime.api.ChoiceRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.GeneratedRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.IdentityRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.InputRuntimeType;
@@ -33,6 +38,7 @@ import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
  */
 public final class DefaultBindingRuntimeTypes implements BindingRuntimeTypes {
     private final @NonNull EffectiveModelContext context;
+    private final ImmutableSetMultimap<JavaTypeName, CaseRuntimeType> choiceToCases;
     private final ImmutableMap<QNameModule, ModuleRuntimeType> modulesByNamespace;
     private final ImmutableSortedMap<String, ModuleRuntimeType> modulesByPackage;
     private final ImmutableMap<QName, IdentityRuntimeType> identities;
@@ -43,12 +49,14 @@ public final class DefaultBindingRuntimeTypes implements BindingRuntimeTypes {
     public DefaultBindingRuntimeTypes(final EffectiveModelContext context,
             final Map<QNameModule, ModuleRuntimeType> modules, final Map<JavaTypeName, RuntimeType> types,
             final Map<QName, IdentityRuntimeType> identities, final Map<QName, InputRuntimeType> rpcInputs,
-            final Map<QName, OutputRuntimeType> rpcOutputs) {
+            final Map<QName, OutputRuntimeType> rpcOutputs,
+            final SetMultimap<JavaTypeName, CaseRuntimeType> choiceToCases) {
         this.context = requireNonNull(context);
         this.identities = ImmutableMap.copyOf(identities);
         this.types = ImmutableMap.copyOf(types);
         this.rpcInputs = ImmutableMap.copyOf(rpcInputs);
         this.rpcOutputs = ImmutableMap.copyOf(rpcOutputs);
+        this.choiceToCases = ImmutableSetMultimap.copyOf(choiceToCases);
 
         modulesByNamespace = ImmutableMap.copyOf(modules);
         modulesByPackage = ImmutableSortedMap.copyOf(Maps.uniqueIndex(modules.values(),
@@ -93,6 +101,11 @@ public final class DefaultBindingRuntimeTypes implements BindingRuntimeTypes {
         return Optional.ofNullable(rpcOutputs.get(requireNonNull(rpcName)));
     }
 
+    @Override
+    public Set<CaseRuntimeType> allCaseChildren(final ChoiceRuntimeType choiceType) {
+        return choiceToCases.get(choiceType.getIdentifier());
+    }
+
     @Override
     public String toString() {
         return MoreObjects.toStringHelper(this)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.mdsal.binding.generator.impl.rt;
 
+import com.google.common.annotations.Beta;
 import java.util.List;
 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
 import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
@@ -14,9 +15,10 @@ import org.opendaylight.mdsal.binding.runtime.api.CaseRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
 import org.opendaylight.yangtools.yang.model.api.stmt.CaseEffectiveStatement;
 
-abstract class AbstractCaseRuntimeType extends AbstractCompositeRuntimeType<CaseEffectiveStatement>
+@Beta
+public final class DefaultCaseRuntimeType extends AbstractAugmentableRuntimeType<CaseEffectiveStatement>
         implements CaseRuntimeType {
-    AbstractCaseRuntimeType(final GeneratedType bindingType, final CaseEffectiveStatement statement,
+    public DefaultCaseRuntimeType(final GeneratedType bindingType, final CaseEffectiveStatement statement,
             final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
         super(bindingType, statement, children, augments);
     }
@@ -7,31 +7,32 @@
  */
 package org.opendaylight.mdsal.binding.generator.impl.rt;
 
+import com.google.common.annotations.Beta;
 import com.google.common.collect.Collections2;
 import java.util.Collection;
 import java.util.List;
 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
 import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
-import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.CaseRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.ChoiceRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
 import org.opendaylight.yangtools.yang.model.api.stmt.ChoiceEffectiveStatement;
 
-abstract class AbstractChoiceRuntimeType extends AbstractCompositeRuntimeType<ChoiceEffectiveStatement>
+@Beta
+public final class DefaultChoiceRuntimeType extends AbstractCompositeRuntimeType<ChoiceEffectiveStatement>
         implements ChoiceRuntimeType {
-    AbstractChoiceRuntimeType(final GeneratedType bindingType, final ChoiceEffectiveStatement statement,
-            final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
-        super(bindingType, statement, children, augments);
+    public DefaultChoiceRuntimeType(final GeneratedType bindingType, final ChoiceEffectiveStatement statement,
+            final List<RuntimeType> children) {
+        super(bindingType, statement, children);
     }
 
     @Override
-    public final Collection<CaseRuntimeType> validCaseChildren() {
+    public Collection<CaseRuntimeType> validCaseChildren() {
         return (Collection) Collections2.filter(schemaTreeChildren(), CaseRuntimeType.class::isInstance);
     }
 
     @Override
-    public final CaseRuntimeType bindingCaseChild(final JavaTypeName typeName) {
+    public CaseRuntimeType bindingCaseChild(final JavaTypeName typeName) {
         final var child = bindingChild(typeName);
         return child instanceof CaseRuntimeType ? (CaseRuntimeType) child : null;
     }
index 3a9584793ad6233e63802ee5135a8aecf83d4232..f9c934feb1e5e0c352a801e172aefcdbb498fe25 100644 (file)
@@ -16,7 +16,7 @@ import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
 import org.opendaylight.yangtools.yang.model.api.stmt.ContainerEffectiveStatement;
 
 @Beta
-public final class DefaultContainerRuntimeType extends AbstractCompositeRuntimeType<ContainerEffectiveStatement>
+public final class DefaultContainerRuntimeType extends AbstractAugmentableRuntimeType<ContainerEffectiveStatement>
         implements ContainerRuntimeType {
     public DefaultContainerRuntimeType(final GeneratedType bindingType, final ContainerEffectiveStatement statement,
             final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
index 42f9efecac2318fd9d5cfeee6095f0bc6d800ca3..64260960e916f52b017a5af88cdafbd1be6b58a5 100644 (file)
@@ -10,7 +10,6 @@ package org.opendaylight.mdsal.binding.generator.impl.rt;
 import com.google.common.annotations.Beta;
 import java.util.List;
 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
-import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.GroupingRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
 import org.opendaylight.yangtools.yang.model.api.stmt.GroupingEffectiveStatement;
@@ -19,7 +18,7 @@ import org.opendaylight.yangtools.yang.model.api.stmt.GroupingEffectiveStatement
 public final class DefaultGroupingRuntimeType extends AbstractCompositeRuntimeType<GroupingEffectiveStatement>
         implements GroupingRuntimeType {
     public DefaultGroupingRuntimeType(final GeneratedType bindingType, final GroupingEffectiveStatement statement,
-            final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
-        super(bindingType, statement, children, augments);
+            final List<RuntimeType> children) {
+        super(bindingType, statement, children);
     }
 }
index 3b6eda8059789586336abf0c78fe761d120a2736..3a06ddc214951199e00c9f5a8dc158d60c8060a9 100644 (file)
@@ -16,7 +16,7 @@ import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
 import org.opendaylight.yangtools.yang.model.api.stmt.InputEffectiveStatement;
 
 @Beta
-public final class DefaultInputRuntimeType extends AbstractCompositeRuntimeType<InputEffectiveStatement>
+public class DefaultInputRuntimeType extends AbstractAugmentableRuntimeType<InputEffectiveStatement>
         implements InputRuntimeType {
     public DefaultInputRuntimeType(final GeneratedType bindingType, final InputEffectiveStatement statement,
             final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
index c6e4bca1883829ab9e306e583d6414467139fef5..c409de02d95bef18f72037aa6164f850bc38c23c 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.mdsal.binding.generator.impl.rt;
 
 import com.google.common.annotations.Beta;
 import java.util.List;
+import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
 import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.KeyRuntimeType;
@@ -17,9 +18,9 @@ import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
 import org.opendaylight.yangtools.yang.model.api.stmt.ListEffectiveStatement;
 
 @Beta
-public final class DefaultListRuntimeType extends AbstractCompositeRuntimeType<ListEffectiveStatement>
+public final class DefaultListRuntimeType extends AbstractAugmentableRuntimeType<ListEffectiveStatement>
         implements ListRuntimeType {
-    private final KeyRuntimeType keyType;
+    private final @Nullable KeyRuntimeType keyType;
 
     public DefaultListRuntimeType(final GeneratedType bindingType, final ListEffectiveStatement statement,
             final List<RuntimeType> children, final List<AugmentRuntimeType> augments, final KeyRuntimeType keyType) {
index 433107a6d8d0679245bb1318eb20fa5dd7159ddc..e849745b9dc1e48777580e6d9435b3337c20f8e6 100644 (file)
@@ -10,7 +10,6 @@ package org.opendaylight.mdsal.binding.generator.impl.rt;
 import com.google.common.annotations.Beta;
 import java.util.List;
 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
-import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.ModuleRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
 import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement;
@@ -19,7 +18,7 @@ import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement;
 public final class DefaultModuleRuntimeType extends AbstractCompositeRuntimeType<ModuleEffectiveStatement>
         implements ModuleRuntimeType {
     public DefaultModuleRuntimeType(final GeneratedType bindingType, final ModuleEffectiveStatement statement,
-            final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
-        super(bindingType, statement, children, augments);
+            final List<RuntimeType> children) {
+        super(bindingType, statement, children);
     }
 }
index ef7866b4e405671b370474e6a437eb7d02259cf1..4f9cf9f732fb05b4984d43b68308b1a58fe2b531 100644 (file)
@@ -16,7 +16,7 @@ import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
 import org.opendaylight.yangtools.yang.model.api.stmt.NotificationEffectiveStatement;
 
 @Beta
-public final class DefaultNotificationRuntimeType extends AbstractCompositeRuntimeType<NotificationEffectiveStatement>
+public final class DefaultNotificationRuntimeType extends AbstractAugmentableRuntimeType<NotificationEffectiveStatement>
         implements NotificationRuntimeType {
     public DefaultNotificationRuntimeType(final GeneratedType bindingType,
             final NotificationEffectiveStatement statement, final List<RuntimeType> children,
index 0e4d150809ede044be45c6d91b99542a5ba27c3d..3c37d0e436e0d6f013ccea86bae443734bdcf845 100644 (file)
@@ -16,7 +16,7 @@ import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
 import org.opendaylight.yangtools.yang.model.api.stmt.OutputEffectiveStatement;
 
 @Beta
-public final class DefaultOutputRuntimeType extends AbstractCompositeRuntimeType<OutputEffectiveStatement>
+public class DefaultOutputRuntimeType extends AbstractAugmentableRuntimeType<OutputEffectiveStatement>
         implements OutputRuntimeType {
     public DefaultOutputRuntimeType(final GeneratedType bindingType, final OutputEffectiveStatement statement,
             final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DerivedCaseRuntimeType.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DerivedCaseRuntimeType.java
deleted file mode 100644 (file)
index 271f98a..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2021 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.mdsal.binding.generator.impl.rt;
-
-import static java.util.Objects.requireNonNull;
-
-import com.google.common.annotations.Beta;
-import java.util.List;
-import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.mdsal.binding.model.api.GeneratedType;
-import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
-import org.opendaylight.mdsal.binding.runtime.api.CaseRuntimeType;
-import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
-import org.opendaylight.yangtools.yang.model.api.stmt.CaseEffectiveStatement;
-
-@Beta
-public final class DerivedCaseRuntimeType extends AbstractCaseRuntimeType {
-    private final @NonNull CaseRuntimeType originalType;
-
-    public DerivedCaseRuntimeType(final GeneratedType bindingType, final CaseEffectiveStatement statement,
-            final List<RuntimeType> children, final List<AugmentRuntimeType> augments,
-            final CaseRuntimeType originalType) {
-        super(bindingType, statement, children, augments);
-        this.originalType = requireNonNull(originalType);
-    }
-
-    @Override
-    public @NonNull CaseRuntimeType originalType() {
-        return originalType;
-    }
-}
diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DerivedChoiceRuntimeType.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DerivedChoiceRuntimeType.java
deleted file mode 100644 (file)
index 3a81294..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2021 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.mdsal.binding.generator.impl.rt;
-
-import static java.util.Objects.requireNonNull;
-
-import com.google.common.annotations.Beta;
-import com.google.common.collect.Collections2;
-import com.google.common.collect.Iterables;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.mdsal.binding.model.api.GeneratedType;
-import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
-import org.opendaylight.mdsal.binding.runtime.api.CaseRuntimeType;
-import org.opendaylight.mdsal.binding.runtime.api.ChoiceRuntimeType;
-import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
-import org.opendaylight.yangtools.yang.model.api.stmt.ChoiceEffectiveStatement;
-
-@Beta
-public final class DerivedChoiceRuntimeType extends AbstractChoiceRuntimeType {
-    private final @NonNull ChoiceRuntimeType originalType;
-
-    public DerivedChoiceRuntimeType(final GeneratedType bindingType, final ChoiceEffectiveStatement statement,
-            final List<RuntimeType> children, final List<AugmentRuntimeType> augments,
-            final ChoiceRuntimeType originalType) {
-        super(bindingType, statement, children, augments);
-        this.originalType = requireNonNull(originalType);
-    }
-
-    @Override
-    public @NonNull ChoiceRuntimeType originalType() {
-        return originalType;
-    }
-
-    @Override
-    public Collection<CaseRuntimeType> additionalCaseChildren() {
-        final var myJavaTypes = Collections2.transform(validCaseChildren(), CaseRuntimeType::getIdentifier);
-        final var result = new ArrayList<CaseRuntimeType>();
-        for (var caseType : Iterables.concat(originalType.validCaseChildren(), originalType.additionalCaseChildren())) {
-            if (!myJavaTypes.contains(caseType.getIdentifier())) {
-                result.add(caseType);
-            }
-        }
-        return result;
-    }
-}
diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/OriginalCaseRuntimeType.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/OriginalCaseRuntimeType.java
deleted file mode 100644 (file)
index 200518d..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (c) 2021 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.mdsal.binding.generator.impl.rt;
-
-import com.google.common.annotations.Beta;
-import java.util.List;
-import org.opendaylight.mdsal.binding.model.api.GeneratedType;
-import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
-import org.opendaylight.mdsal.binding.runtime.api.CaseRuntimeType;
-import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
-import org.opendaylight.yangtools.yang.model.api.stmt.CaseEffectiveStatement;
-
-@Beta
-public final class OriginalCaseRuntimeType extends AbstractCaseRuntimeType {
-    public OriginalCaseRuntimeType(final GeneratedType bindingType, final CaseEffectiveStatement statement,
-            final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
-        super(bindingType, statement, children, augments);
-    }
-
-    @Override
-    public CaseRuntimeType originalType() {
-        return null;
-    }
-}
diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/OriginalChoiceRuntimeType.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/OriginalChoiceRuntimeType.java
deleted file mode 100644 (file)
index f996e42..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2021 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.mdsal.binding.generator.impl.rt;
-
-import com.google.common.annotations.Beta;
-import com.google.common.collect.ImmutableList;
-import java.util.Collection;
-import java.util.List;
-import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.mdsal.binding.model.api.GeneratedType;
-import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
-import org.opendaylight.mdsal.binding.runtime.api.CaseRuntimeType;
-import org.opendaylight.mdsal.binding.runtime.api.ChoiceRuntimeType;
-import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
-import org.opendaylight.yangtools.yang.model.api.stmt.ChoiceEffectiveStatement;
-
-@Beta
-public final class OriginalChoiceRuntimeType extends AbstractChoiceRuntimeType {
-    private final @NonNull ImmutableList<CaseRuntimeType> augmentedCases;
-
-    public OriginalChoiceRuntimeType(final GeneratedType bindingType, final ChoiceEffectiveStatement statement,
-            final List<RuntimeType> children, final List<AugmentRuntimeType> augments,
-            final List<CaseRuntimeType> augmentedCases) {
-        super(bindingType, statement, children, augments);
-        this.augmentedCases = ImmutableList.copyOf(augmentedCases);
-    }
-
-    @Override
-    public ChoiceRuntimeType originalType() {
-        return null;
-    }
-
-    @Override
-    public Collection<CaseRuntimeType> additionalCaseChildren() {
-        return augmentedCases;
-    }
-}
diff --git a/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/AugmentableRuntimeType.java b/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/AugmentableRuntimeType.java
new file mode 100644 (file)
index 0000000..cc06d15
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2022 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.mdsal.binding.runtime.api;
+
+import com.google.common.annotations.Beta;
+import java.util.List;
+import org.eclipse.jdt.annotation.NonNull;
+
+/**
+ * A {@link CompositeRuntimeType} which is also can be targeted by {@code augment} statements.
+ */
+@Beta
+public interface AugmentableRuntimeType extends CompositeRuntimeType {
+    /**
+     * Return the {@link AugmentRuntimeType}s extending this type, matching the underlying {@link #statement()}.
+     *
+     * @return {@link AugmentRuntimeType}s extending this type.
+     */
+    @NonNull List<AugmentRuntimeType> augments();
+}
index 73235013f51ca3d187b1708bdf65ae66dc2cd944..20a166688a7ae19022e00a44853ee26818cc30cc 100644 (file)
@@ -9,7 +9,10 @@ package org.opendaylight.mdsal.binding.runtime.api;
 
 import com.google.common.annotations.Beta;
 import java.util.Optional;
+import java.util.Set;
+import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.mdsal.binding.model.api.GeneratedType;
 import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
 import org.opendaylight.yangtools.concepts.Immutable;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -38,4 +41,52 @@ public interface BindingRuntimeTypes extends EffectiveModelContextProvider, Runt
         }
         return tmp;
     }
+
+    /**
+     * Lookup to all {@link CaseRuntimeType}s related to a {@link ChoiceRuntimeType}. This is important when dealing
+     * with sharing incurred by Binding Spec's reuse of constructs defined in a {@code grouping}.
+     *
+     * <p>
+     * As an example, consider {@link ChoiceRuntimeType} and {@link CaseRuntimeType} relationship to
+     * {@link GeneratedType}s in the following model:
+     * <pre>
+     *   <code>
+     *     grouping grp {
+     *       container foo {
+     *         choice bar;
+     *       }
+     *     }
+     *
+     *     container foo {
+     *       uses grp;
+     *     }
+     *
+     *     container bar {
+     *       uses grp;
+     *     }
+     *
+     *     augment /foo/foo/bar {
+     *       case baz
+     *     }
+     *
+     *     augment /bar/foo/bar {
+     *       case xyzzy;
+     *     }
+     *   </code>
+     * </pre>
+     * YANG view of what is valid in {@code /foo/foo/bar} differs from what is valid in {@code /bar/foo/bar}, but this
+     * difference is not reflected in generated Java constructs. More notably, the two augments being in different
+     * modules. Since {@code choice bar}'s is part of a reusable construct, {@code grouping one}, DataObjects' copy
+     * builders can propagate them without translating them to the appropriate manifestation -- and they can do nothing
+     * about that as they lack the complete view of the effective model.
+     *
+     * <p>
+     * This method provides a bridge between a particular instantiation of a {@code choice} to {@link CaseRuntimeType}s
+     * valid in all instantiations.
+     *
+     * @param choiceType A ChoiceRuntimeType
+     * @return The set of {@link CaseRuntimeType}s known to this instance
+     * @throws NullPointerException if {@code ChoiceRuntimeType} is null
+     */
+    @NonNull Set<CaseRuntimeType> allCaseChildren(ChoiceRuntimeType choiceType);
 }
index 8818903e59fe8b91b0418739d5b468f1a235bd7b..fb1110f5dd13f1cfa7774355723768c743f1d3cd 100644 (file)
@@ -8,22 +8,13 @@
 package org.opendaylight.mdsal.binding.runtime.api;
 
 import com.google.common.annotations.Beta;
-import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.yangtools.yang.model.api.stmt.CaseEffectiveStatement;
 
 /**
  * A {@link RuntimeType} associated with a {@code case} statement.
  */
 @Beta
-public interface CaseRuntimeType extends CompositeRuntimeType, DataRuntimeType {
+public interface CaseRuntimeType extends AugmentableRuntimeType, DataRuntimeType {
     @Override
     CaseEffectiveStatement statement();
-
-    /**
-     * Return the runtime type for the original manifestation of this type's {@code case} statement. Returns
-     * {@code null} if this type is the original.
-     *
-     * @return Original manifestatation, or {@code null} if this is the original manifestation.
-     */
-    @Nullable CaseRuntimeType originalType();
 }
index 9a2fa97b3b024bb3717dde2434bb07322f669c87..63fcb19bb32b8152b7f92896f9c8b2b034629d58 100644 (file)
@@ -12,10 +12,12 @@ import java.util.Collection;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
+import org.opendaylight.yangtools.yang.binding.Augmentable;
 import org.opendaylight.yangtools.yang.model.api.stmt.ChoiceEffectiveStatement;
 
 /**
- * A {@link RuntimeType} associated with a {@code choice} statement.
+ * A {@link RuntimeType} associated with a {@code choice} statement. Note that unlike YANG semantics, in Binding Spec
+ * semantics a type generated for a 'choice' statement is <b>does not</b> implement {@link Augmentable}.
  */
 @Beta
 public interface ChoiceRuntimeType extends CompositeRuntimeType, DataRuntimeType {
@@ -31,56 +33,10 @@ public interface ChoiceRuntimeType extends CompositeRuntimeType, DataRuntimeType
      */
     @Nullable CaseRuntimeType bindingCaseChild(JavaTypeName typeName);
 
-    /**
-     * Return the runtime type for the original manifestation of this type's {@code choice} statement.
-     * Returns {@code null} if this type is the original.
-     *
-     * @return Original manifestatation, or {@code null} if this is the original manifestation.
-     */
-    @Nullable ChoiceRuntimeType originalType();
-
     /**
      * Return all {@link CaseRuntimeType} valid at this type's statement.
      *
      * @return Valid {@link CaseRuntimeType}s
      */
     @NonNull Collection<CaseRuntimeType> validCaseChildren();
-
-    /**
-     * Return any additional {@link CaseRuntimeType}s which may be encountered when dealing with DataObjects supported
-     * by this type. These are not strictly valid in YANG view of modeled data, but may have potentially-equivalent
-     * representation, such as in the following case:
-     * <pre>
-     *   <code>
-     *     grouping one {
-     *       container foo {
-     *         choice bar;
-     *       }
-     *     }
-     *
-     *     container foo {
-     *       uses grp;
-     *     }
-     *
-     *     container bar {
-     *       uses grp;
-     *     }
-     *
-     *     augment /foo/foo/bar {
-     *       case baz
-     *     }
-     *
-     *     augment /bar/foo/bar {
-     *       case xyzzy;
-     *     }
-     *   </code>
-     * </pre>
-     * and, more notably, the two augments being in different modules. Since {@code choice bar}'s is part of a reusable
-     * construct, {@code grouping one}, DataObjects' copy builders can propagate them without translating them to the
-     * appropriate manifestation -- and they can do nothing about that as they lack the complete view of the effecitve
-     * model.
-     *
-     * @return Additional {@link CaseRuntimeType}s
-     */
-    @NonNull Collection<CaseRuntimeType> additionalCaseChildren();
 }
index 6d565a26a4e9123fe9828535ab3141aa2bbff39e..4ba56b617163a5ecff1317d18d529540f3934a70 100644 (file)
@@ -8,25 +8,12 @@
 package org.opendaylight.mdsal.binding.runtime.api;
 
 import com.google.common.annotations.Beta;
-import java.util.List;
-import org.eclipse.jdt.annotation.NonNull;
 
 /**
- * A {@link RuntimeType} which is also a {@link RuntimeTypeContainer}.
+ * A {@link RuntimeType} which is also a {@link RuntimeTypeContainer}. This is a pure composition interface and does not
+ * imply further contract.
  */
 @Beta
 public interface CompositeRuntimeType extends GeneratedRuntimeType, RuntimeTypeContainer {
-    /**
-     * Return the {@link AugmentRuntimeType}s extending this type, matching the underlying {@link #statement()}.
-     *
-     * @return {@link AugmentRuntimeType}s extending this type.
-     */
-    @NonNull List<AugmentRuntimeType> augments();
-
-    /**
-     * Return the {@link AugmentRuntimeType}s extending extending a namesake of this type.
-     *
-     * @return {@link AugmentRuntimeType}s extending a namesake of this type.
-     */
-    @NonNull List<AugmentRuntimeType> mismatchedAugments();
+    // Pure contract composition
 }
index 1f69491ec4bf5fc3cfb323e4ceb029def5f834f2..4a2d60819d4094dac10bc5b37787041f6d3ac180 100644 (file)
@@ -19,7 +19,7 @@ import org.opendaylight.yangtools.yang.model.api.stmt.DataTreeEffectiveStatement
 @Beta
 public interface ContainerLikeRuntimeType<D extends DeclaredStatement<QName>,
         E extends DataTreeEffectiveStatement<D> & DataTreeAwareEffectiveStatement<QName, D>>
-        extends CompositeRuntimeType, DataRuntimeType {
+        extends AugmentableRuntimeType, DataRuntimeType {
     @Override
     E statement();
 }
index 4e952d4e58fb3c8aaa8134e7f5156b788db86471..05a1f1bf221a0da0b8d00a64dcecf72a89376da8 100644 (file)
@@ -15,7 +15,7 @@ import org.opendaylight.yangtools.yang.model.api.stmt.ListEffectiveStatement;
  * A {@link RuntimeType} associated with a {@code list} statement.
  */
 @Beta
-public interface ListRuntimeType extends CompositeRuntimeType, DataRuntimeType {
+public interface ListRuntimeType extends AugmentableRuntimeType, DataRuntimeType {
     @Override
     ListEffectiveStatement statement();
 
index a89be0b8eaf9730b75a0e178534c69daaebbc175..821a58d75e3a7cf67636078b3a6a0d9620045ae1 100644 (file)
@@ -14,7 +14,7 @@ import org.opendaylight.yangtools.yang.model.api.stmt.NotificationEffectiveState
  * A {@link RuntimeType} associated with a {@code notification} statement.
  */
 @Beta
-public interface NotificationRuntimeType extends CompositeRuntimeType {
+public interface NotificationRuntimeType extends AugmentableRuntimeType {
     @Override
     NotificationEffectiveStatement statement();
 }
index 1acbae79b11d4eec152e61a16dd7748303898dc8..f6197b5666b39bf6023d2cab74964b3791d4fed8 100644 (file)
@@ -28,7 +28,7 @@ public interface RuntimeTypeContainer extends Immutable {
      * <p>
      * One important omission is this method <b>does not</b> resolve nodes which have been added via {@code augment}
      * statement. Those are exposed indirectly as children of {@link AugmentRuntimeType}s returned via
-     * {@link CompositeRuntimeType#augments()}, if applicable.
+     * {@link AugmentableRuntimeType#augments()}, if applicable.
      *
      * @param qname {@code schema node} identifier
      * @return Corresponding {@link RuntimeType}, or null if not found
index ef55504e52957f0e39a3dcbe4d70b6e4ecd67dbe..0f1dc3e9b90fc2b18ee2ec508e928fc9d4a6c2bc 100644 (file)
@@ -627,6 +627,11 @@ public final class BindingReflections {
      *            Class which should be used at particular subtree
      * @return true if and only if classes represents same data.
      */
+    // FIXME: this really should live in BindingRuntimeTypes and should not be based on reflection. The only user is
+    //        binding-dom-codec and the logic could easily be performed on GeneratedType instead. For a particular
+    //        world this boils down to a matrix, which can be calculated either on-demand or when we create
+    //        BindingRuntimeTypes. Achieving that will bring us one step closer to being able to have a pre-compiled
+    //        Binding Runtime.
     @SuppressWarnings({ "rawtypes", "unchecked" })
     public static boolean isSubstitutionFor(final Class potential, final Class target) {
         Set<Class> subImplemented = new HashSet<>(Arrays.asList(potential.getInterfaces()));