2 * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others. All rights reserved.
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
8 package org.opendaylight.yangtools.yang.parser.rfc7950.stmt;
10 import com.google.common.annotations.Beta;
11 import com.google.common.collect.Collections2;
12 import java.util.Collection;
13 import java.util.Optional;
14 import org.eclipse.jdt.annotation.NonNullByDefault;
15 import org.opendaylight.yangtools.concepts.Mutable;
16 import org.opendaylight.yangtools.yang.common.QName;
17 import org.opendaylight.yangtools.yang.model.api.ActionDefinition;
18 import org.opendaylight.yangtools.yang.model.api.ActionNodeContainer;
19 import org.opendaylight.yangtools.yang.model.api.AddedByUsesAware;
20 import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
21 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
22 import org.opendaylight.yangtools.yang.model.api.CopyableNode;
23 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
24 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
25 import org.opendaylight.yangtools.yang.model.api.DocumentedNode;
26 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
27 import org.opendaylight.yangtools.yang.model.api.MandatoryAware;
28 import org.opendaylight.yangtools.yang.model.api.MustConstraintAware;
29 import org.opendaylight.yangtools.yang.model.api.MustDefinition;
30 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
31 import org.opendaylight.yangtools.yang.model.api.NotificationNodeContainer;
32 import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
33 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
34 import org.opendaylight.yangtools.yang.model.api.Status;
35 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
36 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
37 import org.opendaylight.yangtools.yang.model.api.UsesNode;
38 import org.opendaylight.yangtools.yang.model.api.WhenConditionAware;
39 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
40 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
41 import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionEffectiveStatement;
42 import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceEffectiveStatement;
43 import org.opendaylight.yangtools.yang.model.api.stmt.TypedefEffectiveStatement;
44 import org.opendaylight.yangtools.yang.model.api.stmt.WhenEffectiveStatement;
45 import org.opendaylight.yangtools.yang.parser.spi.meta.CopyHistory;
46 import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
49 * Mix-in interfaces providing services required by SchemaNode et al. These interfaces provide implementations, or
50 * implementation helpers based on default methods, so the correct behavior can be logically centralized.
53 public final class EffectiveStatementMixins {
54 // Marker interface requiring all mixins to be derived from EffectiveStatement.
55 private interface Mixin<A, D extends DeclaredStatement<A>> extends EffectiveStatement<A, D> {
56 @SuppressWarnings("unchecked")
57 default <T> Collection<? extends T> filterEffectiveStatements(final Class<T> type) {
58 // Yeah, this is not nice, but saves one transformation
59 return (Collection<? extends T>) Collections2.filter(effectiveSubstatements(), type::isInstance);
64 * Bridge between {@link EffectiveStatement} and {@link AugmentationTarget}.
66 * @param <A> Argument type ({@link Void} if statement does not have argument.)
67 * @param <D> Class representing declared version of this statement.
69 public interface AugmentationTargetMixin<A, D extends DeclaredStatement<A>>
70 extends Mixin<A, D>, AugmentationTarget {
72 default Collection<? extends AugmentationSchemaNode> getAvailableAugmentations() {
73 return filterEffectiveStatements(AugmentationSchemaNode.class);
78 * Bridge between {@link EffectiveStatementWithFlags} and {@link AddedByUsesAware}.
80 * @param <A> Argument type ({@link Void} if statement does not have argument.)
81 * @param <D> Class representing declared version of this statement.
83 public interface AddedByUsesMixin<A, D extends DeclaredStatement<A>>
84 extends EffectiveStatementWithFlags<A, D>, AddedByUsesAware {
86 default boolean isAddedByUses() {
87 return (flags() & FlagsBuilder.ADDED_BY_USES) != 0;
92 * Bridge between {@link EffectiveStatementWithFlags} and {@link ActionNodeContainer}.
94 * @param <A> Argument type ({@link Void} if statement does not have argument.)
95 * @param <D> Class representing declared version of this statement.
97 public interface ActionNodeContainerMixin<A, D extends DeclaredStatement<A>>
98 extends Mixin<A, D>, ActionNodeContainer {
100 default Collection<? extends ActionDefinition> getActions() {
101 return filterEffectiveStatements(ActionDefinition.class);
106 * Bridge between {@link EffectiveStatementWithFlags} and {@link NotificationNodeContainer}.
108 * @param <A> Argument type ({@link Void} if statement does not have argument.)
109 * @param <D> Class representing declared version of this statement.
111 public interface NotificationNodeContainerMixin<A, D extends DeclaredStatement<A>>
112 extends Mixin<A, D>, NotificationNodeContainer {
114 default Collection<? extends NotificationDefinition> getNotifications() {
115 return filterEffectiveStatements(NotificationDefinition.class);
120 * Bridge between {@link EffectiveStatementWithFlags} and {@link MustConstraintAware}.
122 * @param <A> Argument type ({@link Void} if statement does not have argument.)
123 * @param <D> Class representing declared version of this statement.
125 public interface MustConstraintMixin<A, D extends DeclaredStatement<A>> extends Mixin<A, D>, MustConstraintAware {
127 default Collection<? extends MustDefinition> getMustConstraints() {
128 return filterEffectiveStatements(MustDefinition.class);
133 * Bridge between {@link EffectiveStatementWithFlags} and {@link CopyableNode}.
135 * @param <A> Argument type ({@link Void} if statement does not have argument.)
136 * @param <D> Class representing declared version of this statement.
138 public interface CopyableMixin<A, D extends DeclaredStatement<A>> extends AddedByUsesMixin<A, D>, CopyableNode {
140 default boolean isAugmenting() {
141 return (flags() & FlagsBuilder.AUGMENTING) != 0;
146 * Bridge between {@link EffectiveStatementWithFlags} and {@link DataNodeContainer}.
148 * @param <A> Argument type ({@link Void} if statement does not have argument.)
149 * @param <D> Class representing declared version of this statement.
151 public interface DataNodeContainerMixin<A, D extends DeclaredStatement<A>> extends DataNodeContainer, Mixin<A, D> {
153 default Collection<? extends TypeDefinition<?>> getTypeDefinitions() {
154 // TODO: the cast here is needed to work around Java 11 javac type inference issue
155 return Collections2.transform(filterEffectiveStatements(TypedefEffectiveStatement.class),
156 TypedefEffectiveStatement::getTypeDefinition);
160 default Collection<? extends DataSchemaNode> getChildNodes() {
161 return filterEffectiveStatements(DataSchemaNode.class);
165 default Collection<? extends GroupingDefinition> getGroupings() {
166 return filterEffectiveStatements(GroupingDefinition.class);
170 default Collection<? extends UsesNode> getUses() {
171 return filterEffectiveStatements(UsesNode.class);
176 * Bridge between {@link EffectiveStatementWithFlags} and {@link DataSchemaNode}.
178 * @param <A> Argument type ({@link Void} if statement does not have argument.)
179 * @param <D> Class representing declared version of this statement.
181 public interface DataSchemaNodeMixin<A, D extends DeclaredStatement<A>>
182 extends DataSchemaNode, CopyableMixin<A, D>, SchemaNodeMixin<A, D>, WhenConditionMixin<A, D> {
184 default boolean isConfiguration() {
185 return (flags() & FlagsBuilder.CONFIGURATION) != 0;
190 * Bridge between {@link EffectiveStatementWithFlags} and {@link DocumentedNode}.
192 * @param <A> Argument type ({@link Void} if statement does not have argument.)
193 * @param <D> Class representing declared version of this statement.
195 public interface DocumentedNodeMixin<A, D extends DeclaredStatement<A>> extends Mixin<A, D>, DocumentedNode {
197 * Bridge between {@link EffectiveStatementWithFlags} and
198 * {@link org.opendaylight.yangtools.yang.model.api.DocumentedNode.WithStatus}.
200 * @param <A> Argument type ({@link Void} if statement does not have argument.)
201 * @param <D> Class representing declared version of this statement.
203 interface WithStatus<A, D extends DeclaredStatement<A>>
204 extends EffectiveStatementWithFlags<A, D>, DocumentedNodeMixin<A, D>, DocumentedNode.WithStatus {
206 default Status getStatus() {
207 final int status = flags() & FlagsBuilder.MASK_STATUS;
209 case FlagsBuilder.STATUS_CURRENT:
210 return Status.CURRENT;
211 case FlagsBuilder.STATUS_DEPRECATED:
212 return Status.DEPRECATED;
213 case FlagsBuilder.STATUS_OBSOLETE:
214 return Status.OBSOLETE;
216 throw new IllegalStateException("Illegal status " + status);
222 default Optional<String> getDescription() {
223 return findFirstEffectiveSubstatementArgument(DescriptionEffectiveStatement.class);
227 default Optional<String> getReference() {
228 return findFirstEffectiveSubstatementArgument(ReferenceEffectiveStatement.class);
232 default Collection<? extends UnknownSchemaNode> getUnknownSchemaNodes() {
233 return filterEffectiveStatements(UnknownSchemaNode.class);
238 * Bridge between {@link EffectiveStatementWithFlags} and {@link MandatoryAware}.
240 * @param <A> Argument type ({@link Void} if statement does not have argument.)
241 * @param <D> Class representing declared version of this statement.
243 public interface MandatoryMixin<A, D extends DeclaredStatement<A>>
244 extends EffectiveStatementWithFlags<A, D>, MandatoryAware {
246 default boolean isMandatory() {
247 return (flags() & FlagsBuilder.MANDATORY) != 0;
252 * Bridge between {@link EffectiveStatementWithFlags} and {@code presence} statement.
254 * @param <A> Argument type ({@link Void} if statement does not have argument.)
255 * @param <D> Class representing declared version of this statement.
257 public interface PresenceMixin<A, D extends DeclaredStatement<A>> extends EffectiveStatementWithFlags<A, D> {
258 default boolean presence() {
259 return (flags() & FlagsBuilder.PRESENCE) != 0;
264 * Bridge between {@link EffectiveStatementWithFlags} and {@link SchemaNode}.
266 * @param <A> Argument type ({@link Void} if statement does not have argument.)
267 * @param <D> Class representing declared version of this statement.
269 public interface SchemaNodeMixin<A, D extends DeclaredStatement<A>>
270 extends DocumentedNodeMixin.WithStatus<A, D>, SchemaNode {
272 default QName getQName() {
273 return getPath().getLastComponent();
278 * Bridge between {@link EffectiveStatementWithFlags} and {@code ordered-by} statement.
280 * @param <A> Argument type ({@link Void} if statement does not have argument.)
281 * @param <D> Class representing declared version of this statement.
283 public interface UserOrderedMixin<A, D extends DeclaredStatement<A>> extends EffectiveStatementWithFlags<A, D> {
284 default boolean userOrdered() {
285 return (flags() & FlagsBuilder.USER_ORDERED) != 0;
290 * Helper used to locate the effective {@code when} statement and exposing its argument as per
291 * {@link WhenConditionAware}.
293 * @param <A> Argument type ({@link Void} if statement does not have argument.)
294 * @param <D> Class representing declared version of this statement.
296 public interface WhenConditionMixin<A, D extends DeclaredStatement<A>> extends Mixin<A, D>, WhenConditionAware {
298 default Optional<RevisionAwareXPath> getWhenCondition() {
299 return findFirstEffectiveSubstatementArgument(WhenEffectiveStatement.class);
304 * Support interface for various mixins. Implementations are required to store 32bits worth of flags, which are
305 * globally assigned to sub-interfaces -- thus providing storage for many low-cardinality properties.
307 * @param <A> Argument type ({@link Void} if statement does not have argument.)
308 * @param <D> Class representing declared version of this statement.
310 public interface EffectiveStatementWithFlags<A, D extends DeclaredStatement<A>> extends Mixin<A, D> {
312 * Return flags assicated with this statements. Flags can be built using {@link FlagsBuilder}.
314 * @return Flag field value (32 bits).
319 final class FlagsBuilder implements Mutable {
320 // We still have 24 flags remaining
321 static final int STATUS_CURRENT = 0x0001;
322 static final int STATUS_DEPRECATED = 0x0002;
323 static final int STATUS_OBSOLETE = 0x0003;
324 static final int MASK_STATUS = 0x0003;
326 static final int CONFIGURATION = 0x0004;
327 static final int MANDATORY = 0x0008;
329 static final int AUGMENTING = 0x0010;
330 static final int ADDED_BY_USES = 0x0020;
331 private static final int MASK_HISTORY = 0x0030;
333 static final int USER_ORDERED = 0x0040;
334 static final int PRESENCE = 0x0080;
338 public FlagsBuilder setConfiguration(final boolean config) {
340 flags |= CONFIGURATION;
342 flags &= ~CONFIGURATION;
347 public FlagsBuilder setHistory(final CopyHistory history) {
349 if (history.contains(CopyType.ADDED_BY_USES_AUGMENTATION)) {
350 bits = AUGMENTING | ADDED_BY_USES;
353 if (history.contains(CopyType.ADDED_BY_AUGMENTATION)) {
356 if (history.contains(CopyType.ADDED_BY_USES)) {
357 bits |= ADDED_BY_USES;
361 flags = flags & ~MASK_HISTORY | bits;
365 public FlagsBuilder setMandatory(final boolean mandatory) {
374 public FlagsBuilder setPresence(final boolean presence) {
383 public FlagsBuilder setStatus(final Status status) {
387 bits = STATUS_CURRENT;
390 bits = STATUS_DEPRECATED;
393 bits = STATUS_DEPRECATED;
396 throw new IllegalStateException("Unhandled status " + status);
399 flags = flags & ~MASK_STATUS | bits;
403 public FlagsBuilder setUserOrdered(final boolean userOrdered) {
405 flags |= USER_ORDERED;
407 flags &= ~USER_ORDERED;
412 public int toFlags() {