Bump to odlparent-9.0.0/yangtools-7.0.1-SNAPSHOT
[mdsal.git] / binding / mdsal-binding-generator-impl / src / main / java / org / opendaylight / mdsal / binding / generator / impl / reactor / AbstractAugmentGenerator.java
1 /*
2  * Copyright (c) 2021 PANTHEON.tech, s.r.o. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.mdsal.binding.generator.impl.reactor;
9
10 import static com.google.common.base.Verify.verify;
11 import static com.google.common.base.Verify.verifyNotNull;
12
13 import java.util.Comparator;
14 import org.eclipse.jdt.annotation.NonNull;
15 import org.opendaylight.mdsal.binding.generator.impl.reactor.CollisionDomain.Member;
16 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
17 import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilder;
18 import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilderBase;
19 import org.opendaylight.mdsal.binding.model.util.BindingTypes;
20 import org.opendaylight.yangtools.odlext.model.api.AugmentIdentifierEffectiveStatement;
21 import org.opendaylight.yangtools.yang.common.AbstractQName;
22 import org.opendaylight.yangtools.yang.model.api.stmt.AugmentEffectiveStatement;
23 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
24
25 /**
26  * A generator corresponding to a {@code augment} statement. This class is further specialized for the two distinct uses
27  * an augment is used.
28  */
29 abstract class AbstractAugmentGenerator extends AbstractCompositeGenerator<AugmentEffectiveStatement> {
30     /**
31      * Comparator comparing target path length. This is useful for quickly determining order the order in which two
32      * (or more) {@link AbstractAugmentGenerator}s need to be evaluated. This is necessary when augments are layered on
33      * top of each other:
34      *
35      * <p>
36      * <pre>
37      *   <code>
38      *     container foo;
39      *
40      *     augment /foo/bar {
41      *       container baz;
42      *     }
43      *
44      *     augment /foo {
45      *       container bar;
46      *     }
47      *   </code>
48      * </pre>
49      *
50      * <p>
51      * Evaluating these in the order of increasing argument component count solves this without having to perform a full
52      * analysis.
53      */
54     static final Comparator<? super AbstractAugmentGenerator> COMPARATOR =
55         Comparator.comparingInt(augment -> augment.statement().argument().getNodeIdentifiers().size());
56
57     private AbstractCompositeGenerator<?> targetGen;
58
59     AbstractAugmentGenerator(final AugmentEffectiveStatement statement, final AbstractCompositeGenerator<?> parent) {
60         super(statement, parent);
61     }
62
63     @Override
64     final void pushToInference(final SchemaInferenceStack dataTree) {
65         dataTree.enterSchemaTree(statement().argument());
66     }
67
68     @Override
69     final AbstractQName localName() {
70         throw new UnsupportedOperationException();
71     }
72
73     @Override
74     ClassPlacement classPlacement() {
75         // if the target is a choice we are NOT creating an explicit augmentation, but we still need a phantom to
76         // reserve the appropriate package name
77         final AbstractCompositeGenerator<?> target = targetGenerator();
78         return target instanceof ChoiceGenerator ? ClassPlacement.PHANTOM : super.classPlacement();
79     }
80
81     @Override
82     final Member createMember(final CollisionDomain domain) {
83         final AbstractQName explicitIdentifier = statement()
84             .findFirstEffectiveSubstatementArgument(AugmentIdentifierEffectiveStatement.class).orElse(null);
85         if (explicitIdentifier != null) {
86             return domain.addPrimary(new CamelCaseNamingStrategy(StatementNamespace.DEFAULT, explicitIdentifier));
87         }
88
89         final AbstractCompositeGenerator<?> target = targetGenerator();
90         final AbstractQName ref = target.localName();
91         int offset = 1;
92         for (Generator gen : getParent()) {
93             if (gen == this) {
94                 break;
95             }
96             if (gen instanceof AbstractAugmentGenerator
97                 && ref.equals(((AbstractAugmentGenerator) gen).targetGenerator().localName())) {
98                 offset++;
99             }
100         }
101
102         return domain.addSecondary(target.getMember(), String.valueOf(offset), statement().argument());
103     }
104
105     @Override
106     final GeneratedType createTypeImpl(final TypeBuilderFactory builderFactory) {
107         final GeneratedTypeBuilder builder = builderFactory.newGeneratedTypeBuilder(typeName());
108
109         builder.addImplementsType(BindingTypes.augmentation(targetGenerator().getGeneratedType(builderFactory)));
110         addUsesInterfaces(builder, builderFactory);
111         addConcreteInterfaceMethods(builder);
112
113         addGetterMethods(builder, builderFactory);
114         annotateDeprecatedIfNecessary(builder);
115
116         return builder.build();
117     }
118
119     @Override
120     final void addAsGetterMethod(final GeneratedTypeBuilderBase<?> builder, final TypeBuilderFactory builderFactory) {
121         // Augments are never added as getters, as they are handled via Augmentable mechanics
122     }
123
124     final void setTargetGenerator(final AbstractExplicitGenerator<?> target) {
125         verify(target instanceof AbstractCompositeGenerator, "Unexpected target %s", target);
126         targetGen = (AbstractCompositeGenerator<?>) target;
127         targetGen.addAugment(this);
128     }
129
130     final @NonNull AbstractCompositeGenerator<?> targetGenerator() {
131         final AbstractCompositeGenerator<?> existing = targetGen;
132         if (existing != null) {
133             return existing.getOriginal();
134         }
135
136         loadTargetGenerator();
137         return verifyNotNull(targetGen, "No target for %s", this).getOriginal();
138     }
139
140     abstract void loadTargetGenerator();
141
142 }