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.Collection;
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.
36 * @param <A> Argument type
37 * @param <D> Declared Statement representation
38 * @param <E> Effective Statement representation
40 public abstract class StatementSupport<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
41 implements StatementDefinition, StatementFactory<A, D, E> {
43 * A baseline class for implementing the {@link StatementFactory#canReuseCurrent(Current, Current, Collection)}
44 * contract in a manner which is consistent with a statement's {@link CopyPolicy}.
46 * @param <A> Argument type
47 * @param <D> Declared Statement representation
49 public abstract static class StatementPolicy<A, D extends DeclaredStatement<A>> implements Immutable {
50 final @NonNull CopyPolicy copyPolicy;
52 StatementPolicy(final CopyPolicy copyPolicy) {
53 this.copyPolicy = requireNonNull(copyPolicy);
57 * Return an {@link StatementPolicy} for {@link CopyPolicy#CONTEXT_INDEPENDENT}.
59 * @param <A> Argument type
60 * @param <D> Declared Statement representation
61 * @return Context-independent policy
63 @SuppressWarnings("unchecked")
64 public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> contextIndependent() {
65 return (StatementPolicy<A, D>) AlwaysReuse.CONTEXT_INDEPENDENT;
69 * Return an {@link StatementPolicy} for {@link CopyPolicy#IGNORE}.
71 * @param <A> Argument type
72 * @param <D> Declared Statement representation
73 * @return Ignoring policy
75 @SuppressWarnings("unchecked")
76 public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> ignore() {
77 return (StatementPolicy<A, D>) AlwaysFail.IGNORE;
81 * Return an {@link StatementPolicy} for {@link CopyPolicy#REJECT}.
83 * @param <A> Argument type
84 * @param <D> Declared Statement representation
85 * @return Rejecting statement policy
87 @SuppressWarnings("unchecked")
88 public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> reject() {
89 return (StatementPolicy<A, D>) AlwaysFail.REJECT;
93 * Return an {@link StatementPolicy} for {@link CopyPolicy#DECLARED_COPY}, deferring to a
94 * {@link StatementEquality} for individual decisions.
96 * @param <A> Argument type
97 * @param <D> Declared Statement representation
98 * @param equality {@link StatementEquality} to apply to effective statements
99 * @return Rejecting statement policy
101 public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> copyDeclared(
102 final @NonNull StatementEquality<A, D> equality) {
103 return new EqualSemantics<>(equality);
106 abstract boolean canReuseCurrent(@NonNull Current<A, D> copy, @NonNull Current<A, D> current,
107 @NonNull Collection<? extends EffectiveStatement<?, ?>> substatements);
110 @SuppressWarnings("unchecked")
111 static <A, D extends DeclaredStatement<A>> StatementPolicy<A, D> compat(final CopyPolicy copyPolicy) {
112 switch (copyPolicy) {
113 case CONTEXT_INDEPENDENT:
114 return contextIndependent();
116 return (StatementPolicy<A, D>) AlwaysCopy.DECLARED_COPY;
122 throw new IllegalStateException("Unsupported policy " + copyPolicy);
126 private static final class AlwaysCopy<A, D extends DeclaredStatement<A>> extends StatementPolicy<A, D> {
128 static final @NonNull AlwaysCopy<?, ?> DECLARED_COPY = new AlwaysCopy<>(CopyPolicy.DECLARED_COPY);
130 AlwaysCopy(final CopyPolicy copyPolicy) {
135 boolean canReuseCurrent(final Current<A, D> copy, final Current<A, D> current,
136 final Collection<? extends EffectiveStatement<?, ?>> substatements) {
141 private static final class AlwaysReuse<A, D extends DeclaredStatement<A>> extends StatementPolicy<A, D> {
142 static final @NonNull AlwaysReuse<?, ?> CONTEXT_INDEPENDENT =
143 new AlwaysReuse<>(CopyPolicy.CONTEXT_INDEPENDENT);
145 private AlwaysReuse(final CopyPolicy copyPolicy) {
150 boolean canReuseCurrent(final Current<A, D> copy, final Current<A, D> current,
151 final Collection<? extends EffectiveStatement<?, ?>> substatements) {
156 private static final class AlwaysFail<A, D extends DeclaredStatement<A>> extends StatementPolicy<A, D> {
157 static final @NonNull AlwaysFail<?, ?> IGNORE = new AlwaysFail<>(CopyPolicy.IGNORE);
158 static final @NonNull AlwaysFail<?, ?> REJECT = new AlwaysFail<>(CopyPolicy.REJECT);
160 private AlwaysFail(final CopyPolicy copyPolicy) {
165 boolean canReuseCurrent(final Current<A, D> copy, final Current<A, D> current,
166 final Collection<? extends EffectiveStatement<?, ?>> substatements) {
167 throw new VerifyException("This implementation should never be invoked");
171 private static final class EqualSemantics<A, D extends DeclaredStatement<A>> extends StatementPolicy<A, D> {
172 private final @NonNull StatementEquality<A, D> equality;
174 EqualSemantics(final @NonNull StatementEquality<A, D> equality) {
175 super(CopyPolicy.DECLARED_COPY);
176 this.equality = requireNonNull(equality);
180 boolean canReuseCurrent(final Current<A, D> copy, final Current<A, D> current,
181 final Collection<? extends EffectiveStatement<?, ?>> substatements) {
182 return equality.canReuseCurrent(copy, current, substatements);
188 * Abstract base class for comparators associated with statements with a {@link CopyPolicy#DECLARED_COPY} copy
191 * @param <A> Argument type
192 * @param <D> Declared Statement representation
195 public interface StatementEquality<A, D extends DeclaredStatement<A>> {
197 * Determine whether {@code current} statement has the same semantics as the provided copy. See the contract
198 * specification of {@link StatementFactory#canReuseCurrent(Current, Current, Collection)}.
200 * @param copy Copy of current effective context
201 * @param current Current effective context
202 * @param substatements Current effective substatements
203 * @return True if {@code current} can be reused in place of {@code copy}, false if the copy needs to be used.
205 boolean canReuseCurrent(@NonNull Current<A, D> copy, @NonNull Current<A, D> current,
206 @NonNull Collection<? extends EffectiveStatement<?, ?>> substatements);
209 private final @NonNull StatementPolicy<A, D> policy;
210 private final @NonNull StatementDefinition def;
211 private final @NonNull CopyPolicy copyPolicy;
214 protected StatementSupport(final StatementDefinition publicDefinition, final StatementPolicy<A, D> policy) {
215 checkArgument(publicDefinition != this);
216 this.def = requireNonNull(publicDefinition);
217 this.policy = requireNonNull(policy);
218 this.copyPolicy = policy.copyPolicy;
223 // FIXME: remove this constructor
224 protected StatementSupport(final StatementDefinition publicDefinition, final CopyPolicy copyPolicy) {
225 this(publicDefinition, StatementPolicy.compat(copyPolicy));
229 * Returns public statement definition, which will be present in built statements.
232 * Public statement definition may be used to provide different implementation of statement definition,
233 * which will not retain any build specific data or context.
235 * @return public statement definition, which will be present in built statements.
237 public final @NonNull StatementDefinition getPublicView() {
242 * Return this statement's {@link CopyPolicy}. This is a static value, reflecting how this statement reacts to being
243 * replicated to a different context, without reflecting on behaviour of potential substatements, which would come
244 * into play in something like:
258 * description "Can be used in description/reference statements to attach additional notes";
261 * description "A nice module extending description statement semantics" {
262 * foo:note "We can now attach description/reference a note.";
263 * foo:note "Also another note";
270 * In this scenario, it is the reactor's job to figure out what to do (like talking to substatements).
272 * @return This statement's copy policy
274 public final @NonNull CopyPolicy copyPolicy() {
279 public final boolean canReuseCurrent(final Current<A, D> copy, final Current<A, D> current,
280 final Collection<? extends EffectiveStatement<?, ?>> substatements) {
281 return policy.canReuseCurrent(copy, current, substatements);
285 * Parses textual representation of argument in object representation.
287 * @param ctx Context, which may be used to access source-specific namespaces required for parsing.
288 * @param value String representation of value, as was present in text source.
289 * @return Parsed value
290 * @throws SourceException when an inconsistency is detected.
292 public abstract A parseArgumentValue(StmtContext<?, ?, ?> ctx, String value);
295 * Adapts the argument value to match a new module. Default implementation returns original value stored in context,
296 * which is appropriate for most implementations.
298 * @param ctx Context, which may be used to access source-specific namespaces required for parsing.
299 * @param targetModule Target module, may not be null.
300 * @return Adapted argument value.
302 public A adaptArgumentValue(final @NonNull StmtContext<A, D, E> ctx, final @NonNull QNameModule targetModule) {
303 return ctx.argument();
307 * Invoked when a statement supported by this instance is added to build context. This allows implementations
308 * of this interface to start tracking the statement and perform any modifications to the build context hierarchy,
309 * accessible via {@link StmtContext#getParentContext()}. One such use is populating the parent's namespaces to
310 * allow it to locate this child statement.
312 * @param stmt Context of added statement. No substatements are available.
314 public void onStatementAdded(final @NonNull Mutable<A, D, E> stmt) {
315 // NOOP for most implementations
319 * Invoked when statement is closed during {@link ModelProcessingPhase#SOURCE_PRE_LINKAGE} phase, only substatements
320 * from this and previous phase are available.
323 * Implementation may use method to perform actions on this event or register modification action using
324 * {@link Mutable#newInferenceAction(ModelProcessingPhase)}.
326 * @param stmt Context of added statement.
328 public void onPreLinkageDeclared(final @NonNull Mutable<A, D, E> stmt) {
329 // NOOP for most implementations
333 * Invoked when statement is closed during {@link ModelProcessingPhase#SOURCE_LINKAGE} phase, only substatements
334 * from this and previous phase are available.
337 * Implementation may use method to perform actions on this event or register modification action using
338 * {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}.
340 * @param stmt Context of added statement.
341 * @throws SourceException when an inconsistency is detected.
343 public void onLinkageDeclared(final @NonNull Mutable<A, D, E> stmt) {
344 // NOOP for most implementations
348 * Invoked when statement is closed during {@link ModelProcessingPhase#STATEMENT_DEFINITION} phase,
349 * only substatements from this phase are available.
352 * Implementation may use method to perform actions on this event or register modification action using
353 * {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}.
355 * @param stmt Context of added statement. Argument and statement parent is accessible.
356 * @throws SourceException when an inconsistency is detected.
358 public void onStatementDefinitionDeclared(final Mutable<A, D, E> stmt) {
359 // NOOP for most implementations
363 * Invoked when statement is closed during {@link ModelProcessingPhase#FULL_DECLARATION} phase,
364 * only substatements from this phase are available.
367 * Implementation may use method to perform actions on this event or register modification action using
368 * {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}.
370 * @param stmt Context of added statement. Argument and statement parent is accessible.
371 * @throws SourceException when an inconsistency is detected.
373 public void onFullDefinitionDeclared(final StmtContext.Mutable<A, D, E> stmt) {
374 final SubstatementValidator validator = getSubstatementValidator();
375 if (validator != null) {
376 validator.validate(stmt);
381 * Returns corresponding substatement validator of a statement support.
383 * @return substatement validator or null, if substatement validator is not defined
385 // FIXME: rename to 'substatementValidator' and perhaps let it be passed in?
386 protected abstract @Nullable SubstatementValidator getSubstatementValidator();
389 * Returns true if this support has argument specific supports.
391 public boolean hasArgumentSpecificSupports() {
392 // Most of statement supports don't have any argument specific supports, so return 'false'.
397 * If this support has argument specific supports, the method returns support specific for given argument
398 * (e.g. type statement support need to be specialized based on its argument), otherwise returns null.
400 * @param argument argument of statement
401 * @return statement support specific for supplied argument or null
403 public @Nullable StatementSupport<?, ?, ?> getSupportSpecificForArgument(final String argument) {
404 // Most of statement supports don't have any argument specific supports, so return null.
409 * Given a raw string representation of an argument, try to use a shared representation. Default implementation
412 * @param rawArgument Argument string
413 * @return A potentially-shard instance
415 public String internArgument(final String rawArgument) {
420 * Returns unknown statement form of a regular YANG statement supplied as a parameter to the method. Default
421 * implementation does nothing.
423 * @param yangStmtDef statement definition of a regular YANG statement
424 * @return Optional of unknown statement form of a regular YANG statement or empty() if it is not supported by this
427 public Optional<StatementSupport<?, ?, ?>> getUnknownStatementDefinitionOf(final StatementDefinition yangStmtDef) {
428 return Optional.empty();
432 * Returns true if this statement support and all its substatements ignore if-feature statements (e.g. yang-data
433 * extension defined in <a href="https://tools.ietf.org/html/rfc8040#section-8">RFC 8040</a>). Default
434 * implementation returns false.
436 * @return true if this statement support ignores if-feature statements, otherwise false.
439 public boolean isIgnoringIfFeatures() {
444 * Returns true if this statement support and all its substatements ignore config statements (e.g. yang-data
445 * extension defined in <a href="https://tools.ietf.org/html/rfc8040#section-8">RFC 8040</a>). Default
446 * implementation returns false.
448 * @return true if this statement support ignores config statements,
452 public boolean isIgnoringConfig() {
457 public final QName getStatementName() {
458 return def.getStatementName();
462 public final Optional<ArgumentDefinition> getArgumentDefinition() {
463 return def.getArgumentDefinition();
467 // Non-final for compatible extensions
468 public Class<? extends DeclaredStatement<?>> getDeclaredRepresentationClass() {
469 return def.getDeclaredRepresentationClass();
473 // Non-final for compatible extensions
474 public Class<? extends EffectiveStatement<?,?>> getEffectiveRepresentationClass() {
475 return def.getEffectiveRepresentationClass();
479 * Statement context copy policy, indicating how should reactor handle statement copy operations. Every statement
480 * copied by the reactor is subject to this policy.
482 public enum CopyPolicy {
484 * Reuse the source statement context in the new place, as it cannot be affected by any further operations. This
485 * implies that the semantics of the effective statement are not affected by any of its substatements. Each
486 * of the substatements is free to make its own policy.
489 * This policy is typically used by static constant statements such as {@code description} or {@code length},
490 * where the baseline RFC7950 does not allow any impact. A {@code description} could hold an extension statement
491 * in which case this interaction would come into play. Normal YANG will see empty substatements, so the reactor
492 * will be free to complete reuse the context.
495 * In case any substatement is of stronger policy, it is up to the reactor to handle correct handling of
496 * resulting subobjects.
498 // TODO: does this mean source must have transitioned to ModelProcessingPhase.EFFECTIVE_MODEL?
501 * Create a copy sharing declared instance, but otherwise having a separate disconnected lifecycle.
503 // TODO: will the copy transition to ModelProcessingPhase.FULL_DECLARATION or which phase?
506 * Reject any attempt to copy this statement. This is useful for statements that are defined as top-level
507 * constructs, such as {@code contact}, {@code deviation} and similar.
511 * Ignore this statement's existence for the purposes of the new place -- it is not impacted. This guidance
512 * is left here for completeness, as it can have justifiable uses (but I can't think of any). Any substatements
513 * need to be ignored, too.