Retain grouping/uses instantiation vectors
[mdsal.git] / binding / mdsal-binding-generator / src / main / java / org / opendaylight / mdsal / binding / generator / impl / reactor / GroupingGenerator.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 com.google.common.base.VerifyException;
11 import java.util.ArrayList;
12 import java.util.List;
13 import java.util.stream.Collectors;
14 import org.opendaylight.mdsal.binding.generator.impl.rt.DefaultGroupingRuntimeType;
15 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
16 import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilderBase;
17 import org.opendaylight.mdsal.binding.model.ri.BindingTypes;
18 import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
19 import org.opendaylight.mdsal.binding.runtime.api.GroupingRuntimeType;
20 import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
21 import org.opendaylight.yangtools.yang.binding.contract.StatementNamespace;
22 import org.opendaylight.yangtools.yang.model.api.stmt.GroupingEffectiveStatement;
23 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
24
25 /**
26  * Generator corresponding to a {@code grouping} statement.
27  */
28 final class GroupingGenerator extends AbstractCompositeGenerator<GroupingEffectiveStatement, GroupingRuntimeType> {
29     // Linkage towards concrete data tree instantiations of this grouping. This can contain two different kinds of
30     // generators:
31     // - GroupingGenerators which provide next step in the linkage
32     // - other composite generators, which are the actual instantiations
33     private List<AbstractCompositeGenerator<?, ?>> users;
34
35     GroupingGenerator(final GroupingEffectiveStatement statement, final AbstractCompositeGenerator<?, ?> parent) {
36         super(statement, parent);
37     }
38
39     void addUser(final AbstractCompositeGenerator<?, ?> user) {
40         if (users == null) {
41             // We are adding the first user: allocate a small set and notify the groupings we use that we are a user
42             users = new ArrayList<>();
43             for (var grouping : groupings()) {
44                 grouping.addUser(this);
45             }
46         }
47         users.add(user);
48     }
49
50     boolean hasUser() {
51         return users != null;
52     }
53
54     void freezeUsers() {
55         users = users == null ? List.of() : users.stream().distinct().collect(Collectors.toUnmodifiableList());
56     }
57
58     @Override
59     StatementNamespace namespace() {
60         return StatementNamespace.GROUPING;
61     }
62
63     @Override
64     void pushToInference(final SchemaInferenceStack dataTree) {
65         dataTree.enterGrouping(statement().argument());
66     }
67
68     @Override
69     GeneratedType createTypeImpl(final TypeBuilderFactory builderFactory) {
70         final var builder = builderFactory.newGeneratedTypeBuilder(typeName());
71         builder.addImplementsType(BindingTypes.DATA_OBJECT);
72         narrowImplementedInterface(builder);
73         addUsesInterfaces(builder, builderFactory);
74         addGetterMethods(builder, builderFactory);
75
76         final var module = currentModule();
77         module.addQNameConstant(builder, statement().argument());
78
79         annotateDeprecatedIfNecessary(builder);
80         builderFactory.addCodegenInformation(module, statement(), builder);
81
82         return builder.build();
83     }
84
85     @Override
86     void addAsGetterMethod(final GeneratedTypeBuilderBase<?> builder, final TypeBuilderFactory builderFactory) {
87         // groupings are a separate concept
88     }
89
90     @Override
91     CompositeRuntimeTypeBuilder<GroupingEffectiveStatement, GroupingRuntimeType> createBuilder(
92             final GroupingEffectiveStatement statement) {
93         final var local = users;
94         if (local == null) {
95             throw new VerifyException(this + " has unresolved users");
96         }
97
98         final var vectors = local.stream()
99             .map(AbstractCompositeGenerator::getRuntimeType)
100             .distinct()
101             .collect(Collectors.toUnmodifiableList());
102
103         return new CompositeRuntimeTypeBuilder<>(statement) {
104             @Override
105             GroupingRuntimeType build(final GeneratedType type, final GroupingEffectiveStatement statement,
106                     final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
107                 // Groupings cannot be targeted by 'augment'
108                 if (augments.isEmpty()) {
109                     return new DefaultGroupingRuntimeType(type, statement, children, vectors);
110                 }
111                 throw new VerifyException("Unexpected augments " + augments);
112             }
113         };
114     }
115 }