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