2 * Copyright (c) 2021 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 java.util.Objects.requireNonNull;
13 import com.google.common.base.MoreObjects.ToStringHelper;
14 import org.eclipse.jdt.annotation.NonNull;
15 import org.eclipse.jdt.annotation.Nullable;
16 import org.opendaylight.mdsal.binding.generator.impl.reactor.CollisionDomain.Member;
17 import org.opendaylight.mdsal.binding.model.api.MethodSignature.ValueMechanics;
18 import org.opendaylight.mdsal.binding.model.api.Type;
19 import org.opendaylight.mdsal.binding.model.api.TypeMemberComment;
20 import org.opendaylight.mdsal.binding.model.api.type.builder.AnnotableTypeBuilder;
21 import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilderBase;
22 import org.opendaylight.mdsal.binding.model.api.type.builder.MethodSignatureBuilder;
23 import org.opendaylight.mdsal.binding.spec.naming.BindingMapping;
24 import org.opendaylight.yangtools.yang.common.AbstractQName;
25 import org.opendaylight.yangtools.yang.common.QName;
26 import org.opendaylight.yangtools.yang.model.api.AddedByUsesAware;
27 import org.opendaylight.yangtools.yang.model.api.CopyableNode;
28 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
29 import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionEffectiveStatement;
30 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
35 * An explicit {@link Generator}, associated with a particular {@link EffectiveStatement}.
37 public abstract class AbstractExplicitGenerator<T extends EffectiveStatement<?, ?>> extends Generator
38 implements CopyableNode {
39 private static final Logger LOG = LoggerFactory.getLogger(AbstractExplicitGenerator.class);
41 private final @NonNull T statement;
43 // FIXME: this, along with AbstractTypeObjectGenerator's (and TypedefGenerator's) fields should be better-controlled
44 // with explicit sequencing guards. It it currently stands, we are expending two (or more) additional fields
45 // to express downstream linking. If we had the concept of resolution step (an enum), we could just get by
46 // with a simple queue of Step/Callback pairs, which would trigger as needed. For an example see how
47 // AbstractTypeObjectGenerator manages baseGen/inferred fields.
48 private AbstractExplicitGenerator<?> prev;
50 AbstractExplicitGenerator(final T statement) {
51 this.statement = requireNonNull(statement);
54 AbstractExplicitGenerator(final T statement, final AbstractCompositeGenerator<?> parent) {
56 this.statement = requireNonNull(statement);
60 * Return the {@link EffectiveStatement} associated with this generator.
62 * @return An EffectiveStatement
64 public final @NonNull T statement() {
69 public final boolean isAddedByUses() {
70 return statement instanceof AddedByUsesAware && ((AddedByUsesAware) statement).isAddedByUses();
74 public final boolean isAugmenting() {
75 return statement instanceof CopyableNode && ((CopyableNode) statement).isAugmenting();
78 final void linkOriginalGenerator() {
79 if (isAddedByUses() || isAugmenting()) {
80 LOG.trace("Linking {}", this);
81 prev = getParent().getOriginalChild(getQName());
82 LOG.trace("Linked {} to {}", this, prev);
86 final @Nullable AbstractExplicitGenerator<?> previous() {
90 @NonNull AbstractExplicitGenerator<?> getOriginal() {
91 return prev == null ? this : prev.getOriginal();
94 @Nullable AbstractExplicitGenerator<?> findSchemaTreeGenerator(final QName qname) {
95 for (Generator child : this) {
96 if (child instanceof AbstractExplicitGenerator) {
97 final AbstractExplicitGenerator<?> gen = (AbstractExplicitGenerator<?>) child;
98 final EffectiveStatement<?, ?> stmt = gen.statement();
99 if (stmt instanceof SchemaTreeEffectiveStatement && qname.equals(stmt.argument())) {
107 final @NonNull QName getQName() {
108 final Object arg = statement.argument();
109 verify(arg instanceof QName, "Unexpected argument %s", arg);
113 @NonNull AbstractQName localName() {
114 // FIXME: this should be done in a nicer way
115 final Object argument = statement.argument();
116 verify(argument instanceof AbstractQName, "Illegal argument %s", argument);
117 return (AbstractQName) argument;
121 ClassPlacement classPlacement() {
122 // We process nodes introduced through augment or uses separately
123 // FIXME: this is not quite right!
124 return isAddedByUses() || isAugmenting() ? ClassPlacement.NONE : ClassPlacement.TOP_LEVEL;
128 Member createMember(final CollisionDomain domain) {
129 return domain.addPrimary(this, new CamelCaseNamingStrategy(namespace(), localName()));
132 void addAsGetterMethod(final @NonNull GeneratedTypeBuilderBase<?> builder,
133 final @NonNull TypeBuilderFactory builderFactory) {
134 if (isAugmenting()) {
135 // Do not process augmented nodes: they will be taken care of in their home augmentation
138 if (isAddedByUses()) {
139 // If this generator has been added by a uses node, it is already taken care of by the corresponding
140 // grouping. There is one exception to this rule: 'type leafref' can use a relative path to point
141 // outside of its home grouping. In this case we need to examine the instantiation until we succeed in
142 // resolving the reference.
143 addAsGetterMethodOverride(builder, builderFactory);
147 final Type returnType = methodReturnType(builderFactory);
148 constructGetter(builder, returnType);
149 constructRequire(builder, returnType);
152 MethodSignatureBuilder constructGetter(final GeneratedTypeBuilderBase<?> builder, final Type returnType) {
153 return constructGetter(builder, returnType, BindingMapping.getGetterMethodName(localName().getLocalName()));
156 final MethodSignatureBuilder constructGetter(final GeneratedTypeBuilderBase<?> builder,
157 final Type returnType, final String methodName) {
158 final MethodSignatureBuilder getMethod = builder.addMethod(methodName).setReturnType(returnType);
160 annotateDeprecatedIfNecessary(getMethod);
162 statement.findFirstEffectiveSubstatementArgument(DescriptionEffectiveStatement.class)
163 .map(TypeMemberComment::referenceOf).ifPresent(getMethod::setComment);
168 void constructRequire(final GeneratedTypeBuilderBase<?> builder, final Type returnType) {
169 // No-op in most cases
172 final void constructRequireImpl(final GeneratedTypeBuilderBase<?> builder, final Type returnType) {
173 constructGetter(builder, returnType, BindingMapping.getRequireMethodName(localName().getLocalName()))
175 .setMechanics(ValueMechanics.NONNULL);
178 void addAsGetterMethodOverride(final @NonNull GeneratedTypeBuilderBase<?> builder,
179 final @NonNull TypeBuilderFactory builderFactory) {
180 // No-op for most cases
183 @NonNull Type methodReturnType(final @NonNull TypeBuilderFactory builderFactory) {
184 return getGeneratedType(builderFactory);
187 final void annotateDeprecatedIfNecessary(final AnnotableTypeBuilder builder) {
188 annotateDeprecatedIfNecessary(statement, builder);
192 ToStringHelper addToStringAttributes(final ToStringHelper helper) {
193 helper.add("argument", statement.argument());
195 if (isAddedByUses()) {
196 helper.addValue("addedByUses");
198 if (isAugmenting()) {
199 helper.addValue("augmenting");