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