2 * Copyright (c) 2022 PANTHEON.tech, s.r.o. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.mdsal.binding.generator.impl.reactor;
10 import static com.google.common.base.Verify.verify;
11 import static com.google.common.base.Verify.verifyNotNull;
12 import static java.util.Objects.requireNonNull;
14 import java.util.ArrayList;
15 import java.util.List;
16 import java.util.stream.Collectors;
17 import org.eclipse.jdt.annotation.NonNull;
18 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
19 import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
20 import org.opendaylight.mdsal.binding.runtime.api.CaseRuntimeType;
21 import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType;
22 import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
23 import org.opendaylight.yangtools.yang.common.QName;
24 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
25 import org.opendaylight.yangtools.yang.model.api.stmt.AugmentEffectiveStatement;
26 import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement;
27 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
29 abstract class CompositeRuntimeTypeBuilder<S extends EffectiveStatement<?, ?>, R extends CompositeRuntimeType> {
30 private final List<AugmentRuntimeType> augmentTypes = new ArrayList<>();
31 private final List<RuntimeType> childTypes = new ArrayList<>();
32 private final @NonNull S statement;
34 CompositeRuntimeTypeBuilder(final S statement) {
35 this.statement = requireNonNull(statement);
38 final CompositeRuntimeTypeBuilder<S, R> populate(final AugmentResolver resolver,
39 final AbstractCompositeGenerator<S, R> generator) {
40 resolver.enter(generator);
42 processGenerator(resolver, generator);
49 final @NonNull R build(final @NonNull GeneratedType generatedType) {
50 return build(generatedType, statement, childTypes, augmentTypes);
53 abstract @NonNull R build(GeneratedType type, S statement, List<RuntimeType> children,
54 List<AugmentRuntimeType> augments);
56 final @NonNull List<CaseRuntimeType> getCaseChilden() {
57 return childTypes.stream()
59 verify(child instanceof CaseRuntimeType, "Unexpected child %s in %s", child, statement);
60 return (CaseRuntimeType) child;
62 .collect(Collectors.toUnmodifiableList());
65 final @NonNull S statement() {
69 boolean isAugmentedChild(final QName qname) {
70 // Note we are dealing with two different kinds of augments and they behave differently with respect
71 // to namespaces. Top-level augments do not make an adjustment, while uses-augments do.
72 for (var augment : augmentTypes) {
73 if (augment.schemaTreeChild(qname) != null) {
80 void processAugment(final AugmentResolver resolver, final AbstractAugmentGenerator augment) {
81 augmentTypes.add(augment.runtimeTypeIn(resolver, statement));
84 private void processGenerator(final AugmentResolver resolver, final AbstractCompositeGenerator<S, R> generator) {
85 // Figure out which augments are valid in target statement and record their RuntimeTypes.
86 // We will pass the latter to create method. We will use the former to perform replacement lookups instead
87 // of 'this.augments'. That is necessary because 'this.augments' holds all augments targeting the GeneratedType,
88 // hence equivalent augmentations from differing places would match our lookup and the reverse search would be
91 // Note we should not do this for 'module' and 'uses' statements, as those are not valid augment targets. Of
92 // those two we only generate things for 'module'.
93 if (!(statement instanceof ModuleEffectiveStatement)) {
94 for (var stmt : statement.effectiveSubstatements()) {
95 if (stmt instanceof AugmentEffectiveStatement augment) {
96 processAugment(resolver, resolver.getAugment(augment));
101 // Now construct RuntimeTypes for each schema tree child of stmt
102 for (var stmt : statement.effectiveSubstatements()) {
103 if (stmt instanceof SchemaTreeEffectiveStatement<?> child) {
104 // Try valid augments first: they should be empty most of the time and filter all the cases where we
105 // would not find the streamChild among our local and grouping statements. Note that unlike all others,
106 // such matches are not considered to be children in Binding DataObject tree, they are only considered
107 // such in the schema tree.
109 // That is in general -- 'choice' statements are doing their own thing separately.
110 if (!isAugmentedChild(child.argument())) {
111 final var childGen = verifyNotNull(findChildGenerator(generator, child.argument().getLocalName()),
112 "Cannot find child for %s in %s", child, generator);
113 final var childRuntimeType = childGen.createInternalRuntimeType(resolver, child);
114 if (childRuntimeType != null) {
115 childTypes.add(childRuntimeType);
122 // When we reach here we have dealt with all known augments in this scope, hence the only option is that the
123 // statement is either local or added via 'uses' -- in either case it has namespace equal to whatever the local
124 // namespace is and there can be no conflicts on QName.getLocalName(). That simplifies things a ton.
125 private static <S extends SchemaTreeEffectiveStatement<?>> AbstractExplicitGenerator<S, ?> findChildGenerator(
126 final AbstractCompositeGenerator<?, ?> parent, final String localName) {
127 // Search direct children first ...
128 for (var child : parent) {
129 if (child instanceof AbstractExplicitGenerator) {
130 @SuppressWarnings("unchecked")
131 final AbstractExplicitGenerator<S, ?> gen = (AbstractExplicitGenerator<S, ?>) child;
132 final EffectiveStatement<?, ?> genStmt = gen.statement();
133 if (genStmt instanceof SchemaTreeEffectiveStatement<?> schemaStmt
134 && localName.equals(schemaStmt.argument().getLocalName())) {
140 // ... groupings recursively next ...
141 for (var grouping : parent.groupings()) {
142 final AbstractExplicitGenerator<S, ?> found = findChildGenerator(grouping, localName);
148 // ... and finally anything along instantiation axis ...
149 final var origParent = (AbstractCompositeGenerator<?, ?>) parent.previous();
150 return origParent == null ? null : findChildGenerator(origParent, localName);