Add CopyPolicy.EXACT_REPLICA
[yangtools.git] / yang / yang-parser-spi / src / main / java / org / opendaylight / yangtools / yang / parser / spi / meta / StatementSupport.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. 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.parser.spi.meta;
9
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static java.util.Objects.requireNonNull;
12
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;
29
30 /**
31  * Support for processing concrete YANG statement.
32  *
33  * <p>
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.
36  *
37  * @param <A> Argument type
38  * @param <D> Declared Statement representation
39  * @param <E> Effective Statement representation
40  */
41 public abstract class StatementSupport<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
42         implements StatementDefinition, StatementFactory<A, D, E> {
43     /**
44      * A baseline class for implementing the {@link StatementFactory#canReuseCurrent(Current, Current, Collection)}
45      * contract in a manner which is consistent with a statement's {@link CopyPolicy}.
46      *
47      * @param <A> Argument type
48      * @param <D> Declared Statement representation
49      */
50     public abstract static class StatementPolicy<A, D extends DeclaredStatement<A>> implements Immutable {
51         final @NonNull CopyPolicy copyPolicy;
52
53         StatementPolicy(final CopyPolicy copyPolicy) {
54             this.copyPolicy = requireNonNull(copyPolicy);
55         }
56
57         /**
58          * Return a {@link StatementPolicy} for {@link CopyPolicy#CONTEXT_INDEPENDENT}.
59          *
60          * @param <A> Argument type
61          * @param <D> Declared Statement representation
62          * @return Context-independent policy
63          */
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;
67         }
68
69         /**
70          * Return a {@link StatementPolicy} for {@link CopyPolicy#EXACT_REPLICA}.
71          *
72          * @param <A> Argument type
73          * @param <D> Declared Statement representation
74          * @return Exact-replica policy
75          */
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;
79         }
80
81         /**
82          * Return a {@link StatementPolicy} for {@link CopyPolicy#IGNORE}.
83          *
84          * @param <A> Argument type
85          * @param <D> Declared Statement representation
86          * @return Ignoring policy
87          */
88         @SuppressWarnings("unchecked")
89         public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> ignore() {
90             return (StatementPolicy<A, D>) AlwaysFail.IGNORE;
91         }
92
93         /**
94          * Return a {@link StatementPolicy} for {@link CopyPolicy#REJECT}.
95          *
96          * @param <A> Argument type
97          * @param <D> Declared Statement representation
98          * @return Rejecting statement policy
99          */
100         @SuppressWarnings("unchecked")
101         public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> reject() {
102             return (StatementPolicy<A, D>) AlwaysFail.REJECT;
103         }
104
105         /**
106          * Return a {@link StatementPolicy} for {@link CopyPolicy#DECLARED_COPY}, deferring to a
107          * {@link StatementEquality} for individual decisions.
108          *
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
113          */
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);
117         }
118
119         /**
120          * Return a {@link StatementPolicy} for {@link CopyPolicy#DECLARED_COPY}, always performing a copy operation.
121          *
122          * @param <A> Argument type
123          * @param <D> Declared Statement representation
124          * @return Rejecting statement policy
125          */
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;
129         }
130
131         @Deprecated(forRemoval = true)
132         // FIXME: 7.0.0: remove this method
133         public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> legacyDeclaredCopy() {
134             return alwaysCopyDeclared();
135         }
136
137         abstract boolean canReuseCurrent(@NonNull Current<A, D> copy, @NonNull Current<A, D> current,
138             @NonNull Collection<? extends EffectiveStatement<?, ?>> substatements);
139
140         private static final class AlwaysFail<A, D extends DeclaredStatement<A>> extends StatementPolicy<A, D> {
141             static final @NonNull AlwaysFail<?, ?> IGNORE = new AlwaysFail<>(CopyPolicy.IGNORE);
142             static final @NonNull AlwaysFail<?, ?> REJECT = new AlwaysFail<>(CopyPolicy.REJECT);
143
144             private AlwaysFail(final CopyPolicy copyPolicy) {
145                 super(copyPolicy);
146             }
147
148             @Override
149             boolean canReuseCurrent(final Current<A, D> copy, final Current<A, D> current,
150                     final Collection<? extends EffectiveStatement<?, ?>> substatements) {
151                 throw new VerifyException("This implementation should never be invoked");
152             }
153         }
154
155         private static final class EqualSemantics<A, D extends DeclaredStatement<A>> extends StatementPolicy<A, D> {
156             static final @NonNull EqualSemantics<?, ?> ALWAYS_COPY =
157                 new EqualSemantics<>((copy, stmt, substatements) -> false);
158             static final @NonNull EqualSemantics<?, ?> CONTEXT_INDEPENDENT =
159                 new EqualSemantics<>(CopyPolicy.CONTEXT_INDEPENDENT, (copy, stmt, substatements) -> true);
160             static final @NonNull EqualSemantics<?, ?> EXACT_REPLICA =
161                 new EqualSemantics<>(CopyPolicy.EXACT_REPLICA, (copy, stmt, substatements) -> true);
162
163             private final @NonNull StatementEquality<A, D> equality;
164
165             private EqualSemantics(final CopyPolicy copyPolicy, final StatementEquality<A, D> equality) {
166                 super(copyPolicy);
167                 this.equality = requireNonNull(equality);
168             }
169
170             EqualSemantics(final StatementEquality<A, D> equality) {
171                 this(CopyPolicy.DECLARED_COPY, equality);
172             }
173
174             @Override
175             boolean canReuseCurrent(final Current<A, D> copy, final Current<A, D> current,
176                     final Collection<? extends EffectiveStatement<?, ?>> substatements) {
177                 return equality.canReuseCurrent(copy, current, substatements);
178             }
179         }
180     }
181
182     /**
183      * Abstract base class for comparators associated with statements with a {@link CopyPolicy#DECLARED_COPY} copy
184      * policy.
185      *
186      * @param <A> Argument type
187      * @param <D> Declared Statement representation
188      */
189     @FunctionalInterface
190     public interface StatementEquality<A, D extends DeclaredStatement<A>> {
191         /**
192          * Determine whether {@code current} statement has the same semantics as the provided copy. See the contract
193          * specification of {@link StatementFactory#canReuseCurrent(Current, Current, Collection)}.
194          *
195          * @param copy Copy of current effective context
196          * @param current Current effective context
197          * @param substatements Current effective substatements
198          * @return True if {@code current} can be reused in place of {@code copy}, false if the copy needs to be used.
199          */
200         boolean canReuseCurrent(@NonNull Current<A, D> copy, @NonNull Current<A, D> current,
201             @NonNull Collection<? extends EffectiveStatement<?, ?>> substatements);
202     }
203
204     private final @NonNull StatementPolicy<A, D> policy;
205     private final @NonNull StatementDefinition def;
206     private final @NonNull CopyPolicy copyPolicy;
207
208     @Beta
209     protected StatementSupport(final StatementSupport<A, D, E> delegate) {
210         checkArgument(delegate != this);
211         this.def = delegate.def;
212         this.policy = delegate.policy;
213         this.copyPolicy = delegate.copyPolicy;
214     }
215
216     @Beta
217     protected StatementSupport(final StatementDefinition publicDefinition, final StatementPolicy<A, D> policy) {
218         checkArgument(publicDefinition != this);
219         this.def = requireNonNull(publicDefinition);
220         this.policy = requireNonNull(policy);
221         this.copyPolicy = policy.copyPolicy;
222     }
223
224     /**
225      * Returns public statement definition, which will be present in built statements.
226      *
227      * <p>
228      * Public statement definition may be used to provide different implementation of statement definition,
229      * which will not retain any build specific data or context.
230      *
231      * @return public statement definition, which will be present in built statements.
232      */
233     public final @NonNull StatementDefinition getPublicView() {
234         return def;
235     }
236
237     /**
238      * Return this statement's {@link CopyPolicy}. This is a static value, reflecting how this statement reacts to being
239      * replicated to a different context, without reflecting on behaviour of potential substatements, which would come
240      * into play in something like:
241      *
242      * <pre>
243      *   <code>
244      *     module foo {
245      *       namespace foo;
246      *       prefix foo;
247      *
248      *       extension note {
249      *         argument string {
250      *           type string {
251      *             length 1..max;
252      *           }
253      *         }
254      *         description "Can be used in description/reference statements to attach additional notes";
255      *       }
256      *
257      *       description "A nice module extending description statement semantics" {
258      *         foo:note "We can now attach description/reference a note.";
259      *         foo:note "Also another note";
260      *       }
261      *     }
262      *   </code>
263      * </pre>
264      *
265      * <p>
266      * In this scenario, it is the reactor's job to figure out what to do (like talking to substatements).
267      *
268      * @return This statement's copy policy
269      */
270     public final @NonNull CopyPolicy copyPolicy() {
271         return copyPolicy;
272     }
273
274     @Override
275     public final boolean canReuseCurrent(final Current<A, D> copy, final Current<A, D> current,
276             final Collection<? extends EffectiveStatement<?, ?>> substatements) {
277         return policy.canReuseCurrent(copy, current, substatements);
278     }
279
280     /**
281      * Parses textual representation of argument in object representation.
282      *
283      * @param ctx Context, which may be used to access source-specific namespaces required for parsing.
284      * @param value String representation of value, as was present in text source.
285      * @return Parsed value
286      * @throws SourceException when an inconsistency is detected.
287      */
288     public abstract A parseArgumentValue(StmtContext<?, ?, ?> ctx, String value);
289
290     /**
291      * Adapts the argument value to match a new module. Default implementation returns original value stored in context,
292      * which is appropriate for most implementations.
293      *
294      * @param ctx Context, which may be used to access source-specific namespaces required for parsing.
295      * @param targetModule Target module, may not be null.
296      * @return Adapted argument value.
297      */
298     public A adaptArgumentValue(final @NonNull StmtContext<A, D, E> ctx, final @NonNull QNameModule targetModule) {
299         return ctx.argument();
300     }
301
302     /**
303      * Invoked when a statement supported by this instance is added to build context. This allows implementations
304      * of this interface to start tracking the statement and perform any modifications to the build context hierarchy,
305      * accessible via {@link StmtContext#getParentContext()}. One such use is populating the parent's namespaces to
306      * allow it to locate this child statement.
307      *
308      * @param stmt Context of added statement. No substatements are available.
309      */
310     public void onStatementAdded(final @NonNull Mutable<A, D, E> stmt) {
311         // NOOP for most implementations
312     }
313
314     /**
315      * Invoked when statement is closed during {@link ModelProcessingPhase#SOURCE_PRE_LINKAGE} phase, only substatements
316      * from this and previous phase are available.
317      *
318      * <p>
319      * Implementation may use method to perform actions on this event or register modification action using
320      * {@link Mutable#newInferenceAction(ModelProcessingPhase)}.
321      *
322      * @param stmt Context of added statement.
323      */
324     public void onPreLinkageDeclared(final @NonNull Mutable<A, D, E> stmt) {
325         // NOOP for most implementations
326     }
327
328     /**
329      * Invoked when statement is closed during {@link ModelProcessingPhase#SOURCE_LINKAGE} phase, only substatements
330      * from this and previous phase are available.
331      *
332      * <p>
333      * Implementation may use method to perform actions on this event or register modification action using
334      * {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}.
335      *
336      * @param stmt Context of added statement.
337      * @throws SourceException when an inconsistency is detected.
338      */
339     public void onLinkageDeclared(final @NonNull Mutable<A, D, E> stmt) {
340         // NOOP for most implementations
341     }
342
343     /**
344      * Invoked when statement is closed during {@link ModelProcessingPhase#STATEMENT_DEFINITION} phase,
345      * only substatements from this phase are available.
346      *
347      * <p>
348      * Implementation may use method to perform actions on this event or register modification action using
349      * {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}.
350      *
351      * @param stmt Context of added statement. Argument and statement parent is accessible.
352      * @throws SourceException when an inconsistency is detected.
353      */
354     public void onStatementDefinitionDeclared(final Mutable<A, D, E> stmt) {
355         // NOOP for most implementations
356     }
357
358     /**
359      * Invoked when statement is closed during {@link ModelProcessingPhase#FULL_DECLARATION} phase,
360      * only substatements from this phase are available.
361      *
362      * <p>
363      * Implementation may use method to perform actions on this event or register modification action using
364      * {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}.
365      *
366      * @param stmt Context of added statement. Argument and statement parent is accessible.
367      * @throws SourceException when an inconsistency is detected.
368      */
369     public void onFullDefinitionDeclared(final StmtContext.Mutable<A, D, E> stmt) {
370         final SubstatementValidator validator = getSubstatementValidator();
371         if (validator != null) {
372             validator.validate(stmt);
373         }
374     }
375
376     /**
377      * Returns corresponding substatement validator of a statement support.
378      *
379      * @return substatement validator or null, if substatement validator is not defined
380      */
381     // FIXME: rename to 'substatementValidator' and perhaps let it be passed in?
382     protected abstract @Nullable SubstatementValidator getSubstatementValidator();
383
384     /**
385      * Returns true if this support has argument specific supports.
386      */
387     public boolean hasArgumentSpecificSupports() {
388         // Most of statement supports don't have any argument specific supports, so return 'false'.
389         return false;
390     }
391
392     /**
393      * If this support has argument specific supports, the method returns support specific for given argument
394      * (e.g. type statement support need to be specialized based on its argument), otherwise returns null.
395      *
396      * @param argument argument of statement
397      * @return statement support specific for supplied argument or null
398      */
399     public @Nullable StatementSupport<?, ?, ?> getSupportSpecificForArgument(final String argument) {
400         // Most of statement supports don't have any argument specific supports, so return null.
401         return null;
402     }
403
404     /**
405      * Given a raw string representation of an argument, try to use a shared representation. Default implementation
406      * does nothing.
407      *
408      * @param rawArgument Argument string
409      * @return A potentially-shard instance
410      */
411     public String internArgument(final String rawArgument) {
412         return rawArgument;
413     }
414
415     /**
416      * Returns unknown statement form of a regular YANG statement supplied as a parameter to the method. Default
417      * implementation does nothing.
418      *
419      * @param yangStmtDef statement definition of a regular YANG statement
420      * @return Optional of unknown statement form of a regular YANG statement or empty() if it is not supported by this
421      *         statement support
422      */
423     public Optional<StatementSupport<?, ?, ?>> getUnknownStatementDefinitionOf(final StatementDefinition yangStmtDef) {
424         return Optional.empty();
425     }
426
427     /**
428      * Returns true if this statement support and all its substatements ignore if-feature statements (e.g. yang-data
429      * extension defined in <a href="https://tools.ietf.org/html/rfc8040#section-8">RFC 8040</a>). Default
430      * implementation returns false.
431      *
432      * @return true if this statement support ignores if-feature statements, otherwise false.
433      */
434     @Beta
435     public boolean isIgnoringIfFeatures() {
436         return false;
437     }
438
439     /**
440      * Returns true if this statement support and all its substatements ignore config statements (e.g. yang-data
441      * extension defined in <a href="https://tools.ietf.org/html/rfc8040#section-8">RFC 8040</a>). Default
442      * implementation returns false.
443      *
444      * @return true if this statement support ignores config statements,
445      *         otherwise false.
446      */
447     @Beta
448     public boolean isIgnoringConfig() {
449         return false;
450     }
451
452     @Override
453     public final QName getStatementName() {
454         return def.getStatementName();
455     }
456
457     @Override
458     public final Optional<ArgumentDefinition> getArgumentDefinition() {
459         return def.getArgumentDefinition();
460     }
461
462     @Override
463     // Non-final for compatible extensions
464     public Class<? extends DeclaredStatement<?>> getDeclaredRepresentationClass() {
465         return def.getDeclaredRepresentationClass();
466     }
467
468     @Override
469     // Non-final for compatible extensions
470     public Class<? extends EffectiveStatement<?,?>> getEffectiveRepresentationClass() {
471         return def.getEffectiveRepresentationClass();
472     }
473
474     /**
475      * Statement context copy policy, indicating how should reactor handle statement copy operations. Every statement
476      * copied by the reactor is subject to this policy.
477      */
478     public enum CopyPolicy {
479         /**
480          * Reuse the source statement context in the new place, as it cannot be affected by any further operations. This
481          * implies that the semantics of the effective statement are not affected by any of its substatements. Each
482          * of the substatements is free to make its own policy.
483          *
484          * <p>
485          * This policy is typically used by static constant statements such as {@code description} or {@code length},
486          * where the baseline RFC7950 does not allow any impact. A {@code description} could hold an extension statement
487          * in which case this interaction would come into play. Normal YANG will see empty substatements, so the reactor
488          * will be free to complete reuse the context.
489          *
490          * <p>
491          * In case any substatement is of stronger policy, it is up to the reactor to handle correct handling of
492          * resulting subobjects.
493          */
494         // TODO: does this mean source must have transitioned to ModelProcessingPhase.EFFECTIVE_MODEL?
495         CONTEXT_INDEPENDENT,
496         /**
497          * Reuse the source statement context in the new place completely. This policy is more stringent than
498          * {@link #CONTEXT_INDEPENDENT} in that the statement is dependent on circumstances of its original definition
499          * and any copy operation must replicate it exactly as is. This implies ignoring the usual policy of its
500          * substatements. A typical example of such a statement is {@code type}.
501          */
502         EXACT_REPLICA,
503         /**
504          * Create a copy sharing declared instance, but otherwise having a separate disconnected lifecycle.
505          */
506         // TODO: will the copy transition to ModelProcessingPhase.FULL_DECLARATION or which phase?
507         DECLARED_COPY,
508         /**
509          * Reject any attempt to copy this statement. This is useful for statements that are defined as top-level
510          * constructs, such as {@code contact}, {@code deviation} and similar.
511          */
512         REJECT,
513         /**
514          * Ignore this statement's existence for the purposes of the new place -- it is not impacted. This guidance
515          * is left here for completeness, as it can have justifiable uses (but I can't think of any). Any substatements
516          * need to be ignored, too.
517          */
518         IGNORE;
519     }
520 }