Revert "Do not call setFullyDefined() in ReplicateStatementContext"
[yangtools.git] / yang / yang-parser-rfc7950 / src / main / java / org / opendaylight / yangtools / yang / parser / rfc7950 / stmt / BaseSchemaTreeStatementSupport.java
1 /*
2  * Copyright (c) 2020 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.yang.parser.rfc7950.stmt;
9
10 import java.util.Collection;
11 import java.util.Objects;
12 import org.opendaylight.yangtools.yang.common.QName;
13 import org.opendaylight.yangtools.yang.model.api.CopyableNode;
14 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
15 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
16 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
17 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
18 import org.opendaylight.yangtools.yang.parser.spi.SchemaTreeNamespace;
19 import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractQNameStatementSupport;
20 import org.opendaylight.yangtools.yang.parser.spi.meta.CopyHistory;
21 import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
22 import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current;
23 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
24 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
25 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
26
27 /**
28  * Specialization of {@link AbstractQNameStatementSupport} for {@link SchemaTreeEffectiveStatement} implementations.
29  * Every statement automatically participates in {@link SchemaTreeNamespace}.
30  *
31  * @param <D> Declared Statement representation
32  * @param <E> Effective Statement representation
33  */
34 public abstract class BaseSchemaTreeStatementSupport<D extends DeclaredStatement<QName>,
35         E extends SchemaTreeEffectiveStatement<D>> extends AbstractQNameStatementSupport<D, E> {
36     private static class SchemaTreeEquality<D extends DeclaredStatement<QName>>
37             implements StatementEquality<QName, D> {
38         private static final class Instantiated<D extends DeclaredStatement<QName>> extends SchemaTreeEquality<D> {
39             @Override
40             public boolean canReuseCurrent(final Current<QName, D> copy, final Current<QName, D> current,
41                     final Collection<? extends EffectiveStatement<?, ?>> substatements) {
42                 return copy.effectiveConfig() == current.effectiveConfig()
43                     && super.canReuseCurrent(copy, current, substatements)
44                     // This weird quirk is needed for ... something somewhere
45                     && Objects.equals(copy.original(), current.original());
46             }
47         }
48
49         @Override
50         public boolean canReuseCurrent(final Current<QName, D> copy, final Current<QName, D> current,
51                 final Collection<? extends EffectiveStatement<?, ?>> substatements) {
52             return equalHistory(copy, current)
53                 // FIXME: this should devolve to getArgument() equality
54                 && copy.getSchemaPath().equals(current.getSchemaPath());
55         }
56
57         // TODO: can we speed this up?
58         private static boolean equalHistory(final Current<?, ?> copy, final Current<?, ?> current) {
59             return isAugmenting(copy) == isAugmenting(current)
60                 && isAddedByUses(copy) == isAddedByUses(current);
61         }
62
63         private static boolean isAugmenting(final Current<?, ?> stmt) {
64             final CopyHistory history = stmt.history();
65             return history.contains(CopyType.ADDED_BY_AUGMENTATION)
66                 || history.contains(CopyType.ADDED_BY_USES_AUGMENTATION);
67         }
68
69         private static boolean isAddedByUses(final Current<?, ?> stmt) {
70             final CopyHistory history = stmt.history();
71             return history.contains(CopyType.ADDED_BY_USES)
72                 || history.contains(CopyType.ADDED_BY_USES_AUGMENTATION);
73         }
74     }
75
76     private static final StatementPolicy<QName, ?> INSTANTIATED_POLICY =
77         StatementPolicy.copyDeclared(new SchemaTreeEquality.Instantiated<>());
78     private static final StatementPolicy<QName, ?> UNINSTANTIATED_POLICY =
79         StatementPolicy.copyDeclared(new SchemaTreeEquality<>());
80
81     protected BaseSchemaTreeStatementSupport(final StatementDefinition publicDefinition,
82             final StatementPolicy<QName, D> policy) {
83         super(publicDefinition, policy);
84     }
85
86     /**
87      * Return the {@link StatementPolicy} corresponding to a potentially-instantiated YANG statement. Statements are
88      * reused as long as:
89      * <ul>
90      *   <li>{@link Current#schemaPath()} does not change</li>
91      *   <li>{@link Current#argument()} does not change</li>
92      *   <li>{@link Current#history()} does not change as far as {@link CopyableNode} is concerned</li>
93      *   <li>{@link Current#effectiveConfig()} does not change</li>
94      *   <li>{@link Current#original()} does not change</li>
95      * </ul>
96      *
97      * <p>
98      * Typical users include {@code container} and {@code leaf}.
99      *
100      * @param <D> Declared Statement representation
101      * @return A StatementPolicy
102      */
103     @SuppressWarnings("unchecked")
104     public static final <D extends DeclaredStatement<QName>> StatementPolicy<QName, D> instantiatedPolicy() {
105         return (StatementPolicy<QName, D>) INSTANTIATED_POLICY;
106     }
107
108     /**
109      * Return the {@link StatementPolicy} corresponding to an uninstantiated YANG statement. Statements are
110      * reused as long as:
111      * <ul>
112      *   <li>{@link Current#schemaPath()} does not change</li>
113      *   <li>{@link Current#argument()} does not change</li>
114      *   <li>{@link Current#history()} does not change as far as {@link CopyableNode} is concerned</li>
115      * </ul>
116      *
117      * <p>
118      * Typical users include {@code action} and {@code notification} (in its YANG 1.1 form).
119      *
120      * @param <D> Declared Statement representation
121      * @return A StatementPolicy
122      */
123     @SuppressWarnings("unchecked")
124     public static final <D extends DeclaredStatement<QName>> StatementPolicy<QName, D> uninstantiatedPolicy() {
125         return (StatementPolicy<QName, D>) UNINSTANTIATED_POLICY;
126     }
127
128     /**
129      * {@inheritDoc}
130      *
131      * <p>
132      * This method ensures the statement is added to its parent {@link SchemaTreeNamespace}.
133      */
134     @Override
135     public void onStatementAdded(final Mutable<QName, D, E> stmt) {
136         stmt.coerceParentContext().addToNs(SchemaTreeNamespace.class, stmt.getArgument(), stmt);
137     }
138
139     // Non-final because {@code input} and {@code output} are doing their own thing.
140     @Override
141     public QName parseArgumentValue(final StmtContext<?, ?, ?> ctx, final String value) {
142         return StmtContextUtils.parseIdentifier(ctx, value);
143     }
144 }