Index TypedefNamespace
[yangtools.git] / model / yang-model-spi / src / main / java / org / opendaylight / yangtools / yang / model / spi / meta / AbstractDeclaredEffectiveStatement.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.model.spi.meta;
9
10 import static com.google.common.base.Verify.verify;
11 import static java.util.Objects.requireNonNull;
12
13 import com.google.common.annotations.Beta;
14 import com.google.common.collect.ImmutableList;
15 import com.google.common.collect.ImmutableMap;
16 import java.util.Map;
17 import java.util.Optional;
18 import org.eclipse.jdt.annotation.NonNull;
19 import org.eclipse.jdt.annotation.Nullable;
20 import org.opendaylight.yangtools.yang.common.Empty;
21 import org.opendaylight.yangtools.yang.common.QName;
22 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
23 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
24 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
25 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
26 import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
27 import org.opendaylight.yangtools.yang.model.api.meta.StatementOrigin;
28 import org.opendaylight.yangtools.yang.model.api.stmt.DataTreeAwareEffectiveStatement;
29 import org.opendaylight.yangtools.yang.model.api.stmt.DataTreeEffectiveStatement;
30 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeAwareEffectiveStatement;
31 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
32 import org.opendaylight.yangtools.yang.model.api.stmt.TypedefEffectiveStatement;
33 import org.opendaylight.yangtools.yang.model.api.stmt.TypedefNamespace;
34
35 /**
36  * Base stateless superclass for statements which (logically) always have an associated {@link DeclaredStatement}. This
37  * is notably not true for all {@code case} statements, some of which may actually be implied.
38  *
39  * <p>
40  * Note implementations are not strictly required to make the declared statement available, they are free to throw
41  * {@link UnsupportedOperationException} from {@link #getDeclared()}, rendering any services relying on declared
42  * statement to be not available.
43  *
44  * @param <A> Argument type ({@link Empty} if statement does not have argument.)
45  * @param <D> Class representing declared version of this statement.
46  */
47 @Beta
48 public abstract class AbstractDeclaredEffectiveStatement<A, D extends DeclaredStatement<A>>
49         extends AbstractEffectiveStatement<A, D> {
50     @Override
51     public final StatementOrigin statementOrigin() {
52         return StatementOrigin.DECLARATION;
53     }
54
55     @Override
56     public abstract @NonNull D getDeclared();
57
58     /**
59      * Base stateless superclass form {@link SchemaTreeAwareEffectiveStatement}s. It maintains the contents of schema
60      * tree namespace based of effective substatements.
61      *
62      * @param <A> Argument type ({@link Empty} if statement does not have argument.)
63      * @param <D> Class representing declared version of this statement.
64      * @param <E> Class representing effective version of this statement.
65      */
66     public abstract static class WithSchemaTree<A, D extends DeclaredStatement<A>,
67             E extends SchemaTreeAwareEffectiveStatement<A, D>> extends AbstractDeclaredEffectiveStatement<A, D> {
68         @Override
69         @SuppressWarnings("unchecked")
70         protected <K, V, N extends IdentifierNamespace<K, V>> Optional<? extends Map<K, V>> getNamespaceContents(
71                 final Class<N> namespace) {
72             if (SchemaTreeAwareEffectiveStatement.Namespace.class.equals(namespace)) {
73                 return Optional.of((Map<K, V>) schemaTreeNamespace());
74             }
75             return super.getNamespaceContents(namespace);
76         }
77
78         /**
79          * Indexing support for {@link DataNodeContainer#dataChildByName(QName)}.
80          */
81         protected final @Nullable DataSchemaNode dataSchemaNode(final QName name) {
82             // Only DataNodeContainer subclasses should be calling this method
83             verify(this instanceof DataNodeContainer);
84             final SchemaTreeEffectiveStatement<?> child = schemaTreeNamespace().get(requireNonNull(name));
85             return child instanceof DataSchemaNode ? (DataSchemaNode) child : null;
86         }
87
88         protected abstract Map<QName, SchemaTreeEffectiveStatement<?>> schemaTreeNamespace();
89     }
90
91     /**
92      * Base stateless superclass for {@link DataTreeAwareEffectiveStatement}s. It maintains the contents of data tree
93      * namespace based of effective substatements.
94      *
95      * @param <A> Argument type ({@link Empty} if statement does not have argument.)
96      * @param <D> Class representing declared version of this statement.
97      * @param <E> Class representing effective version of this statement.
98      */
99     public abstract static class WithDataTree<A, D extends DeclaredStatement<A>,
100             E extends DataTreeAwareEffectiveStatement<A, D>> extends WithSchemaTree<A, D, E> {
101         @Override
102         @SuppressWarnings("unchecked")
103         protected <K, V, N extends IdentifierNamespace<K, V>> Optional<? extends Map<K, V>> getNamespaceContents(
104                 final Class<N> namespace) {
105             if (DataTreeAwareEffectiveStatement.Namespace.class.equals(namespace)) {
106                 return Optional.of((Map<K, V>) dataTreeNamespace());
107             }
108             return super.getNamespaceContents(namespace);
109         }
110
111         protected abstract Map<QName, DataTreeEffectiveStatement<?>> dataTreeNamespace();
112     }
113
114     /**
115      * A stateful version of {@link AbstractDeclaredEffectiveStatement}, which holds (and requires) a declared
116      * statement.
117      *
118      * @param <A> Argument type ({@link Empty} if statement does not have argument.)
119      * @param <D> Class representing declared version of this statement.
120      */
121     public abstract static class Default<A, D extends DeclaredStatement<A>>
122             extends AbstractDeclaredEffectiveStatement<A, D> {
123         private final @NonNull D declared;
124
125         protected Default(final D declared) {
126             this.declared = requireNonNull(declared);
127         }
128
129         protected Default(final Default<A, D> original) {
130             this.declared = original.declared;
131         }
132
133         @Override
134         public final @NonNull D getDeclared() {
135             return declared;
136         }
137     }
138
139     /**
140      * An extra building block on top of {@link Default}, which is wiring {@link #argument()} to the declared statement.
141      * This is mostly useful for arguments that are not subject to inference transformation -- for example Strings in
142      * {@code description}, etc. This explicitly is not true of statements which underwent namespace binding via
143      * {@code uses} or similar.
144      *
145      * @param <A> Argument type ({@link Empty} if statement does not have argument.)
146      * @param <D> Class representing declared version of this statement.
147      */
148     public abstract static class DefaultArgument<A, D extends DeclaredStatement<A>> extends Default<A, D> {
149         public abstract static class WithSubstatements<A, D extends DeclaredStatement<A>>
150                 extends DefaultArgument<A, D> {
151             private final @NonNull Object substatements;
152
153             protected WithSubstatements(final D declared,
154                     final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
155                 super(declared);
156                 this.substatements = maskList(substatements);
157             }
158
159             protected WithSubstatements(final WithSubstatements<A, D> original) {
160                 super(original);
161                 this.substatements = original.substatements;
162             }
163
164             @Override
165             public final ImmutableList<? extends EffectiveStatement<?, ?>> effectiveSubstatements() {
166                 return unmaskList(substatements);
167             }
168         }
169
170         protected DefaultArgument(final D declared) {
171             super(declared);
172         }
173
174         protected DefaultArgument(final DefaultArgument<A, D> original) {
175             super(original);
176         }
177
178         @Override
179         public final A argument() {
180             return getDeclared().argument();
181         }
182     }
183
184     /**
185      * A building block on top of {@link Default}, which adds an explicit argument value, which is not related to the
186      * context. This is mostly useful when the effective argument value reflects additional statements and similar.
187      *
188      * @param <A> Argument type ({@link Empty} if statement does not have argument.)
189      * @param <D> Class representing declared version of this statement.
190      */
191     public abstract static class DefaultWithArgument<A, D extends DeclaredStatement<A>> extends Default<A, D> {
192         public abstract static class WithSubstatements<A, D extends DeclaredStatement<A>>
193                 extends DefaultWithArgument<A, D> {
194             private final @NonNull Object substatements;
195
196             protected WithSubstatements(final D declared, final A argument,
197                     final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
198                 super(declared, argument);
199                 this.substatements = maskList(substatements);
200             }
201
202             @Override
203             public final ImmutableList<? extends EffectiveStatement<?, ?>> effectiveSubstatements() {
204                 return unmaskList(substatements);
205             }
206         }
207
208         private final A argument;
209
210         protected DefaultWithArgument(final D declared, final A argument) {
211             super(declared);
212             this.argument = argument;
213         }
214
215         @Override
216         public final A argument() {
217             return argument;
218         }
219     }
220
221     /**
222      * Stateful version of {@link WithSchemaTree}. Schema tree namespace is eagerly instantiated (and checked).
223      *
224      * @param <A> Argument type ({@link Empty} if statement does not have argument.)
225      * @param <D> Class representing declared version of this statement.
226      * @param <E> Class representing effective version of this statement.
227      */
228     public abstract static class DefaultWithSchemaTree<A, D extends DeclaredStatement<A>,
229             E extends SchemaTreeAwareEffectiveStatement<A, D>> extends WithSchemaTree<A, D, E> {
230         private final @NonNull ImmutableMap<QName, SchemaTreeEffectiveStatement<?>> schemaTree;
231         private final @NonNull Object substatements;
232         private final @NonNull D declared;
233
234         protected DefaultWithSchemaTree(final D declared,
235                 final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
236             this.declared = requireNonNull(declared);
237             this.substatements = maskList(substatements);
238             this.schemaTree = ImmutableMap.copyOf(createSchemaTreeNamespace(substatements));
239         }
240
241         protected DefaultWithSchemaTree(final DefaultWithSchemaTree<A, D, E> original) {
242             this.declared = original.declared;
243             this.schemaTree = original.schemaTree;
244             this.substatements = original.substatements;
245         }
246
247         @Override
248         public final D getDeclared() {
249             return declared;
250         }
251
252         @Override
253         public final ImmutableList<? extends EffectiveStatement<?, ?>> effectiveSubstatements() {
254             return unmaskList(substatements);
255         }
256
257         @Override
258         protected final Map<QName, SchemaTreeEffectiveStatement<?>> schemaTreeNamespace() {
259             return schemaTree;
260         }
261     }
262
263     /**
264      * Stateful version of {@link WithDataTree}. Schema tree and data tree namespaces are eagerly instantiated
265      * (and checked).
266      *
267      * @param <A> Argument type ({@link Empty} if statement does not have argument.)
268      * @param <D> Class representing declared version of this statement.
269      * @param <E> Class representing effective version of this statement.
270      */
271     public abstract static class DefaultWithDataTree<A, D extends DeclaredStatement<A>,
272             E extends DataTreeAwareEffectiveStatement<A, D>> extends WithDataTree<A, D, E> {
273         public abstract static class WithTypedefNamespace<A, D extends DeclaredStatement<A>,
274                 E extends DataTreeAwareEffectiveStatement<A, D>> extends DefaultWithDataTree<A, D, E> {
275             private final @NonNull ImmutableMap<QName, TypedefEffectiveStatement> typedefNamespace;
276
277             protected WithTypedefNamespace(final D declared,
278                 final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
279                 super(declared, substatements);
280                 this.typedefNamespace = createTypedefNamespace(substatements);
281             }
282
283             protected WithTypedefNamespace(final WithTypedefNamespace<A, D, E> original) {
284                 super(original);
285                 this.typedefNamespace = original.typedefNamespace;
286             }
287
288             @Override
289             @SuppressWarnings("unchecked")
290             protected <K, V, N extends IdentifierNamespace<K, V>> Optional<? extends Map<K, V>> getNamespaceContents(
291                     final Class<N> namespace) {
292                 if (TypedefNamespace.class.equals(namespace)) {
293                     return Optional.of((Map<K, V>) typedefNamespace);
294                 }
295                 return super.getNamespaceContents(namespace);
296             }
297         }
298
299         private final @NonNull ImmutableMap<QName, SchemaTreeEffectiveStatement<?>> schemaTree;
300         private final @NonNull ImmutableMap<QName, DataTreeEffectiveStatement<?>> dataTree;
301         private final @NonNull Object substatements;
302         private final @NonNull D declared;
303
304         protected DefaultWithDataTree(final D declared,
305                 final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
306             this.declared = requireNonNull(declared);
307             this.substatements = maskList(substatements);
308
309             // Note we call schema.values() so we do not retain them, as that is just pure memory overhead
310             final Map<QName, SchemaTreeEffectiveStatement<?>> schema = createSchemaTreeNamespace(substatements);
311             this.schemaTree = ImmutableMap.copyOf(schema);
312             this.dataTree = createDataTreeNamespace(schema.values(), schemaTree);
313         }
314
315         protected DefaultWithDataTree(final DefaultWithDataTree<A, D, E> original) {
316             this.declared = original.declared;
317             this.schemaTree = original.schemaTree;
318             this.dataTree = original.dataTree;
319             this.substatements = original.substatements;
320         }
321
322         @Override
323         public final D getDeclared() {
324             return declared;
325         }
326
327         @Override
328         public final ImmutableList<? extends EffectiveStatement<?, ?>> effectiveSubstatements() {
329             return unmaskList(substatements);
330         }
331
332         @Override
333         protected final Map<QName, SchemaTreeEffectiveStatement<?>> schemaTreeNamespace() {
334             return schemaTree;
335         }
336
337         @Override
338         protected final Map<QName, DataTreeEffectiveStatement<?>> dataTreeNamespace() {
339             return dataTree;
340         }
341     }
342 }