8703cbddf8aadd6d5260bfe8fb956a86458d2a14
[yangtools.git] / parser / rfc8040-parser-support / src / main / java / org / opendaylight / yangtools / rfc8040 / parser / OperationsCreateLeafStatements.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.yangtools.rfc8040.parser;
9
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;
13
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.Comparator;
17 import java.util.List;
18 import java.util.stream.Collectors;
19 import org.opendaylight.yangtools.yang.common.QName;
20 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
21 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
22 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
23 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
24 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
25 import org.opendaylight.yangtools.yang.model.api.stmt.LeafEffectiveStatement;
26 import org.opendaylight.yangtools.yang.model.api.stmt.RpcStatement;
27 import org.opendaylight.yangtools.yang.model.api.stmt.TypeEffectiveStatement;
28 import org.opendaylight.yangtools.yang.model.api.type.TypeDefinitions;
29 import org.opendaylight.yangtools.yang.parser.spi.ModuleNamespace;
30 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder.InferenceAction;
31 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder.InferenceContext;
32 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder.Prerequisite;
33 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
34 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport;
35 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupportNamespace;
36 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
37 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
38
39 /**
40  * Once we have identified the {@code operations} container we want to enrich, we need to identify all RPC statements
41  * in the reactor. For that we need that all sources complete {@link ModelProcessingPhase#FULL_DECLARATION} -- after
42  * which we are still not done, as not all those RPCs may make it to the resulting {@link EffectiveModelContext}.
43  */
44 final class OperationsCreateLeafStatements implements InferenceAction {
45     private final List<Prerequisite<? extends StmtContext<?, ?, ?>>> prereqs;
46     private final Mutable<?, ?, ?> operations;
47
48     private OperationsCreateLeafStatements(final Mutable<?, ?, ?> operations,
49             final List<Prerequisite<? extends StmtContext<?, ?, ?>>> prereqs) {
50         this.operations = requireNonNull(operations);
51         this.prereqs = requireNonNull(prereqs);
52     }
53
54     static void applyTo(final StmtContext<?, ?, ?> ietfRestconfModule, final Mutable<?, ?, ?> operations) {
55         final var action = operations.newInferenceAction(ModelProcessingPhase.EFFECTIVE_MODEL);
56         action.mutatesEffectiveCtx(operations);
57
58         final var prereqs = new ArrayList<Prerequisite<? extends StmtContext<?, ?, ?>>>();
59         // FIXME: this not accurate: we need all sources, not just modules
60         for (var module : ietfRestconfModule.getAllFromNamespace(ModuleNamespace.class).values()) {
61             if (!ietfRestconfModule.equals(module)) {
62                 prereqs.add(action.requiresCtx((StmtContext<?, ?, ?>)module, ModelProcessingPhase.EFFECTIVE_MODEL));
63             }
64         }
65
66         action.apply(new OperationsCreateLeafStatements(operations, prereqs));
67     }
68
69     @Override
70     public void apply(final InferenceContext ctx) {
71         // Enumerate all RPCs that can be built
72         final var qnames = prereqs.stream()
73             .flatMap(prereq -> prereq.resolve(ctx).declaredSubstatements().stream())
74             .filter(stmt -> stmt.producesDeclared(RpcStatement.class)
75                 && stmt.isSupportedToBuildEffective() && stmt.isSupportedByFeatures())
76             .map(stmt -> (QName) stmt.argument())
77             // predictable order...
78             .sorted(Comparator.naturalOrder())
79             // each QName should be distinct, but let's make sure anyway
80             .distinct()
81             .collect(Collectors.toUnmodifiableList());
82
83         if (!qnames.isEmpty()) {
84             final var leafSupport = getSupport(YangStmtMapping.LEAF, LeafEffectiveStatement.class);
85             final var typeSupport = getSupport(YangStmtMapping.TYPE, TypeEffectiveStatement.class);
86
87             for (var qname : qnames) {
88                 final var leaf = operations.createUndeclaredSubstatement(leafSupport, qname);
89                 leaf.addEffectiveSubstatement(leaf.createUndeclaredSubstatement(typeSupport, TypeDefinitions.EMPTY));
90                 operations.addEffectiveSubstatement(leaf);
91             }
92         }
93     }
94
95     @Override
96     public void prerequisiteFailed(final Collection<? extends Prerequisite<?>> failed) {
97         // We do not really need to fail, as this means reactor will fail anyway
98     }
99
100     private <X, Y extends DeclaredStatement<X>, Z extends EffectiveStatement<X, Y>>
101             StatementSupport<X, Y, Z> getSupport(final StatementDefinition def, final Class<Z> effectiveClass) {
102         final var tmp = verifyNotNull(operations.getFromNamespace(StatementSupportNamespace.class,
103             def.getStatementName()));
104         final var repr = tmp.getEffectiveRepresentationClass();
105         verify(effectiveClass.equals(repr), "Unexpected support %s representation %s", tmp, repr);
106
107         @SuppressWarnings("unchecked")
108         final var ret = (StatementSupport<X, Y, Z>) tmp;
109         return ret;
110     }
111 }