Track schema tree generator linkage 98/99798/17
authorRobert Varga <robert.varga@pantheon.tech>
Fri, 18 Feb 2022 10:49:16 +0000 (11:49 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Fri, 4 Mar 2022 20:19:58 +0000 (21:19 +0100)
Runtime information requires looking up target generator for a schema
tree particant, which means that AbstractCompositeGenerator needs to
resolve QName to the original instantiation.

We already have that mechanics for the most part, as we need to perform
the lookup to resolve augment statements target.

Introduce SchemaTree{Child,Parent} decomposition of the addressing
problem, and retrofit generators to support them. This will allow us to
support lookups along the schema tree axis.

JIRA: MDSAL-696
Change-Id: I619fe9e7c0896d6d3f0f33b04d5200ca8ec30340
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
19 files changed:
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractCompositeGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractTypeAwareGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ActionGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/CaseGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ChoiceGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/CompositeSchemaTreeGenerator.java [new file with mode: 0644]
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ContainerGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/GeneratorReactor.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/LeafGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/LeafListGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ListGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/NotificationGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/OpaqueObjectGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/OperationContainerGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/RpcGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/SchemaTreePlaceholder.java [new file with mode: 0644]
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/tree/SchemaTreeChild.java [new file with mode: 0644]
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/tree/SchemaTreeParent.java [new file with mode: 0644]
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/tree/package-info.java [new file with mode: 0644]

index 450dab4e2e232f27943688f783e7359d98e6c9d3..d4ed8314b06f2144f7ee8fd33256256b6c0bcec0 100644 (file)
@@ -13,9 +13,13 @@ import static java.util.Objects.requireNonNull;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
 import java.util.stream.Collectors;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.mdsal.binding.generator.impl.tree.SchemaTreeChild;
+import org.opendaylight.mdsal.binding.generator.impl.tree.SchemaTreeParent;
 import org.opendaylight.mdsal.binding.model.api.Enumeration;
 import org.opendaylight.mdsal.binding.model.api.GeneratedTransferObject;
 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
@@ -108,12 +112,17 @@ import org.slf4j.LoggerFactory;
  * with linking original instances in the tree iteration order. The part dealing with augment attachment lives mostly
  * in {@link AugmentRequirement}.
  */
-abstract class AbstractCompositeGenerator<T extends EffectiveStatement<?, ?>> extends AbstractExplicitGenerator<T> {
+public abstract class AbstractCompositeGenerator<T extends EffectiveStatement<?, ?>>
+        extends AbstractExplicitGenerator<T> implements SchemaTreeParent<T> {
     private static final Logger LOG = LoggerFactory.getLogger(AbstractCompositeGenerator.class);
 
     // FIXME: we want to allocate this lazily to lower memory footprint
     private final @NonNull CollisionDomain domain = new CollisionDomain(this);
-    private final List<Generator> children;
+    private final @NonNull List<Generator> childGenerators;
+    /**
+     * {@link SchemaTreeChild} children of this generator. Generator linkage is ensured on first access.
+     */
+    private final @NonNull List<SchemaTreeChild<?, ?>> schemaTreeChildren;
 
     /**
      * List of {@code augment} statements targeting this generator. This list is maintained only for the primary
@@ -142,22 +151,38 @@ abstract class AbstractCompositeGenerator<T extends EffectiveStatement<?, ?>> ex
 
     AbstractCompositeGenerator(final T statement) {
         super(statement);
-        children = createChildren(statement);
+
+        final var children = createChildren(statement);
+        childGenerators = children.getKey();
+        schemaTreeChildren = children.getValue();
     }
 
     AbstractCompositeGenerator(final T statement, final AbstractCompositeGenerator<?> parent) {
         super(statement, parent);
-        children = createChildren(statement);
+
+        final var children = createChildren(statement);
+        childGenerators = children.getKey();
+        schemaTreeChildren = children.getValue();
     }
 
     @Override
     public final Iterator<Generator> iterator() {
-        return children.iterator();
+        return childGenerators.iterator();
+    }
+
+    @Override
+    public List<SchemaTreeChild<?, ?>> schemaTreeChildren() {
+        for (var child : schemaTreeChildren) {
+            if (child instanceof SchemaTreePlaceholder) {
+                ((SchemaTreePlaceholder<?, ?>) child).setGenerator(this);
+            }
+        }
+        return schemaTreeChildren;
     }
 
     @Override
     final boolean isEmpty() {
-        return children.isEmpty();
+        return childGenerators.isEmpty();
     }
 
     final @Nullable AbstractExplicitGenerator<?> findGenerator(final List<EffectiveStatement<?, ?>> stmtPath) {
@@ -170,7 +195,7 @@ abstract class AbstractCompositeGenerator<T extends EffectiveStatement<?, ?>> ex
         final EffectiveStatement<?, ?> stmt = stmtPath.get(offset);
 
         // Try direct children first, which is simple
-        AbstractExplicitGenerator<?> ret = childStrategy.findGenerator(stmt, children);
+        AbstractExplicitGenerator<?> ret = childStrategy.findGenerator(stmt, childGenerators);
         if (ret != null) {
             final int next = offset + 1;
             if (stmtPath.size() == next) {
@@ -242,7 +267,7 @@ abstract class AbstractCompositeGenerator<T extends EffectiveStatement<?, ?>> ex
     }
 
     final void startUsesAugmentLinkage(final List<AugmentRequirement> requirements) {
-        for (Generator child : children) {
+        for (Generator child : childGenerators) {
             if (child instanceof UsesAugmentGenerator) {
                 requirements.add(((UsesAugmentGenerator) child).startLinkage());
             }
@@ -272,7 +297,7 @@ abstract class AbstractCompositeGenerator<T extends EffectiveStatement<?, ?>> ex
         }
 
         if (unlinkedChildren == null) {
-            unlinkedChildren = children.stream()
+            unlinkedChildren = childGenerators.stream()
                 .filter(AbstractExplicitGenerator.class::isInstance)
                 .map(child -> (AbstractExplicitGenerator<?>) child)
                 .collect(Collectors.toList());
@@ -439,33 +464,50 @@ abstract class AbstractCompositeGenerator<T extends EffectiveStatement<?, ?>> ex
         }
     }
 
-    private List<Generator> createChildren(final EffectiveStatement<?, ?> statement) {
-        final List<Generator> tmp = new ArrayList<>();
-        final List<AbstractAugmentGenerator> tmpAug = new ArrayList<>();
+    private Entry<List<Generator>, List<SchemaTreeChild<?, ?>>> createChildren(
+            final EffectiveStatement<?, ?> statement) {
+        final var tmp = new ArrayList<Generator>();
+        final var tmpAug = new ArrayList<AbstractAugmentGenerator>();
+        final var tmpSchema = new ArrayList<SchemaTreeChild<?, ?>>();
 
-        for (EffectiveStatement<?, ?> stmt : statement.effectiveSubstatements()) {
+        for (var stmt : statement.effectiveSubstatements()) {
             if (stmt instanceof ActionEffectiveStatement) {
-                if (!isAugmenting(stmt)) {
-                    tmp.add(new ActionGenerator((ActionEffectiveStatement) stmt, this));
+                final var cast = (ActionEffectiveStatement) stmt;
+                if (isAugmenting(cast)) {
+                    tmpSchema.add(new SchemaTreePlaceholder<>(cast, ActionGenerator.class));
+                } else {
+                    tmp.add(new ActionGenerator(cast, this));
                 }
             } else if (stmt instanceof AnydataEffectiveStatement) {
-                if (!isAugmenting(stmt)) {
-                    tmp.add(new OpaqueObjectGenerator<>((AnydataEffectiveStatement) stmt, this));
+                final var cast = (AnydataEffectiveStatement) stmt;
+                if (isAugmenting(stmt)) {
+                    tmpSchema.add(new SchemaTreePlaceholder<>(cast, OpaqueObjectGenerator.class));
+                } else {
+                    tmp.add(new OpaqueObjectGenerator<>(cast, this));
                 }
             } else if (stmt instanceof AnyxmlEffectiveStatement) {
-                if (!isAugmenting(stmt)) {
-                    tmp.add(new OpaqueObjectGenerator<>((AnyxmlEffectiveStatement) stmt, this));
+                final var cast = (AnyxmlEffectiveStatement) stmt;
+                if (isAugmenting(stmt)) {
+                    tmpSchema.add(new SchemaTreePlaceholder<>(cast, OpaqueObjectGenerator.class));
+                } else {
+                    tmp.add(new OpaqueObjectGenerator<>(cast, this));
                 }
             } else if (stmt instanceof CaseEffectiveStatement) {
                 tmp.add(new CaseGenerator((CaseEffectiveStatement) stmt, this));
             } else if (stmt instanceof ChoiceEffectiveStatement) {
+                final var cast = (ChoiceEffectiveStatement) stmt;
                 // FIXME: use isOriginalDeclaration() ?
-                if (!isAddedByUses(stmt)) {
-                    tmp.add(new ChoiceGenerator((ChoiceEffectiveStatement) stmt, this));
+                if (isAddedByUses(stmt)) {
+                    tmpSchema.add(new SchemaTreePlaceholder<>(cast, ChoiceGenerator.class));
+                } else {
+                    tmp.add(new ChoiceGenerator(cast, this));
                 }
             } else if (stmt instanceof ContainerEffectiveStatement) {
+                final var cast = (ContainerEffectiveStatement) stmt;
                 if (isOriginalDeclaration(stmt)) {
                     tmp.add(new ContainerGenerator((ContainerEffectiveStatement) stmt, this));
+                } else {
+                    tmpSchema.add(new SchemaTreePlaceholder<>(cast, ContainerGenerator.class));
                 }
             } else if (stmt instanceof GroupingEffectiveStatement) {
                 tmp.add(new GroupingGenerator((GroupingEffectiveStatement) stmt, this));
@@ -476,26 +518,38 @@ abstract class AbstractCompositeGenerator<T extends EffectiveStatement<?, ?>> ex
                 tmp.add(this instanceof RpcGenerator ? new RpcContainerGenerator((InputEffectiveStatement) stmt, this)
                     : new OperationContainerGenerator((InputEffectiveStatement) stmt, this));
             } else if (stmt instanceof LeafEffectiveStatement) {
-                if (!isAugmenting(stmt)) {
-                    tmp.add(new LeafGenerator((LeafEffectiveStatement) stmt, this));
+                final var cast = (LeafEffectiveStatement) stmt;
+                if (isAugmenting(stmt)) {
+                    tmpSchema.add(new SchemaTreePlaceholder<>(cast, LeafGenerator.class));
+                } else {
+                    tmp.add(new LeafGenerator(cast, this));
                 }
             } else if (stmt instanceof LeafListEffectiveStatement) {
-                if (!isAugmenting(stmt)) {
+                final var cast = (LeafListEffectiveStatement) stmt;
+                if (isAugmenting(stmt)) {
+                    tmpSchema.add(new SchemaTreePlaceholder<>(cast, LeafListGenerator.class));
+                } else {
                     tmp.add(new LeafListGenerator((LeafListEffectiveStatement) stmt, this));
                 }
             } else if (stmt instanceof ListEffectiveStatement) {
+                final var cast = (ListEffectiveStatement) stmt;
                 if (isOriginalDeclaration(stmt)) {
-                    final ListGenerator listGen = new ListGenerator((ListEffectiveStatement) stmt, this);
+                    final ListGenerator listGen = new ListGenerator(cast, this);
                     tmp.add(listGen);
 
                     final KeyGenerator keyGen = listGen.keyGenerator();
                     if (keyGen != null) {
                         tmp.add(keyGen);
                     }
+                } else {
+                    tmpSchema.add(new SchemaTreePlaceholder<>(cast, ListGenerator.class));
                 }
             } else if (stmt instanceof NotificationEffectiveStatement) {
-                if (!isAugmenting(stmt)) {
-                    tmp.add(new NotificationGenerator((NotificationEffectiveStatement) stmt, this));
+                final var cast = (NotificationEffectiveStatement) stmt;
+                if (isAugmenting(stmt)) {
+                    tmpSchema.add(new SchemaTreePlaceholder<>(cast, NotificationGenerator.class));
+                } else {
+                    tmp.add(new NotificationGenerator(cast, this));
                 }
             } else if (stmt instanceof OutputEffectiveStatement) {
                 // FIXME: do not generate legacy RPC layout
@@ -535,6 +589,13 @@ abstract class AbstractCompositeGenerator<T extends EffectiveStatement<?, ?>> ex
             }
         }
 
+        // Add any SchemaTreeChild generators to the list
+        for (var child : tmp) {
+            if (child instanceof SchemaTreeChild) {
+                tmpSchema.add((SchemaTreeChild<?, ?>) child);
+            }
+        }
+
         // Sort augments and add them last. This ensures child iteration order always reflects potential
         // interdependencies, hence we do not need to worry about them. This is extremely important, as there are a
         // number of places where we would have to either move the logic to parent statement and explicitly filter/sort
@@ -563,7 +624,7 @@ abstract class AbstractCompositeGenerator<T extends EffectiveStatement<?, ?>> ex
             }
         }
 
-        return List.copyOf(tmp);
+        return Map.entry(List.copyOf(tmp), List.copyOf(tmpSchema));
     }
 
     // Utility equivalent of (!isAddedByUses(stmt) && !isAugmenting(stmt)). Takes advantage of relationship between
index 6c0e9a34605b8b7ce4ec21a259d07fc517b4bd8e..a93efef124d26c70962a7db7558b06ee341580b0 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.mdsal.binding.generator.impl.reactor;
 
 import static com.google.common.base.Verify.verify;
 
+import org.opendaylight.mdsal.binding.generator.impl.tree.SchemaTreeChild;
 import org.opendaylight.mdsal.binding.model.api.GeneratedTransferObject;
 import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
 import org.opendaylight.mdsal.binding.model.api.Type;
@@ -21,16 +22,13 @@ import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.TypedDataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.stmt.DataTreeEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * Common base class for {@link LeafGenerator} and {@link LeafListGenerator}.
  */
-abstract class AbstractTypeAwareGenerator<T extends DataTreeEffectiveStatement<?>>
-        extends AbstractTypeObjectGenerator<T> {
-    private static final Logger LOG = LoggerFactory.getLogger(AbstractTypeAwareGenerator.class);
-
+abstract class AbstractTypeAwareGenerator<T extends DataTreeEffectiveStatement<?>,
+        G extends AbstractTypeAwareGenerator<T, G>>
+        extends AbstractTypeObjectGenerator<T> implements SchemaTreeChild<T, G> {
     private IdentityGenerator contextType;
 
     AbstractTypeAwareGenerator(final T statement, final AbstractCompositeGenerator<?> parent) {
@@ -38,6 +36,12 @@ abstract class AbstractTypeAwareGenerator<T extends DataTreeEffectiveStatement<?
         verify(statement instanceof TypeAware, "Unexpected statement %s", statement);
     }
 
+    @Override
+    @SuppressWarnings("unchecked")
+    public final G generator() {
+        return (G) this;
+    }
+
     @Override
     final void pushToInference(final SchemaInferenceStack dataTree) {
         dataTree.enterDataTree(statement().getIdentifier());
index 1b26a386739f55f4acb2dca0d8b379b60139f88a..f6dd71b5f5a9b0dc3b5d3be13f0df5e5e2a93e0b 100644 (file)
@@ -21,7 +21,7 @@ import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
 /**
  * Generator corresponding to a {@code action} statement.
  */
-final class ActionGenerator extends AbstractCompositeGenerator<ActionEffectiveStatement> {
+final class ActionGenerator extends CompositeSchemaTreeGenerator<ActionEffectiveStatement, ActionGenerator> {
     ActionGenerator(final ActionEffectiveStatement statement, final AbstractCompositeGenerator<?> parent) {
         super(statement, parent);
     }
index ab7c79e863136da0813503ded6ce58e2f3d3da35..84a29c0a85792c16320b1e45a33b5fd244051b41 100644 (file)
@@ -18,7 +18,7 @@ import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
 /**
  * Generator corresponding to a {@code case} statement.
  */
-final class CaseGenerator extends AbstractCompositeGenerator<CaseEffectiveStatement> {
+final class CaseGenerator extends CompositeSchemaTreeGenerator<CaseEffectiveStatement, CaseGenerator> {
     CaseGenerator(final CaseEffectiveStatement statement, final AbstractCompositeGenerator<?> parent) {
         super(statement, parent);
     }
index e43e2eff510927a067d43d0b63e6536e7bf30114..c45a09985725ff61e8ca9da4f20ac7adc09e4e44 100644 (file)
@@ -17,7 +17,7 @@ import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
 /**
  * Generator corresponding to a {@code choice} statement.
  */
-final class ChoiceGenerator extends AbstractCompositeGenerator<ChoiceEffectiveStatement> {
+final class ChoiceGenerator extends CompositeSchemaTreeGenerator<ChoiceEffectiveStatement, ChoiceGenerator> {
     ChoiceGenerator(final ChoiceEffectiveStatement statement, final AbstractCompositeGenerator<?> parent) {
         super(statement, parent);
     }
diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/CompositeSchemaTreeGenerator.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/CompositeSchemaTreeGenerator.java
new file mode 100644 (file)
index 0000000..c92707d
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * 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 org.opendaylight.mdsal.binding.generator.impl.tree.SchemaTreeChild;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
+
+/**
+ * Abstract base class for {@link AbstractCompositeGenerator}s which are also {@link SchemaTreeChild}ren.
+ */
+abstract class CompositeSchemaTreeGenerator<S extends SchemaTreeEffectiveStatement<?>,
+        G extends CompositeSchemaTreeGenerator<S, G>>
+        extends AbstractCompositeGenerator<S> implements SchemaTreeChild<S, G> {
+    CompositeSchemaTreeGenerator(final S statement, final AbstractCompositeGenerator<?> parent) {
+        super(statement, parent);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public final G generator() {
+        return (G) this;
+    }
+}
index b2d490ca7cd130d936d22e55c56a5ba24d9aa71b..cd2752f1ae45e312eb0b6919879f87825f15b5b6 100644 (file)
@@ -15,7 +15,7 @@ import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
 /**
  * Generator corresponding to a {@code container} statement.
  */
-final class ContainerGenerator extends AbstractCompositeGenerator<ContainerEffectiveStatement> {
+final class ContainerGenerator extends CompositeSchemaTreeGenerator<ContainerEffectiveStatement, ContainerGenerator> {
     ContainerGenerator(final ContainerEffectiveStatement statement, final AbstractCompositeGenerator<?> parent) {
         super(statement, parent);
     }
index 8a8feed0995d528301bd64b6918bccf652a027ce..f8214ad1445247f3e4d6878234037ee7e1f92bd4 100644 (file)
@@ -145,9 +145,9 @@ public final class GeneratorReactor extends GeneratorContext implements Mutable
         }
         LOG.trace("Processing linkage of {} augment generators", augments.size());
 
-        // Step 1c: ... finally establish linkage along the reverse uses/augment axis. This is needed to route generated
-        //          type manifestations (isAddedByUses/isAugmenting) to their type generation sites. Since generator
-        //          tree iteration order does not match dependencies, we may need to perform multiple passes.
+        // Step 1c: Establish linkage along the reverse uses/augment axis. This is needed to route generated type
+        //          manifestations (isAddedByUses/isAugmenting) to their type generation sites. Since generator tree
+        //          iteration order does not match dependencies, we may need to perform multiple passes.
         for (ModuleGenerator module : children) {
             verify(module.linkOriginalGenerator(), "Module %s failed to link", module);
         }
@@ -319,7 +319,7 @@ public final class GeneratorReactor extends GeneratorContext implements Mutable
         }
     }
 
-    private @NonNull AbstractTypeAwareGenerator<?> strictResolvePath(final @NonNull PathExpression path) {
+    private @NonNull AbstractTypeAwareGenerator<?, ?> strictResolvePath(final @NonNull PathExpression path) {
         try {
             inferenceStack.resolvePathExpression(path);
         } catch (IllegalArgumentException e) {
@@ -328,7 +328,7 @@ public final class GeneratorReactor extends GeneratorContext implements Mutable
         return mapToGenerator();
     }
 
-    private @Nullable AbstractTypeAwareGenerator<?> lenientResolveLeafref(final @NonNull PathExpression path) {
+    private @Nullable AbstractTypeAwareGenerator<?, ?> lenientResolveLeafref(final @NonNull PathExpression path) {
         try {
             inferenceStack.resolvePathExpression(path);
         } catch (IllegalArgumentException e) {
@@ -339,7 +339,7 @@ public final class GeneratorReactor extends GeneratorContext implements Mutable
     }
 
     // Map a statement to the corresponding generator
-    private @NonNull AbstractTypeAwareGenerator<?> mapToGenerator() {
+    private @NonNull AbstractTypeAwareGenerator<?, ?> mapToGenerator() {
         // Some preliminaries first: we need to be in the correct module to walk the path
         final ModuleEffectiveStatement module = inferenceStack.currentModule();
         final ModuleGenerator gen = verifyNotNull(generators.get(module.localQNameModule()),
@@ -349,7 +349,7 @@ public final class GeneratorReactor extends GeneratorContext implements Mutable
         final List<EffectiveStatement<?, ?>> stmtPath = inferenceStack.toInference().statementPath();
         final AbstractExplicitGenerator<?> found = gen.findGenerator(stmtPath);
         if (found instanceof AbstractTypeAwareGenerator) {
-            return (AbstractTypeAwareGenerator<?>) found;
+            return (AbstractTypeAwareGenerator<?, ?>) found;
         }
         throw new VerifyException("Statements " + stmtPath + " resulted in unexpected " + found);
     }
index c28dbf0f1ba78924dce7440fd4e87436f52e3200..a872d94c465353fa801ad994d845e40ff695b638 100644 (file)
@@ -12,7 +12,7 @@ import org.opendaylight.yangtools.yang.model.api.stmt.LeafEffectiveStatement;
 /**
  * Generator corresponding to a {@code leaf} statement.
  */
-final class LeafGenerator extends AbstractTypeAwareGenerator<LeafEffectiveStatement> {
+final class LeafGenerator extends AbstractTypeAwareGenerator<LeafEffectiveStatement, LeafGenerator> {
     LeafGenerator(final LeafEffectiveStatement statement, final AbstractCompositeGenerator<?> parent) {
         super(statement, parent);
     }
index f20ad882aa49fca638dc9ce408b9cace0ecd1bff..68727b69c32cfc3cdfd74fd8421fa98c07f91b3b 100644 (file)
@@ -16,7 +16,7 @@ import org.opendaylight.yangtools.yang.model.api.stmt.OrderedByEffectiveStatemen
 /**
  * Generator corresponding to a {@code leaf-list} statement.
  */
-final class LeafListGenerator extends AbstractTypeAwareGenerator<LeafListEffectiveStatement> {
+final class LeafListGenerator extends AbstractTypeAwareGenerator<LeafListEffectiveStatement, LeafListGenerator> {
     LeafListGenerator(final LeafListEffectiveStatement statement, final AbstractCompositeGenerator<?> parent) {
         super(statement, parent);
     }
index 5eca4ee13a6a3ed27a100a59edd61bf95d85a8dc..63a6e8d9afd5195557b470b3ef1339654e58afef 100644 (file)
@@ -27,7 +27,7 @@ import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
 /**
  * Generator corresponding to a {@code list} statement.
  */
-final class ListGenerator extends AbstractCompositeGenerator<ListEffectiveStatement> {
+final class ListGenerator extends CompositeSchemaTreeGenerator<ListEffectiveStatement, ListGenerator> {
     private final @Nullable KeyGenerator keyGen;
 
     ListGenerator(final ListEffectiveStatement statement, final AbstractCompositeGenerator<?> parent) {
index e169fb9f1edabd791d4aee4c8ff8f64e1128e34c..1be7ae1112d40223946a64a5a4231704c976f070 100644 (file)
@@ -18,7 +18,8 @@ import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
 /**
  * Generator corresponding to a {@code notification} statement.
  */
-final class NotificationGenerator extends AbstractCompositeGenerator<NotificationEffectiveStatement> {
+final class NotificationGenerator
+        extends CompositeSchemaTreeGenerator<NotificationEffectiveStatement, NotificationGenerator> {
     NotificationGenerator(final NotificationEffectiveStatement statement, final AbstractCompositeGenerator<?> parent) {
         super(statement, parent);
     }
index d05c9b55ed0f45d8c8e4931e68aacbd4ae72b888..f020779dca5b6b679a5245ab53823f4f6b2ce3d8 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.mdsal.binding.generator.impl.reactor;
 
+import org.opendaylight.mdsal.binding.generator.impl.tree.SchemaTreeChild;
 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;
@@ -18,11 +19,17 @@ import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
 /**
  * Common generator for {@code anydata} and {@code anyxml}.
  */
-final class OpaqueObjectGenerator<T extends DataTreeEffectiveStatement<?>> extends AbstractExplicitGenerator<T> {
+final class OpaqueObjectGenerator<T extends DataTreeEffectiveStatement<?>> extends AbstractExplicitGenerator<T>
+        implements SchemaTreeChild<T, OpaqueObjectGenerator<T>> {
     OpaqueObjectGenerator(final T statement, final AbstractCompositeGenerator<?> parent) {
         super(statement, parent);
     }
 
+    @Override
+    public OpaqueObjectGenerator<T> generator() {
+        return this;
+    }
+
     @Override
     void pushToInference(final SchemaInferenceStack dataTree) {
         dataTree.enterDataTree(statement().getIdentifier());
index bd3ea607ae0131f2572a4e7c1f7071cbbce0de71..e588743fdaba9610502e4acc20178bb87fc3ee20 100644 (file)
@@ -19,7 +19,8 @@ import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
 /**
  * Generator corresponding to an {@code input} or an {@code output} statement.
  */
-class OperationContainerGenerator extends AbstractCompositeGenerator<SchemaTreeEffectiveStatement<?>> {
+class OperationContainerGenerator
+        extends CompositeSchemaTreeGenerator<SchemaTreeEffectiveStatement<?>, OperationContainerGenerator> {
     private final ConcreteType baseInterface;
 
     OperationContainerGenerator(final InputEffectiveStatement statement, final AbstractCompositeGenerator<?> parent) {
index a79d27f3a3e07f366b702a530727548bbb11aa16..39b934e18d44b2a85c50bcff48201fe1a223fe4f 100644 (file)
@@ -15,7 +15,7 @@ import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
 /**
  * Generator corresponding to a {@code rpc} statement.
  */
-final class RpcGenerator extends AbstractCompositeGenerator<RpcEffectiveStatement> {
+final class RpcGenerator extends CompositeSchemaTreeGenerator<RpcEffectiveStatement, RpcGenerator> {
     RpcGenerator(final RpcEffectiveStatement statement, final AbstractCompositeGenerator<?> parent) {
         super(statement, parent);
     }
diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/SchemaTreePlaceholder.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/SchemaTreePlaceholder.java
new file mode 100644 (file)
index 0000000..9cfd59e
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * 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 org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.mdsal.binding.generator.impl.tree.SchemaTreeChild;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
+
+/**
+ * A placeholder {@link SchemaTreeChild}.
+ *
+ */
+final class SchemaTreePlaceholder<S extends SchemaTreeEffectiveStatement<?>,
+        G extends AbstractExplicitGenerator<S> & SchemaTreeChild<S, G>> implements SchemaTreeChild<S, G> {
+    private final @NonNull Class<G> generatorType;
+    private final @NonNull S statement;
+
+    private @Nullable G generator;
+
+    SchemaTreePlaceholder(final S statement, final Class<G> generatorType) {
+        this.statement = requireNonNull(statement);
+        this.generatorType = requireNonNull(generatorType);
+    }
+
+    @Override
+    public S statement() {
+        return statement;
+    }
+
+    @Override
+    public G generator() {
+        final var local = generator;
+        if (local == null) {
+            throw new IllegalStateException("Unresolved generator in " + this);
+        }
+        return local;
+    }
+
+    void setGenerator(final AbstractCompositeGenerator<?> parent) {
+        verify(generator == null, "Attempted to set generator for %s", this);
+        final var qname = getIdentifier();
+        generator = generatorType.cast(verifyNotNull(parent.findSchemaTreeGenerator(qname),
+            "Failed to find generator for child %s in %s", qname, parent));
+    }
+}
diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/tree/SchemaTreeChild.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/tree/SchemaTreeChild.java
new file mode 100644 (file)
index 0000000..e3c409c
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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.tree;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.mdsal.binding.generator.impl.reactor.AbstractExplicitGenerator;
+import org.opendaylight.yangtools.concepts.Identifiable;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
+
+/**
+ * An object reflecting a YANG {@code schema node}.
+ *
+ * @param <S> Concrete {@link SchemaTreeEffectiveStatement} type
+ * @param <G> Concrete {@link AbstractExplicitGenerator} type
+ */
+// FIXME: do not reference Generator once we have the codegen and runtime views well-defined
+public interface SchemaTreeChild<S extends SchemaTreeEffectiveStatement<?>,
+        G extends AbstractExplicitGenerator<S> & SchemaTreeChild<S, G>> extends Identifiable<QName> {
+    @Override
+    default QName getIdentifier() {
+        return statement().argument();
+    }
+
+    /**
+     * Return the effective YANG statement being represented by this object.
+     *
+     * @return A YANG statement
+     */
+    @NonNull S statement();
+
+    /**
+     * Return the generator responsible for handling the binding type view of this statement. Note that the statement
+     * returned by {@code generator().statement()} may differ from the statement returned by {@link #statement()}.
+     *
+     * @return Underlying binding generator
+     * @throws IllegalStateException if the generator has not been resolved yet
+     */
+    @NonNull G generator();
+}
diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/tree/SchemaTreeParent.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/tree/SchemaTreeParent.java
new file mode 100644 (file)
index 0000000..d846bef
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * 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.tree;
+
+import java.util.List;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+
+/**
+ * A parent containing a number of {@link SchemaTreeChild} objects.
+ *
+ * @param <S> Concrete {@link EffectiveStatement} type
+ */
+// FIXME: S extends SchemaTreeAwareStatement ... once AugmentEffectiveStatement implements that
+public interface SchemaTreeParent<S extends EffectiveStatement<?, ?>> {
+    /*
+     * Immutable view of children of this object along the {@code schema tree} child axis.
+     *
+     * @return Immutable view of this objects children along the {@code schema tree} child axis.
+     */
+    @NonNull List<SchemaTreeChild<?, ?>> schemaTreeChildren();
+}
diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/tree/package-info.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/tree/package-info.java
new file mode 100644 (file)
index 0000000..35a9759
--- /dev/null
@@ -0,0 +1,11 @@
+/*
+ * 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
+ */
+/**
+ * Concepts relating to the organization of the tree backing the codegen and runtime type information generator.
+ */
+package org.opendaylight.mdsal.binding.generator.impl.tree;
\ No newline at end of file