From: Robert Varga Date: Mon, 14 Mar 2022 19:36:49 +0000 (+0100) Subject: Rework AugmentRuntimeType and Choice/Case linkage X-Git-Tag: v9.0.0~5 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=mdsal.git;a=commitdiff_plain;h=0ee55d1f9da11dd03ff05fc67d10cbcbfe63fd2c Rework AugmentRuntimeType and Choice/Case linkage 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 --- diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ChoiceNodeCodecContext.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ChoiceNodeCodecContext.java index 6100d4db20..6566f9e07d 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ChoiceNodeCodecContext.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ChoiceNodeCodecContext.java @@ -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 extends DataContainerCo final Map, DataContainerCodecPrototype> byClassBuilder = new HashMap<>(); final SetMultimap, DataContainerCodecPrototype> childToCase = SetMultimapBuilder.hashKeys().hashSetValues().build(); - final Set> 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 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 cazeCls = (Class) caze; - for (final Class 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(); + 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 cazeCls = (Class) cazeDef.getBindingClass(); + for (final Class 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 extends DataContainerCo ambiguousByCaseChildWarnings = ambiguousByCaseChildClass.isEmpty() ? ImmutableSet.of() : ConcurrentHashMap.newKeySet(); - final Map, 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, DataContainerCodecPrototype> real : byClassBuilder.entrySet()) { - if (BindingReflections.isSubstitutionFor(substitution, real.getKey())) { - bySubstitutionBuilder.put(substitution, real.getValue()); - break search; + final Map, 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, 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> loadCaseClasses() { - final var context = factory().getRuntimeContext(); - final var type = getType(); + private static DataContainerCodecPrototype 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 extends DataContainerCo return Iterables.concat(byCaseChildClass.keySet(), ambiguousByCaseChildClass.keySet()); } - protected DataContainerCodecPrototype 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; diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectCodecContext.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectCodecContext.java index 52a7b06be4..47575f9321 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectCodecContext.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectCodecContext.java @@ -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 possibleAugmentations; + final List 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 rpcOutputs = new HashMap<>(); // All RpcInputs, indexed by their RPC's QName private final Map rpcInputs = new HashMap<>(); + // All known 'choice's to their corresponding cases + private final SetMultimap 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 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); diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractAugmentGenerator.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractAugmentGenerator.java index 5a018acdb5..d52d09632b 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractAugmentGenerator.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractAugmentGenerator.java @@ -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 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 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 children, final List 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.>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 createBuilder( + final AugmentEffectiveStatement statement) { + return new CompositeRuntimeTypeBuilder<>(statement) { + @Override + AugmentRuntimeType build(final GeneratedType type, final AugmentEffectiveStatement statement, + final List children, final List 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; } } diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractCompositeGenerator.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractCompositeGenerator.java index e88739a72c..769830433f 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractCompositeGenerator.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractCompositeGenerator.java @@ -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 { - 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 children, @NonNull List augments); - - @Override - final R rebaseRuntimeType(final R type, final S statement) { - return createRuntimeType(type.javaType(), statement, indexChildren(statement), augmentRuntimeTypes()); + final @NonNull List augments() { + return augments; } - private @NonNull List indexChildren(final @NonNull S statement) { - final var childMap = new ArrayList(); - - 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 rt = childGen.runtimeTypeOf(child); - rt.ifPresent(childMap::add); - } - } - - return childMap; + final @NonNull List 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 augments() { - return augments; - } + abstract @NonNull CompositeRuntimeTypeBuilder createBuilder(S statement); - private @NonNull List 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 diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractExplicitGenerator.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractExplicitGenerator.java index 67883f3f94..5219378e39 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractExplicitGenerator.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractExplicitGenerator.java @@ -79,35 +79,81 @@ public abstract class AbstractExplicitGenerator runtimeType() { if (!runtimeTypeInitialized) { - runtimeType = createRuntimeType(); + final var type = runtimeJavaType(); + if (type != null) { + runtimeType = createExternalRuntimeType(type); + } runtimeTypeInitialized = true; } return Optional.ofNullable(runtimeType); } - final Optional 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 + *
+     *   
+     *     leaf foo {
+     *       type string;
+     *     }
+     *   
+     * 
+ * 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() { diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractTypeObjectGenerator.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractTypeObjectGenerator.java index 2c41edb80b..845fb0dcba 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractTypeObjectGenerator.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractTypeObjectGenerator.java @@ -457,20 +457,18 @@ abstract class AbstractTypeObjectGenerator, 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) { diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ActionGenerator.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ActionGenerator.java index 8b0c9b9b22..19cca901a5 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ActionGenerator.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ActionGenerator.java @@ -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 children, final List 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 builder, final TypeBuilderFactory builderFactory) { // actions are a separate concept } + + @Override + CompositeRuntimeTypeBuilder createBuilder( + final ActionEffectiveStatement statement) { + return new CompositeRuntimeTypeBuilder<>(statement) { + @Override + ActionRuntimeType build(final GeneratedType generatedType, final ActionEffectiveStatement statement, + final List childTypes, final List augmentTypes) { + verify(augmentTypes.isEmpty(), "Unexpected augments %s", augmentTypes); + return new DefaultActionRuntimeType(generatedType, statement, childTypes); + } + }; + } } diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/CaseGenerator.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/CaseGenerator.java index 1b3bc495db..f49f371aca 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/CaseGenerator.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/CaseGenerator.java @@ -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 CompositeSchemaTreeGeneratorchild 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 children, final List 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 createBuilder( + final CaseEffectiveStatement statement) { + return new CompositeRuntimeTypeBuilder<>(statement) { + @Override + CaseRuntimeType build(final GeneratedType generatedType, final CaseEffectiveStatement statement, + final List childTypes, final List 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 index 0000000000..083bf08f93 --- /dev/null +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ChildLookup.java @@ -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 validUsesAugments; + private final ImmutableSet squashNamespaces; + private final QNameModule localNamespace; + + private ChildLookup(final ImmutableSet validUsesAugments, + final ImmutableSet 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 newSquashNamespaces; + if (squashNamespaces.contains(itemNamespace)) { + newSquashNamespaces = squashNamespaces; + } else { + newSquashNamespaces = ImmutableSet.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 concatUsesAugments(final EffectiveStatement stmt) { + final var concat = ImmutableSet.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 streamUsesAugments(final EffectiveStatement stmt) { + return stmt.streamEffectiveSubstatements(UsesEffectiveStatement.class) + .flatMap(uses -> uses.streamEffectiveSubstatements(AugmentEffectiveStatement.class)); + } +} diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ChoiceGenerator.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ChoiceGenerator.java index 1a6ac7fe5b..1b73a7d4d5 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ChoiceGenerator.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ChoiceGenerator.java @@ -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 { + static final class ChoiceBuilder extends CompositeRuntimeTypeBuilder { + private ImmutableList augmentedCases; + + ChoiceBuilder(final ChoiceEffectiveStatement statement) { + super(statement); + } + + @Override + CompositeRuntimeTypeBuilder fillTypes( + final ChildLookup lookup, + final AbstractCompositeGenerator 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 children, final List 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 augments) { + final var builder = ImmutableList.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 children, final List 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(); - 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 index 0000000000..57af55851f --- /dev/null +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/CompositeRuntimeTypeBuilder.java @@ -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, R extends CompositeRuntimeType> { + private final List augmentTypes = new ArrayList<>(); + private final List 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 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 children, + List augments); + + CompositeRuntimeTypeBuilder fillTypes(final ChildLookup lookup, + final AbstractCompositeGenerator 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 > @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; + } +} diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ContainerGenerator.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ContainerGenerator.java index 6a8b7e3029..8e905ea938 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ContainerGenerator.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ContainerGenerator.java @@ -52,8 +52,14 @@ final class ContainerGenerator extends CompositeSchemaTreeGenerator children, final List augments) { - return new DefaultContainerRuntimeType(type, statement, children, augments); + CompositeRuntimeTypeBuilder createBuilder( + final ContainerEffectiveStatement statement) { + return new CompositeRuntimeTypeBuilder<>(statement) { + @Override + ContainerRuntimeType build(final GeneratedType type, final ContainerEffectiveStatement statement, + final List children, final List augments) { + return new DefaultContainerRuntimeType(type, statement, children, augments); + } + }; } } diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/GroupingGenerator.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/GroupingGenerator.java index d789413cac..74ca6074c0 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/GroupingGenerator.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/GroupingGenerator.java @@ -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 children, final List 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 createBuilder( + final GroupingEffectiveStatement statement) { + return new CompositeRuntimeTypeBuilder<>(statement) { + @Override + GroupingRuntimeType build(final GeneratedType type, final GroupingEffectiveStatement statement, + final List children, final List augments) { + // Groupings cannot be targeted by 'augment' + verify(augments.isEmpty(), "Unexpected augments %s", augments); + return new DefaultGroupingRuntimeType(type, statement, children); + } + }; } + } diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/IdentityGenerator.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/IdentityGenerator.java index e5fc913e72..ccd88efc57 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/IdentityGenerator.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/IdentityGenerator.java @@ -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 diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/InputGenerator.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/InputGenerator.java index 2400b4a9ee..08e4da9b3a 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/InputGenerator.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/InputGenerator.java @@ -25,8 +25,14 @@ class InputGenerator extends OperationContainerGenerator children, final List augments) { - return new DefaultInputRuntimeType(type, statement, children, augments); + final CompositeRuntimeTypeBuilder createBuilder( + final InputEffectiveStatement statement) { + return new CompositeRuntimeTypeBuilder<>(statement) { + @Override + InputRuntimeType build(final GeneratedType type, final InputEffectiveStatement statement, + final List children, final List augments) { + return new DefaultInputRuntimeType(type, statement, children, augments); + } + }; } } diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/KeyGenerator.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/KeyGenerator.java index 4a28b410f1..a45c1dcb35 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/KeyGenerator.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/KeyGenerator.java @@ -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 { - 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 diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/LeafGenerator.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/LeafGenerator.java index 53aadbed25..233b785917 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/LeafGenerator.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/LeafGenerator.java @@ -21,12 +21,13 @@ final class LeafGenerator extends AbstractTypeAwareGenerator children, final List 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 createBuilder( + final ListEffectiveStatement statement) { + return new CompositeRuntimeTypeBuilder<>(statement) { + @Override + ListRuntimeType build(final GeneratedType type, final ListEffectiveStatement statement, + final List children, final List augments) { + // FIXME: the key here is not rebased correctly :( + return new DefaultListRuntimeType(type, statement, children, augments, keyRuntimeType()); + } + }; + } } diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ModuleGenerator.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ModuleGenerator.java index 4607f9b437..edb1aee7dd 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ModuleGenerator.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ModuleGenerator.java @@ -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 children, final List augments) { - return new DefaultModuleRuntimeType(type, statement, children, augments); - } - @NonNull Member getPrefixMember() { return verifyNotNull(prefixMember); } @@ -113,4 +108,17 @@ public final class ModuleGenerator extends AbstractCompositeGenerator createBuilder( + final ModuleEffectiveStatement statement) { + return new CompositeRuntimeTypeBuilder<>(statement) { + @Override + ModuleRuntimeType build(final GeneratedType type, final ModuleEffectiveStatement statement, + final List children, final List augments) { + verify(augments.isEmpty(), "Unexpected augments %s", augments); + return new DefaultModuleRuntimeType(type, statement, children); + } + }; + } } diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/NotificationGenerator.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/NotificationGenerator.java index c2d4a38275..cc49b1d455 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/NotificationGenerator.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/NotificationGenerator.java @@ -58,14 +58,20 @@ final class NotificationGenerator } @Override - NotificationRuntimeType createRuntimeType(final GeneratedType type, final NotificationEffectiveStatement statement, - final List children, final List 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 createBuilder( + final NotificationEffectiveStatement statement) { + return new CompositeRuntimeTypeBuilder<>(statement) { + @Override + NotificationRuntimeType build(final GeneratedType type, final NotificationEffectiveStatement statement, + final List children, final List augments) { + return new DefaultNotificationRuntimeType(type, statement, children, augments); + } + }; } private Type notificationType(final GeneratedTypeBuilder builder, final TypeBuilderFactory builderFactory) { diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/OpaqueObjectGenerator.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/OpaqueObjectGenerator.java index 63564ce2f6..2e7da2abbb 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/OpaqueObjectGenerator.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/OpaqueObjectGenerator.java @@ -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, 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, 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, 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); } diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/OutputGenerator.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/OutputGenerator.java index 320593d7e6..83c48d2634 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/OutputGenerator.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/OutputGenerator.java @@ -25,8 +25,14 @@ class OutputGenerator extends OperationContainerGenerator children, final List augments) { - return new DefaultOutputRuntimeType(type, statement, children, augments); + final CompositeRuntimeTypeBuilder createBuilder( + final OutputEffectiveStatement statement) { + return new CompositeRuntimeTypeBuilder<>(statement) { + @Override + OutputRuntimeType build(final GeneratedType type, final OutputEffectiveStatement statement, + final List children, final List augments) { + return new DefaultOutputRuntimeType(type, statement, children, augments); + } + }; } } diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/RpcGenerator.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/RpcGenerator.java index 985ac81dd3..e0ae6b4151 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/RpcGenerator.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/RpcGenerator.java @@ -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 children, final List 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 createBuilder( + final RpcEffectiveStatement statement) { + // RPCs do not have a dedicated interface + throw new UnsupportedOperationException("Should never be called"); } } diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/TargetAugmentEffectiveStatement.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/TargetAugmentEffectiveStatement.java index 65544db7f2..0a80038022 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/TargetAugmentEffectiveStatement.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/TargetAugmentEffectiveStatement.java @@ -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> 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.>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(); + } } diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/TypedefGenerator.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/TypedefGenerator.java index 3267b83aa5..e3cfd4d594 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/TypedefGenerator.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/TypedefGenerator.java @@ -95,14 +95,16 @@ final class TypedefGenerator extends AbstractTypeObjectGenerator 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.>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 index 0000000000..a3dd7f2747 --- /dev/null +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/AbstractAugmentableRuntimeType.java @@ -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> + extends AbstractCompositeRuntimeType implements AugmentableRuntimeType { + private final @NonNull ImmutableList augments; + + AbstractAugmentableRuntimeType(final GeneratedType bindingType, final S statement, final List children, + final List augments) { + super(bindingType, statement, children); + this.augments = ImmutableList.copyOf(augments); + } + + @Override + public final List augments() { + return augments; + } +} diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/AbstractCompositeRuntimeType.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/AbstractCompositeRuntimeType.java index d67f1cf94c..85ecec6148 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/AbstractCompositeRuntimeType.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/AbstractCompositeRuntimeType.java @@ -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> extends AbstractRuntimeType implements CompositeRuntimeType { private final ImmutableMap byClass; private final ImmutableMap bySchemaTree; - private final @NonNull ImmutableList augments; - private final @NonNull ImmutableList mismatchedAugments; - AbstractCompositeRuntimeType(final GeneratedType bindingType, final S statement, final List children, - final List augments) { + AbstractCompositeRuntimeType(final GeneratedType bindingType, final S statement, final List children) { super(bindingType, statement); - final var substatements = statement.effectiveSubstatements(); - final var correctBuilder = ImmutableList.builder(); - final var mismatchedBuilder = ImmutableList.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> bySchemaTree = builder.build(); } - @Override - public final List augments() { - return augments; - } - - @Override - public final List mismatchedAugments() { - return mismatchedAugments; - } - @Override public final RuntimeType schemaTreeChild(final QName qname) { return bySchemaTree.get(requireNonNull(qname)); diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/AbstractRuntimeType.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/AbstractRuntimeType.java index c2cb51fec6..6bb4d1287f 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/AbstractRuntimeType.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/AbstractRuntimeType.java @@ -36,6 +36,9 @@ abstract class AbstractRuntimeType, 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(); } } diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultActionRuntimeType.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultActionRuntimeType.java index 84af4cc2f8..32aff37f7e 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultActionRuntimeType.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultActionRuntimeType.java @@ -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 children, final List augments) { - super(bindingType, statement, children, augments); + final List children) { + super(bindingType, statement, children); input = child(children, InputRuntimeType.class); output = child(children, OutputRuntimeType.class); } diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultAugmentRuntimeType.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultAugmentRuntimeType.java index 3a0de76f95..3ee15b7279 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultAugmentRuntimeType.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultAugmentRuntimeType.java @@ -18,7 +18,7 @@ import org.opendaylight.yangtools.yang.model.api.stmt.AugmentEffectiveStatement; public final class DefaultAugmentRuntimeType extends AbstractCompositeRuntimeType implements AugmentRuntimeType { public DefaultAugmentRuntimeType(final GeneratedType bindingType, final AugmentEffectiveStatement statement, - final List children, final List augments) { - super(bindingType, statement, children, augments); + final List children) { + super(bindingType, statement, children); } } diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultBindingRuntimeTypes.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultBindingRuntimeTypes.java index 9bd748f7dd..9222de8266 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultBindingRuntimeTypes.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultBindingRuntimeTypes.java @@ -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 choiceToCases; private final ImmutableMap modulesByNamespace; private final ImmutableSortedMap modulesByPackage; private final ImmutableMap identities; @@ -43,12 +49,14 @@ public final class DefaultBindingRuntimeTypes implements BindingRuntimeTypes { public DefaultBindingRuntimeTypes(final EffectiveModelContext context, final Map modules, final Map types, final Map identities, final Map rpcInputs, - final Map rpcOutputs) { + final Map rpcOutputs, + final SetMultimap 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 allCaseChildren(final ChoiceRuntimeType choiceType) { + return choiceToCases.get(choiceType.getIdentifier()); + } + @Override public String toString() { return MoreObjects.toStringHelper(this) diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/AbstractCaseRuntimeType.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultCaseRuntimeType.java similarity index 78% rename from binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/AbstractCaseRuntimeType.java rename to binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultCaseRuntimeType.java index ec518405b9..69fff2ebac 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/AbstractCaseRuntimeType.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultCaseRuntimeType.java @@ -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 +@Beta +public final class DefaultCaseRuntimeType extends AbstractAugmentableRuntimeType implements CaseRuntimeType { - AbstractCaseRuntimeType(final GeneratedType bindingType, final CaseEffectiveStatement statement, + public DefaultCaseRuntimeType(final GeneratedType bindingType, final CaseEffectiveStatement statement, final List children, final List augments) { super(bindingType, statement, children, augments); } diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/AbstractChoiceRuntimeType.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultChoiceRuntimeType.java similarity index 67% rename from binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/AbstractChoiceRuntimeType.java rename to binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultChoiceRuntimeType.java index 8f2809e19c..e69bd390a3 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/AbstractChoiceRuntimeType.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultChoiceRuntimeType.java @@ -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 +@Beta +public final class DefaultChoiceRuntimeType extends AbstractCompositeRuntimeType implements ChoiceRuntimeType { - AbstractChoiceRuntimeType(final GeneratedType bindingType, final ChoiceEffectiveStatement statement, - final List children, final List augments) { - super(bindingType, statement, children, augments); + public DefaultChoiceRuntimeType(final GeneratedType bindingType, final ChoiceEffectiveStatement statement, + final List children) { + super(bindingType, statement, children); } @Override - public final Collection validCaseChildren() { + public Collection 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; } diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultContainerRuntimeType.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultContainerRuntimeType.java index 3a9584793a..f9c934feb1 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultContainerRuntimeType.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultContainerRuntimeType.java @@ -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 +public final class DefaultContainerRuntimeType extends AbstractAugmentableRuntimeType implements ContainerRuntimeType { public DefaultContainerRuntimeType(final GeneratedType bindingType, final ContainerEffectiveStatement statement, final List children, final List augments) { diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultGroupingRuntimeType.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultGroupingRuntimeType.java index 42f9efecac..64260960e9 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultGroupingRuntimeType.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultGroupingRuntimeType.java @@ -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 implements GroupingRuntimeType { public DefaultGroupingRuntimeType(final GeneratedType bindingType, final GroupingEffectiveStatement statement, - final List children, final List augments) { - super(bindingType, statement, children, augments); + final List children) { + super(bindingType, statement, children); } } diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultInputRuntimeType.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultInputRuntimeType.java index 3b6eda8059..3a06ddc214 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultInputRuntimeType.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultInputRuntimeType.java @@ -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 +public class DefaultInputRuntimeType extends AbstractAugmentableRuntimeType implements InputRuntimeType { public DefaultInputRuntimeType(final GeneratedType bindingType, final InputEffectiveStatement statement, final List children, final List augments) { diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultListRuntimeType.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultListRuntimeType.java index c6e4bca188..c409de02d9 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultListRuntimeType.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultListRuntimeType.java @@ -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 +public final class DefaultListRuntimeType extends AbstractAugmentableRuntimeType implements ListRuntimeType { - private final KeyRuntimeType keyType; + private final @Nullable KeyRuntimeType keyType; public DefaultListRuntimeType(final GeneratedType bindingType, final ListEffectiveStatement statement, final List children, final List augments, final KeyRuntimeType keyType) { diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultModuleRuntimeType.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultModuleRuntimeType.java index 433107a6d8..e849745b9d 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultModuleRuntimeType.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultModuleRuntimeType.java @@ -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 implements ModuleRuntimeType { public DefaultModuleRuntimeType(final GeneratedType bindingType, final ModuleEffectiveStatement statement, - final List children, final List augments) { - super(bindingType, statement, children, augments); + final List children) { + super(bindingType, statement, children); } } diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultNotificationRuntimeType.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultNotificationRuntimeType.java index ef7866b4e4..4f9cf9f732 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultNotificationRuntimeType.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultNotificationRuntimeType.java @@ -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 +public final class DefaultNotificationRuntimeType extends AbstractAugmentableRuntimeType implements NotificationRuntimeType { public DefaultNotificationRuntimeType(final GeneratedType bindingType, final NotificationEffectiveStatement statement, final List children, diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultOutputRuntimeType.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultOutputRuntimeType.java index 0e4d150809..3c37d0e436 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultOutputRuntimeType.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DefaultOutputRuntimeType.java @@ -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 +public class DefaultOutputRuntimeType extends AbstractAugmentableRuntimeType implements OutputRuntimeType { public DefaultOutputRuntimeType(final GeneratedType bindingType, final OutputEffectiveStatement statement, final List children, final List 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 index 271f98ace1..0000000000 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DerivedCaseRuntimeType.java +++ /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 children, final List 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 index 3a81294583..0000000000 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/DerivedChoiceRuntimeType.java +++ /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 children, final List augments, - final ChoiceRuntimeType originalType) { - super(bindingType, statement, children, augments); - this.originalType = requireNonNull(originalType); - } - - @Override - public @NonNull ChoiceRuntimeType originalType() { - return originalType; - } - - @Override - public Collection additionalCaseChildren() { - final var myJavaTypes = Collections2.transform(validCaseChildren(), CaseRuntimeType::getIdentifier); - final var result = new ArrayList(); - 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 index 200518d21d..0000000000 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/OriginalCaseRuntimeType.java +++ /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 children, final List 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 index f996e42184..0000000000 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/rt/OriginalChoiceRuntimeType.java +++ /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 augmentedCases; - - public OriginalChoiceRuntimeType(final GeneratedType bindingType, final ChoiceEffectiveStatement statement, - final List children, final List augments, - final List augmentedCases) { - super(bindingType, statement, children, augments); - this.augmentedCases = ImmutableList.copyOf(augmentedCases); - } - - @Override - public ChoiceRuntimeType originalType() { - return null; - } - - @Override - public Collection 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 index 0000000000..cc06d15c77 --- /dev/null +++ b/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/AugmentableRuntimeType.java @@ -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 augments(); +} diff --git a/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/BindingRuntimeTypes.java b/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/BindingRuntimeTypes.java index 73235013f5..20a166688a 100644 --- a/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/BindingRuntimeTypes.java +++ b/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/BindingRuntimeTypes.java @@ -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}. + * + *

+ * As an example, consider {@link ChoiceRuntimeType} and {@link CaseRuntimeType} relationship to + * {@link GeneratedType}s in the following model: + *

+     *   
+     *     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;
+     *     }
+     *   
+     * 
+ * 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. + * + *

+ * 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 allCaseChildren(ChoiceRuntimeType choiceType); } diff --git a/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/CaseRuntimeType.java b/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/CaseRuntimeType.java index 8818903e59..fb1110f5dd 100644 --- a/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/CaseRuntimeType.java +++ b/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/CaseRuntimeType.java @@ -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(); } diff --git a/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/ChoiceRuntimeType.java b/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/ChoiceRuntimeType.java index 9a2fa97b3b..63fcb19bb3 100644 --- a/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/ChoiceRuntimeType.java +++ b/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/ChoiceRuntimeType.java @@ -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 does not 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 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: - *

-     *   
-     *     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;
-     *     }
-     *   
-     * 
- * 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 additionalCaseChildren(); } diff --git a/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/CompositeRuntimeType.java b/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/CompositeRuntimeType.java index 6d565a26a4..4ba56b6171 100644 --- a/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/CompositeRuntimeType.java +++ b/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/CompositeRuntimeType.java @@ -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 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 mismatchedAugments(); + // Pure contract composition } diff --git a/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/ContainerLikeRuntimeType.java b/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/ContainerLikeRuntimeType.java index 1f69491ec4..4a2d60819d 100644 --- a/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/ContainerLikeRuntimeType.java +++ b/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/ContainerLikeRuntimeType.java @@ -19,7 +19,7 @@ import org.opendaylight.yangtools.yang.model.api.stmt.DataTreeEffectiveStatement @Beta public interface ContainerLikeRuntimeType, E extends DataTreeEffectiveStatement & DataTreeAwareEffectiveStatement> - extends CompositeRuntimeType, DataRuntimeType { + extends AugmentableRuntimeType, DataRuntimeType { @Override E statement(); } diff --git a/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/ListRuntimeType.java b/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/ListRuntimeType.java index 4e952d4e58..05a1f1bf22 100644 --- a/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/ListRuntimeType.java +++ b/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/ListRuntimeType.java @@ -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(); diff --git a/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/NotificationRuntimeType.java b/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/NotificationRuntimeType.java index a89be0b8ea..821a58d75e 100644 --- a/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/NotificationRuntimeType.java +++ b/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/NotificationRuntimeType.java @@ -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(); } diff --git a/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/RuntimeTypeContainer.java b/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/RuntimeTypeContainer.java index 1acbae79b1..f6197b5666 100644 --- a/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/RuntimeTypeContainer.java +++ b/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/RuntimeTypeContainer.java @@ -28,7 +28,7 @@ public interface RuntimeTypeContainer extends Immutable { *

* One important omission is this method does not 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 diff --git a/binding/mdsal-binding-spec-util/src/main/java/org/opendaylight/mdsal/binding/spec/reflect/BindingReflections.java b/binding/mdsal-binding-spec-util/src/main/java/org/opendaylight/mdsal/binding/spec/reflect/BindingReflections.java index ef55504e52..0f1dc3e9b9 100644 --- a/binding/mdsal-binding-spec-util/src/main/java/org/opendaylight/mdsal/binding/spec/reflect/BindingReflections.java +++ b/binding/mdsal-binding-spec-util/src/main/java/org/opendaylight/mdsal/binding/spec/reflect/BindingReflections.java @@ -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 subImplemented = new HashSet<>(Arrays.asList(potential.getInterfaces()));