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 com.google.common.collect.ImmutableList;
13 import java.util.Collection;
14 import java.util.List;
15 import java.util.Optional;
16 import org.eclipse.jdt.annotation.NonNullByDefault;
17 import org.opendaylight.yangtools.concepts.Mutable;
18 import org.opendaylight.yangtools.yang.common.QName;
19 import org.opendaylight.yangtools.yang.model.api.AddedByUsesAware;
20 import org.opendaylight.yangtools.yang.model.api.CopyableNode;
21 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
22 import org.opendaylight.yangtools.yang.model.api.DocumentedNode;
23 import org.opendaylight.yangtools.yang.model.api.MandatoryAware;
24 import org.opendaylight.yangtools.yang.model.api.MustConstraintAware;
25 import org.opendaylight.yangtools.yang.model.api.MustDefinition;
26 import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
27 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
28 import org.opendaylight.yangtools.yang.model.api.Status;
29 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
30 import org.opendaylight.yangtools.yang.model.api.WhenConditionAware;
31 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
32 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
33 import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionEffectiveStatement;
34 import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceEffectiveStatement;
35 import org.opendaylight.yangtools.yang.model.api.stmt.WhenEffectiveStatement;
36 import org.opendaylight.yangtools.yang.parser.spi.meta.CopyHistory;
37 import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
40 * Mix-in interfaces providing services required by SchemaNode et al. These interfaces provide implementations, or
41 * implementation helpers based on default methods, so the correct behavior can be logically centralized.
44 public final class EffectiveStatementMixins {
45 // Marker interface requiring all mixins to be derived from EffectiveStatement.
46 private interface Mixin<A, D extends DeclaredStatement<A>> extends EffectiveStatement<A, D> {
47 @SuppressWarnings("unchecked")
48 default <T> Collection<T> filterEffectiveStatements(final Class<T> type) {
49 // Yeah, this is not nice, but saves one transformation
50 return (Collection<T>) Collections2.filter(effectiveSubstatements(), type::isInstance);
53 default <T> List<T> filterEffectiveStatementsList(final Class<T> type) {
54 return effectiveSubstatements().stream().filter(type::isInstance).map(type::cast)
55 .collect(ImmutableList.toImmutableList());
60 * Bridge between {@link EffectiveStatementWithFlags} and {@link AddedByUsesAware}.
62 * @param <A> Argument type ({@link Void} if statement does not have argument.)
63 * @param <D> Class representing declared version of this statement.
65 public interface AddedByUsesMixin<A, D extends DeclaredStatement<A>>
66 extends EffectiveStatementWithFlags<A, D>, AddedByUsesAware {
68 default boolean isAddedByUses() {
69 return (flags() & FlagsBuilder.ADDED_BY_USES) != 0;
74 * Bridge between {@link EffectiveStatementWithFlags} and {@link MustConstraintAware}.
76 * @param <A> Argument type ({@link Void} if statement does not have argument.)
77 * @param <D> Class representing declared version of this statement.
79 public interface MustConstraintMixin<A, D extends DeclaredStatement<A>> extends Mixin<A, D>, MustConstraintAware {
81 default Collection<MustDefinition> getMustConstraints() {
82 return filterEffectiveStatements(MustDefinition.class);
87 * Bridge between {@link EffectiveStatementWithFlags} and {@link CopyableNode}.
89 * @param <A> Argument type ({@link Void} if statement does not have argument.)
90 * @param <D> Class representing declared version of this statement.
92 public interface CopyableMixin<A, D extends DeclaredStatement<A>> extends AddedByUsesMixin<A, D>, CopyableNode {
94 default boolean isAugmenting() {
95 return (flags() & FlagsBuilder.AUGMENTING) != 0;
100 * Bridge between {@link EffectiveStatementWithFlags} and {@link DataSchemaNode}.
102 * @param <A> Argument type ({@link Void} if statement does not have argument.)
103 * @param <D> Class representing declared version of this statement.
105 public interface DataSchemaNodeMixin<A, D extends DeclaredStatement<A>>
106 extends DataSchemaNode, CopyableMixin<A, D>, SchemaNodeMixin<A, D>, WhenConditionMixin<A, D> {
108 default boolean isConfiguration() {
109 return (flags() & FlagsBuilder.CONFIGURATION) != 0;
114 * Bridge between {@link EffectiveStatementWithFlags} and {@link DocumentedNode}.
116 * @param <A> Argument type ({@link Void} if statement does not have argument.)
117 * @param <D> Class representing declared version of this statement.
119 public interface DocumentedNodeMixin<A, D extends DeclaredStatement<A>> extends Mixin<A, D>, DocumentedNode {
121 * Bridge between {@link EffectiveStatementWithFlags} and
122 * {@link org.opendaylight.yangtools.yang.model.api.DocumentedNode.WithStatus}.
124 * @param <A> Argument type ({@link Void} if statement does not have argument.)
125 * @param <D> Class representing declared version of this statement.
127 interface WithStatus<A, D extends DeclaredStatement<A>>
128 extends EffectiveStatementWithFlags<A, D>, DocumentedNodeMixin<A, D>, DocumentedNode.WithStatus {
130 default Status getStatus() {
131 final int status = flags() & FlagsBuilder.MASK_STATUS;
133 case FlagsBuilder.STATUS_CURRENT:
134 return Status.CURRENT;
135 case FlagsBuilder.STATUS_DEPRECATED:
136 return Status.DEPRECATED;
137 case FlagsBuilder.STATUS_OBSOLETE:
138 return Status.OBSOLETE;
140 throw new IllegalStateException("Illegal status " + status);
146 default Optional<String> getDescription() {
147 return findFirstEffectiveSubstatementArgument(DescriptionEffectiveStatement.class);
151 default Optional<String> getReference() {
152 return findFirstEffectiveSubstatementArgument(ReferenceEffectiveStatement.class);
156 default List<UnknownSchemaNode> getUnknownSchemaNodes() {
157 return filterEffectiveStatementsList(UnknownSchemaNode.class);
162 * Bridge between {@link EffectiveStatementWithFlags} and {@link MandatoryAware}.
164 * @param <A> Argument type ({@link Void} if statement does not have argument.)
165 * @param <D> Class representing declared version of this statement.
167 public interface MandatoryMixin<A, D extends DeclaredStatement<A>>
168 extends EffectiveStatementWithFlags<A, D>, MandatoryAware {
170 default boolean isMandatory() {
171 return (flags() & FlagsBuilder.MANDATORY) != 0;
176 * Bridge between {@link EffectiveStatementWithFlags} and {@link SchemaNode}.
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 SchemaNodeMixin<A, D extends DeclaredStatement<A>>
182 extends DocumentedNodeMixin.WithStatus<A, D>, SchemaNode {
184 default QName getQName() {
185 return getPath().getLastComponent();
190 * Bridge between {@link EffectiveStatementWithFlags} and {@code ordered-by} statement.
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 UserOrderedMixin<A, D extends DeclaredStatement<A>> extends EffectiveStatementWithFlags<A, D> {
196 default boolean userOrdered() {
197 return (flags() & FlagsBuilder.USER_ORDERED) != 0;
202 * Helper used to locate the effective {@code when} statement and exposing its argument as per
203 * {@link WhenConditionAware}.
205 * @param <A> Argument type ({@link Void} if statement does not have argument.)
206 * @param <D> Class representing declared version of this statement.
208 public interface WhenConditionMixin<A, D extends DeclaredStatement<A>> extends Mixin<A, D>, WhenConditionAware {
210 default Optional<RevisionAwareXPath> getWhenCondition() {
211 return findFirstEffectiveSubstatementArgument(WhenEffectiveStatement.class);
216 * Support interface for various mixins. Implementations are required to store 32bits worth of flags, which are
217 * globally assigned to sub-interfaces -- thus providing storage for many low-cardinality properties.
219 * @param <A> Argument type ({@link Void} if statement does not have argument.)
220 * @param <D> Class representing declared version of this statement.
222 public interface EffectiveStatementWithFlags<A, D extends DeclaredStatement<A>> extends Mixin<A, D> {
224 * Return flags assicated with this statements. Flags can be built using {@link FlagsBuilder}.
226 * @return Flag field value (32 bits).
231 final class FlagsBuilder implements Mutable {
232 // We still have 25 flags remaining
233 static final int STATUS_CURRENT = 0x0001;
234 static final int STATUS_DEPRECATED = 0x0002;
235 static final int STATUS_OBSOLETE = 0x0003;
236 static final int MASK_STATUS = 0x0003;
238 static final int CONFIGURATION = 0x0004;
239 static final int MANDATORY = 0x0008;
241 static final int AUGMENTING = 0x0010;
242 static final int ADDED_BY_USES = 0x0020;
243 private static final int MASK_HISTORY = 0x0030;
245 static final int USER_ORDERED = 0x0040;
249 public FlagsBuilder setConfiguration(final boolean config) {
251 flags |= CONFIGURATION;
253 flags &= ~CONFIGURATION;
258 public FlagsBuilder setHistory(final CopyHistory history) {
260 if (history.contains(CopyType.ADDED_BY_USES_AUGMENTATION)) {
261 bits = AUGMENTING | ADDED_BY_USES;
264 if (history.contains(CopyType.ADDED_BY_AUGMENTATION)) {
267 if (history.contains(CopyType.ADDED_BY_USES)) {
268 bits |= ADDED_BY_USES;
272 flags = flags & ~MASK_HISTORY | bits;
276 public FlagsBuilder setMandatory(final boolean mandatory) {
285 public FlagsBuilder setStatus(final Status status) {
289 bits = STATUS_CURRENT;
292 bits = STATUS_DEPRECATED;
295 bits = STATUS_DEPRECATED;
298 throw new IllegalStateException("Unhandled status " + status);
301 flags = flags & ~MASK_STATUS | bits;
305 public FlagsBuilder setUserOrdered(final boolean userOrdered) {
307 flags |= USER_ORDERED;
309 flags &= ~USER_ORDERED;
314 public int toFlags() {