2 * Copyright (c) 2015 Cisco Systems, Inc. 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.spi.meta;
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static java.util.Objects.requireNonNull;
13 import com.google.common.annotations.Beta;
14 import com.google.common.base.VerifyException;
15 import java.util.List;
16 import java.util.Optional;
17 import org.eclipse.jdt.annotation.NonNull;
18 import org.eclipse.jdt.annotation.Nullable;
19 import org.opendaylight.yangtools.concepts.Immutable;
20 import org.opendaylight.yangtools.yang.common.QName;
21 import org.opendaylight.yangtools.yang.common.QNameModule;
22 import org.opendaylight.yangtools.yang.model.api.meta.ArgumentDefinition;
23 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
24 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
25 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
26 import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current;
27 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
28 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
31 * Support for processing concrete YANG statement.
34 * This interface is intended to be implemented by developers, which want to introduce support of statement to parser.
35 * Consider subclassing {@link AbstractStatementSupport} for easier implementation of this interface.
37 * @param <A> Argument type
38 * @param <D> Declared Statement representation
39 * @param <E> Effective Statement representation
41 public abstract class StatementSupport<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
42 implements StatementFactory<A, D, E> {
44 * A baseline class for implementing the {@link StatementFactory#canReuseCurrent(Current, Current, List)}
45 * contract in a manner which is consistent with a statement's {@link CopyPolicy}.
47 * @param <A> Argument type
48 * @param <D> Declared Statement representation
50 public abstract static class StatementPolicy<A, D extends DeclaredStatement<A>> implements Immutable {
51 final @NonNull CopyPolicy copyPolicy;
53 StatementPolicy(final CopyPolicy copyPolicy) {
54 this.copyPolicy = requireNonNull(copyPolicy);
58 * Return a {@link StatementPolicy} for {@link CopyPolicy#CONTEXT_INDEPENDENT}.
60 * @param <A> Argument type
61 * @param <D> Declared Statement representation
62 * @return Context-independent policy
64 @SuppressWarnings("unchecked")
65 public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> contextIndependent() {
66 return (StatementPolicy<A, D>) EqualSemantics.CONTEXT_INDEPENDENT;
70 * Return a {@link StatementPolicy} for {@link CopyPolicy#EXACT_REPLICA}.
72 * @param <A> Argument type
73 * @param <D> Declared Statement representation
74 * @return Exact-replica policy
76 @SuppressWarnings("unchecked")
77 public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> exactReplica() {
78 return (StatementPolicy<A, D>) EqualSemantics.EXACT_REPLICA;
82 * Return a {@link StatementPolicy} for {@link CopyPolicy#IGNORE}.
84 * @param <A> Argument type
85 * @param <D> Declared Statement representation
86 * @return Ignoring policy
88 @SuppressWarnings("unchecked")
89 public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> ignore() {
90 return (StatementPolicy<A, D>) AlwaysFail.IGNORE;
94 * Return a {@link StatementPolicy} for {@link CopyPolicy#REJECT}.
96 * @param <A> Argument type
97 * @param <D> Declared Statement representation
98 * @return Rejecting statement policy
100 @SuppressWarnings("unchecked")
101 public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> reject() {
102 return (StatementPolicy<A, D>) AlwaysFail.REJECT;
106 * Return a {@link StatementPolicy} for {@link CopyPolicy#DECLARED_COPY}, deferring to a
107 * {@link StatementEquality} for individual decisions.
109 * @param <A> Argument type
110 * @param <D> Declared Statement representation
111 * @param equality {@link StatementEquality} to apply to effective statements
112 * @return Equality-based statement policy
114 public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> copyDeclared(
115 final @NonNull StatementEquality<A, D> equality) {
116 return new EqualSemantics<>(equality);
120 * Return a {@link StatementPolicy} for {@link CopyPolicy#DECLARED_COPY}, always performing a copy operation.
122 * @param <A> Argument type
123 * @param <D> Declared Statement representation
124 * @return Rejecting statement policy
126 @SuppressWarnings("unchecked")
127 public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> alwaysCopyDeclared() {
128 return (StatementPolicy<A, D>) EqualSemantics.ALWAYS_COPY;
131 abstract boolean canReuseCurrent(@NonNull Current<A, D> copy, @NonNull Current<A, D> current,
132 @NonNull List<? extends EffectiveStatement<?, ?>> substatements);
134 private static final class AlwaysFail<A, D extends DeclaredStatement<A>> extends StatementPolicy<A, D> {
135 static final @NonNull AlwaysFail<?, ?> IGNORE = new AlwaysFail<>(CopyPolicy.IGNORE);
136 static final @NonNull AlwaysFail<?, ?> REJECT = new AlwaysFail<>(CopyPolicy.REJECT);
138 private AlwaysFail(final CopyPolicy copyPolicy) {
143 boolean canReuseCurrent(final Current<A, D> copy, final Current<A, D> current,
144 final List<? extends EffectiveStatement<?, ?>> substatements) {
145 throw new VerifyException("This implementation should never be invoked");
149 private static final class EqualSemantics<A, D extends DeclaredStatement<A>> extends StatementPolicy<A, D> {
150 static final @NonNull EqualSemantics<?, ?> ALWAYS_COPY =
151 new EqualSemantics<>((copy, stmt, substatements) -> false);
152 static final @NonNull EqualSemantics<?, ?> CONTEXT_INDEPENDENT =
153 new EqualSemantics<>(CopyPolicy.CONTEXT_INDEPENDENT, (copy, stmt, substatements) -> true);
154 static final @NonNull EqualSemantics<?, ?> EXACT_REPLICA =
155 new EqualSemantics<>(CopyPolicy.EXACT_REPLICA, (copy, stmt, substatements) -> true);
157 private final @NonNull StatementEquality<A, D> equality;
159 private EqualSemantics(final CopyPolicy copyPolicy, final StatementEquality<A, D> equality) {
161 this.equality = requireNonNull(equality);
164 EqualSemantics(final StatementEquality<A, D> equality) {
165 this(CopyPolicy.DECLARED_COPY, equality);
169 boolean canReuseCurrent(final Current<A, D> copy, final Current<A, D> current,
170 final List<? extends EffectiveStatement<?, ?>> substatements) {
171 return equality.canReuseCurrent(copy, current, substatements);
177 * Abstract base class for comparators associated with statements with a {@link CopyPolicy#DECLARED_COPY} copy
180 * @param <A> Argument type
181 * @param <D> Declared Statement representation
184 public interface StatementEquality<A, D extends DeclaredStatement<A>> {
186 * Determine whether {@code current} statement has the same semantics as the provided copy. See the contract
187 * specification of {@link StatementFactory#canReuseCurrent(Current, Current, List)}.
189 * @param copy Copy of current effective context
190 * @param current Current effective context
191 * @param substatements Current effective substatements
192 * @return True if {@code current} can be reused in place of {@code copy}, false if the copy needs to be used.
194 boolean canReuseCurrent(@NonNull Current<A, D> copy, @NonNull Current<A, D> current,
195 @NonNull List<? extends EffectiveStatement<?, ?>> substatements);
199 * Projection of {@link StatementSupport}s available within a particular source. This namespace is purely virtual
200 * and its behaviour corresponds to {@link NamespaceBehaviour#rootStatementLocal(ParserNamespace)} and is always
202 * Its contents are derived from {@link StatementSupportBundle}s active in the current {@link ModelProcessingPhase}
203 * as well as {@link StatementDefinitions} and {@link StmtContext#yangVersion()} of the source root statement.
206 public static final @NonNull ParserNamespace<QName, StatementSupport<?, ?, ?>> NAMESPACE =
207 new ParserNamespace<>("statementSupports");
209 private final @NonNull StatementPolicy<A, D> policy;
210 private final @NonNull StatementDefinition publicDefinition;
211 private final @NonNull CopyPolicy copyPolicy;
213 protected StatementSupport(final StatementSupport<A, D, E> delegate) {
214 checkArgument(delegate != this);
215 publicDefinition = delegate.publicDefinition;
216 policy = delegate.policy;
217 copyPolicy = delegate.copyPolicy;
220 protected StatementSupport(final StatementDefinition publicDefinition, final StatementPolicy<A, D> policy) {
221 this.publicDefinition = requireNonNull(publicDefinition);
222 this.policy = requireNonNull(policy);
223 copyPolicy = policy.copyPolicy;
227 * Returns public statement definition, which will be present in built statements.
230 * Public statement definition may be used to provide different implementation of statement definition,
231 * which will not retain any build specific data or context.
233 * @return public statement definition, which will be present in built statements.
235 public final @NonNull StatementDefinition getPublicView() {
236 return publicDefinition;
239 // Appropriate to most definitions
240 // Non-final for compatible extensions
241 public @NonNull StatementDefinition definition() {
242 return publicDefinition;
246 * Return this statement's {@link CopyPolicy}. This is a static value, reflecting how this statement reacts to being
247 * replicated to a different context, without reflecting on behaviour of potential substatements, which would come
248 * into play in something like:
262 * description "Can be used in description/reference statements to attach additional notes";
265 * description "A nice module extending description statement semantics" {
266 * foo:note "We can now attach description/reference a note.";
267 * foo:note "Also another note";
274 * In this scenario, it is the reactor's job to figure out what to do (like talking to substatements).
276 * @return This statement's copy policy
278 public final @NonNull CopyPolicy copyPolicy() {
283 public final boolean canReuseCurrent(final Current<A, D> copy, final Current<A, D> current,
284 final List<? extends EffectiveStatement<?, ?>> substatements) {
285 return policy.canReuseCurrent(copy, current, substatements);
289 public EffectiveStatementState extractEffectiveState(final E stmt) {
290 // Not implemented for most statements
295 * Parses textual representation of argument in object representation.
297 * @param ctx Context, which may be used to access source-specific namespaces required for parsing.
298 * @param value String representation of value, as was present in text source.
299 * @return Parsed value
300 * @throws SourceException when an inconsistency is detected.
302 public abstract A parseArgumentValue(@NonNull StmtContext<?, ?, ?> ctx, String value);
305 * Adapts the argument value to match a new module. Default implementation returns original value stored in context,
306 * which is appropriate for most implementations.
308 * @param ctx Context, which may be used to access source-specific namespaces required for parsing.
309 * @param targetModule Target module, may not be null.
310 * @return Adapted argument value.
312 public A adaptArgumentValue(final @NonNull StmtContext<A, D, E> ctx, final @NonNull QNameModule targetModule) {
313 return ctx.argument();
317 * Invoked when a statement supported by this instance is added to build context. This allows implementations
318 * of this interface to start tracking the statement and perform any modifications to the build context hierarchy,
319 * accessible via {@link StmtContext#getParentContext()}. One such use is populating the parent's namespaces to
320 * allow it to locate this child statement.
322 * @param stmt Context of added statement. No substatements are available.
324 public void onStatementAdded(final @NonNull Mutable<A, D, E> stmt) {
325 // NOOP for most implementations
329 * Invoked when statement is closed during {@link ModelProcessingPhase#SOURCE_PRE_LINKAGE} phase, only substatements
330 * from this and previous phase are available.
333 * Implementation may use method to perform actions on this event or register modification action using
334 * {@link Mutable#newInferenceAction(ModelProcessingPhase)}.
336 * @param stmt Context of added statement.
338 public void onPreLinkageDeclared(final @NonNull Mutable<A, D, E> stmt) {
339 // NOOP for most implementations
343 * Invoked when statement is closed during {@link ModelProcessingPhase#SOURCE_LINKAGE} phase, only substatements
344 * from this and previous phase are available.
347 * Implementation may use method to perform actions on this event or register modification action using
348 * {@link Mutable#newInferenceAction(ModelProcessingPhase)}.
350 * @param stmt Context of added statement.
351 * @throws SourceException when an inconsistency is detected.
353 public void onLinkageDeclared(final @NonNull Mutable<A, D, E> stmt) {
354 // NOOP for most implementations
358 * Invoked when statement is closed during {@link ModelProcessingPhase#STATEMENT_DEFINITION} phase,
359 * only substatements from this phase are available.
362 * Implementation may use method to perform actions on this event or register modification action using
363 * {@link Mutable#newInferenceAction(ModelProcessingPhase)}.
365 * @param stmt Context of added statement. Argument and statement parent is accessible.
366 * @throws SourceException when an inconsistency is detected.
368 public void onStatementDefinitionDeclared(final @NonNull Mutable<A, D, E> stmt) {
369 // NOOP for most implementations
373 * Invoked when statement is closed during {@link ModelProcessingPhase#FULL_DECLARATION} phase,
374 * only substatements from this phase are available.
377 * Implementation may use method to perform actions on this event or register modification action using
378 * {@link Mutable#newInferenceAction(ModelProcessingPhase)}.
380 * @param stmt Context of added statement. Argument and statement parent is accessible.
381 * @throws SourceException when an inconsistency is detected.
383 public void onFullDefinitionDeclared(final @NonNull Mutable<A, D, E> stmt) {
384 final SubstatementValidator validator = substatementValidator();
385 if (validator != null) {
386 validator.validate(stmt);
391 * Returns corresponding substatement validator of a statement support.
393 * @return substatement validator or null, if substatement validator is not defined
395 protected abstract @Nullable SubstatementValidator substatementValidator();
398 * Returns true if this support has argument specific supports.
400 * @return true if this support has argument specific supports.
402 public boolean hasArgumentSpecificSupports() {
403 // Most of statement supports don't have any argument specific supports, so return 'false'.
408 * If this support has argument specific supports, the method returns support specific for given argument
409 * (e.g. type statement support need to be specialized based on its argument), otherwise returns null.
411 * @param argument argument of statement
412 * @return statement support specific for supplied argument or null
414 public @Nullable StatementSupport<?, ?, ?> getSupportSpecificForArgument(final String argument) {
415 // Most of statement supports don't have any argument specific supports, so return null.
420 * Given a raw string representation of an argument, try to use a shared representation. Default implementation
423 * @param rawArgument Argument string
424 * @return A potentially-shard instance
426 public String internArgument(final String rawArgument) {
431 * Returns true if this statement support and all its substatements ignore if-feature statements (e.g. yang-data
432 * extension defined in <a href="https://www.rfc-editor.org/rfc/rfc8040#section-8">RFC 8040</a>). Default
433 * implementation returns false.
435 * @return true if this statement support ignores if-feature statements, otherwise false.
438 public boolean isIgnoringIfFeatures() {
443 * Returns true if this statement support and all its substatements ignore config statements (e.g. yang-data
444 * extension defined in <a href="https://www.rfc-editor.org/rfc/rfc8040#section-8">RFC 8040</a>). Default
445 * implementation returns false.
447 * @return true if this statement support ignores config statements,
451 public boolean isIgnoringConfig() {
455 public final @NonNull QName statementName() {
456 return publicDefinition.getStatementName();
459 public final @Nullable QName argumentName() {
460 return publicDefinition.getArgumentDefinition().map(ArgumentDefinition::argumentName).orElse(null);
463 public final @NonNull Optional<ArgumentDefinition> getArgumentDefinition() {
464 return publicDefinition.getArgumentDefinition();
468 * Statement context copy policy, indicating how should reactor handle statement copy operations. Every statement
469 * copied by the reactor is subject to this policy.
471 public enum CopyPolicy {
473 * Reuse the source statement context in the new place, as it cannot be affected by any further operations. This
474 * implies that the semantics of the effective statement are not affected by any of its substatements. Each
475 * of the substatements is free to make its own policy.
478 * This policy is typically used by static constant statements such as {@code description} or {@code length},
479 * where the baseline RFC7950 does not allow any impact. A {@code description} could hold an extension statement
480 * in which case this interaction would come into play. Normal YANG will see empty substatements, so the reactor
481 * will be free to complete reuse the context.
484 * In case any substatement is of stronger policy, it is up to the reactor to handle correct handling of
485 * resulting subobjects.
487 // TODO: does this mean source must have transitioned to ModelProcessingPhase.EFFECTIVE_MODEL?
490 * Reuse the source statement context in the new place completely. This policy is more stringent than
491 * {@link #CONTEXT_INDEPENDENT} in that the statement is dependent on circumstances of its original definition
492 * and any copy operation must replicate it exactly as is. This implies ignoring the usual policy of its
493 * substatements. A typical example of such a statement is {@code type}.
497 * Create a copy sharing declared instance, but otherwise having a separate disconnected lifecycle.
499 // TODO: will the copy transition to ModelProcessingPhase.FULL_DECLARATION or which phase?
502 * Reject any attempt to copy this statement. This is useful for statements that are defined as top-level
503 * constructs, such as {@code contact}, {@code deviation} and similar.
507 * Ignore this statement's existence for the purposes of the new place -- it is not impacted. This guidance
508 * is left here for completeness, as it can have justifiable uses (but I can't think of any). Any substatements
509 * need to be ignored, too.