import static com.google.common.base.Verify.verifyNotNull;
import static java.util.Objects.requireNonNull;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
+import org.opendaylight.mdsal.binding.runtime.api.CaseRuntimeType;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.AugmentEffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
+import org.opendaylight.yangtools.yang.model.api.stmt.ChoiceEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeAwareEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeAwareEffectiveStatement.SchemaTreeNamespace;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.UsesEffectiveStatement;
/**
private GroupingGenerator grouping;
- UsesAugmentGenerator(final AugmentEffectiveStatement statement, final AbstractCompositeGenerator<?> parent,
- final UsesEffectiveStatement uses) {
+ UsesAugmentGenerator(final AugmentEffectiveStatement statement, final UsesEffectiveStatement uses,
+ final AbstractCompositeGenerator<?, ?> parent) {
super(statement, parent);
this.uses = requireNonNull(uses);
+
+ // FIXME: use SchemaTreeAwareEffectiveStatement
+ var stmt = parent.statement();
+ for (var qname : statement.argument().getNodeIdentifiers()) {
+ final var tmp = stmt;
+ stmt = stmt.streamEffectiveSubstatements(SchemaTreeEffectiveStatement.class)
+ .filter(child -> qname.equals(child.argument()))
+ .findFirst()
+ .orElseThrow(() -> new IllegalStateException("Failed to find " + qname + " in " + tmp));
+ }
+ setTargetStatement(stmt);
+ }
+
+ void resolveGrouping(final UsesEffectiveStatement resolvedUses, final GroupingGenerator resolvedGrouping) {
+ if (resolvedUses == uses) {
+ verify(grouping == null, "Attempted to re-resolve grouping of %s", this);
+ grouping = requireNonNull(resolvedGrouping);
+ }
}
- void linkGroupingDependency(final UsesEffectiveStatement checkUses, final GroupingGenerator resolvedGrouping) {
- if (uses.equals(checkUses)) {
- verify(grouping == null, "Attempted to relink %s from %s to %s", this, grouping, resolvedGrouping);
- this.grouping = requireNonNull(resolvedGrouping);
+ @NonNull AugmentRequirement startLinkage() {
+ // Here we are going in the opposite direction of RFC7950, section 7.13:
+ //
+ // The effect of a "uses" reference to a grouping is that the nodes
+ // defined by the grouping are copied into the current schema tree and
+ // are then updated according to the "refine" and "augment" statements.
+ //
+ // Our parent here is *not* the 'uses' statement, but rather the statement which contains it.
+ return new AugmentRequirement(this, verifyNotNull(grouping, "Unresolved grouping in %s", this));
+ }
+
+ @Override
+ List<CaseRuntimeType> augmentedCasesIn(final ChildLookup lookup, final ChoiceEffectiveStatement stmt) {
+ final var result = super.augmentedCasesIn(lookup, stmt);
+ if (result != null) {
+ return result;
+ }
+ final var augment = statement();
+ if (!lookup.contains(augment)) {
+ return List.of();
}
+
+ final var effectiveStatement = effectiveStatement(augment, stmt);
+ return createBuilder(effectiveStatement)
+ .fillTypes(lookup.inStatement(effectiveStatement), this)
+ .getCaseChilden();
}
@Override
- void loadTargetGenerator() {
- final GroupingGenerator grp = verifyNotNull(grouping, "No grouping linked in %s", this);
- final SchemaNodeIdentifier path = statement().argument();
-
- /*
- * Here we are going in the opposite direction of RFC7950, section 3.13:
- *
- * The effect of a "uses" reference to a grouping is that the nodes
- * defined by the grouping are copied into the current schema tree and
- * are then updated according to the "refine" and "augment" statements.
- *
- * Our argument is composed of QNames in the current schema tree's namespace, but the grouping may have been
- * defined in a different module -- and therefore it knows those children under its namespace. Adjust the path
- * we are searching if that happens to be the case.
- */
- setTargetGenerator(grp.resolveSchemaNode(path, grp.statement().argument().getModule()));
+ AugmentRuntimeType runtimeTypeIn(final ChildLookup lookup, final EffectiveStatement<?, ?> target) {
+ final var result = super.runtimeTypeIn(lookup, target);
+ if (result != null) {
+ return result;
+ }
+ final var augment = statement();
+ if (!lookup.contains(augment)) {
+ return null;
+ }
+
+ verify(target instanceof SchemaTreeAwareEffectiveStatement && target instanceof SchemaTreeEffectiveStatement,
+ "Unexpected statement %s", target);
+ final var effectiveStatement = effectiveStatement(augment, (SchemaTreeAwareEffectiveStatement<?, ?>) target);
+ return verifyNotNull(createInternalRuntimeType(lookup.inStatement(effectiveStatement), effectiveStatement));
+ }
+
+ private static @NonNull AugmentEffectiveStatement effectiveStatement(final AugmentEffectiveStatement augment,
+ final SchemaTreeAwareEffectiveStatement<?, ?> target) {
+ verify(target instanceof SchemaTreeEffectiveStatement, "Unexpected statement %s", target);
+ // 'uses'/'augment': our children are binding to target's namespace
+ final var targetNamespace = ((SchemaTreeEffectiveStatement<?>) target).argument().getModule();
+
+ final var stmts = augment.effectiveSubstatements();
+ final var builder = ImmutableList.<EffectiveStatement<?, ?>>builderWithExpectedSize(stmts.size());
+ for (var stmt : stmts) {
+ if (stmt instanceof SchemaTreeEffectiveStatement) {
+ final var qname = ((SchemaTreeEffectiveStatement<?>) stmt).getIdentifier().bindTo(targetNamespace);
+ target.get(SchemaTreeNamespace.class, qname).ifPresent(builder::add);
+ } else {
+ builder.add(stmt);
+ }
+ }
+
+ return new TargetAugmentEffectiveStatement(augment, target, builder.build());
}
}