Do not force materialization when not needed
[yangtools.git] / yang / yang-parser-spi / src / main / java / org / opendaylight / yangtools / yang / parser / spi / meta / AbstractStatementSupport.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 org.eclipse.jdt.annotation.NonNull;
17 import org.eclipse.jdt.annotation.Nullable;
18 import org.opendaylight.yangtools.concepts.Immutable;
19 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
20 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
21 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
22 import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current;
23
24 /**
25  * Class providing necessary support for processing a YANG statement. This class is intended to be subclassed
26  * by developers who want to add semantic support for a statement to a parser reactor.
27  *
28  * @param <A> Argument type
29  * @param <D> Declared Statement representation
30  * @param <E> Effective Statement representation
31  */
32 public abstract class AbstractStatementSupport<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
33         implements StatementDefinition, StatementFactory<A, D, E>, StatementSupport<A, D, E> {
34     /**
35      * A baseline class for implementing the {@link StatementFactory#canReuseCurrent(Current, Current, Collection)}
36      * contract in a manner which is consistent with a statement's {@link CopyPolicy}.
37      *
38      * @param <A> Argument type
39      * @param <D> Declared Statement representation
40      */
41     public abstract static class StatementPolicy<A, D extends DeclaredStatement<A>> implements Immutable {
42         final @NonNull CopyPolicy copyPolicy;
43
44         StatementPolicy(final CopyPolicy copyPolicy) {
45             this.copyPolicy = requireNonNull(copyPolicy);
46         }
47
48         /**
49          * Return an {@link StatementPolicy} for {@link CopyPolicy#CONTEXT_INDEPENDENT}.
50          *
51          * @param <A> Argument type
52          * @param <D> Declared Statement representation
53          * @return Context-independent policy
54          */
55         @SuppressWarnings("unchecked")
56         public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> contextIndependent() {
57             return (StatementPolicy<A, D>) AlwaysReuse.CONTEXT_INDEPENDENT;
58         }
59
60         /**
61          * Return an {@link StatementPolicy} for {@link CopyPolicy#IGNORE}.
62          *
63          * @param <A> Argument type
64          * @param <D> Declared Statement representation
65          * @return Ignoring policy
66          */
67         @SuppressWarnings("unchecked")
68         public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> ignore() {
69             return (StatementPolicy<A, D>) AlwaysFail.IGNORE;
70         }
71
72         /**
73          * Return an {@link StatementPolicy} for {@link CopyPolicy#REJECT}.
74          *
75          * @param <A> Argument type
76          * @param <D> Declared Statement representation
77          * @return Rejecting statement policy
78          */
79         @SuppressWarnings("unchecked")
80         public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> reject() {
81             return (StatementPolicy<A, D>) AlwaysFail.REJECT;
82         }
83
84         /**
85          * Return an {@link StatementPolicy} for {@link CopyPolicy#DECLARED_COPY}, deferring to a
86          * {@link StatementEquality} for individual decisions.
87          *
88          * @param <A> Argument type
89          * @param <D> Declared Statement representation
90          * @param equality {@link StatementEquality} to apply to effective statements
91          * @return Rejecting statement policy
92          */
93         public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> copyDeclared(
94                 final @NonNull StatementEquality<A, D> equality) {
95             return new EqualSemantics<>(equality);
96         }
97
98         abstract boolean canReuseCurrent(@NonNull Current<A, D> copy, @NonNull Current<A, D> current,
99             @NonNull Collection<? extends EffectiveStatement<?, ?>> substatements);
100
101         @Deprecated
102         @SuppressWarnings("unchecked")
103         static <A, D extends DeclaredStatement<A>> StatementPolicy<A, D> compat(final CopyPolicy copyPolicy) {
104             switch (copyPolicy) {
105                 case CONTEXT_INDEPENDENT:
106                     return contextIndependent();
107                 case DECLARED_COPY:
108                     return (StatementPolicy<A, D>) AlwaysCopy.DECLARED_COPY;
109                 case IGNORE:
110                     return ignore();
111                 case REJECT:
112                     return reject();
113                 default:
114                     throw new IllegalStateException("Unsupported policy " + copyPolicy);
115             }
116         }
117
118         private static final class AlwaysCopy<A, D extends DeclaredStatement<A>> extends StatementPolicy<A, D> {
119             @Deprecated
120             static final @NonNull AlwaysCopy<?, ?> DECLARED_COPY = new AlwaysCopy<>(CopyPolicy.DECLARED_COPY);
121
122             AlwaysCopy(final CopyPolicy copyPolicy) {
123                 super(copyPolicy);
124             }
125
126             @Override
127             boolean canReuseCurrent(final Current<A, D> copy, final Current<A, D> current,
128                     final Collection<? extends EffectiveStatement<?, ?>> substatements) {
129                 return false;
130             }
131         }
132
133         private static final class AlwaysReuse<A, D extends DeclaredStatement<A>> extends StatementPolicy<A, D> {
134             static final @NonNull AlwaysReuse<?, ?> CONTEXT_INDEPENDENT =
135                 new AlwaysReuse<>(CopyPolicy.CONTEXT_INDEPENDENT);
136
137             private AlwaysReuse(final CopyPolicy copyPolicy) {
138                 super(copyPolicy);
139             }
140
141             @Override
142             boolean canReuseCurrent(final Current<A, D> copy, final Current<A, D> current,
143                     final Collection<? extends EffectiveStatement<?, ?>> substatements) {
144                 return true;
145             }
146         }
147
148         private static final class AlwaysFail<A, D extends DeclaredStatement<A>> extends StatementPolicy<A, D> {
149             static final @NonNull AlwaysFail<?, ?> IGNORE = new AlwaysFail<>(CopyPolicy.IGNORE);
150             static final @NonNull AlwaysFail<?, ?> REJECT = new AlwaysFail<>(CopyPolicy.REJECT);
151
152             private AlwaysFail(final CopyPolicy copyPolicy) {
153                 super(copyPolicy);
154             }
155
156             @Override
157             boolean canReuseCurrent(final Current<A, D> copy, final Current<A, D> current,
158                     final Collection<? extends EffectiveStatement<?, ?>> substatements) {
159                 throw new VerifyException("This implementation should never be invoked");
160             }
161         }
162
163         private static final class EqualSemantics<A, D extends DeclaredStatement<A>> extends StatementPolicy<A, D> {
164             private final @NonNull StatementEquality<A, D> equality;
165
166             EqualSemantics(final @NonNull StatementEquality<A, D> equality) {
167                 super(CopyPolicy.DECLARED_COPY);
168                 this.equality = requireNonNull(equality);
169             }
170
171             @Override
172             boolean canReuseCurrent(final Current<A, D> copy, final Current<A, D> current,
173                     final Collection<? extends EffectiveStatement<?, ?>> substatements) {
174                 return equality.canReuseCurrent(copy, current, substatements);
175             }
176         }
177     }
178
179     /**
180      * Abstract base class for comparators associated with statements with a {@link CopyPolicy#DECLARED_COPY} copy
181      * policy.
182      *
183      * @param <A> Argument type
184      * @param <D> Declared Statement representation
185      */
186     @FunctionalInterface
187     public interface StatementEquality<A, D extends DeclaredStatement<A>> {
188         /**
189          * Determine whether {@code current} statement has the same semantics as the provided copy. See the contract
190          * specification of {@link StatementFactory#canReuseCurrent(Current, Current, Collection)}.
191          *
192          * @param copy Copy of current effective context
193          * @param current Current effective context
194          * @param substatements Current effective substatements
195          * @return True if {@code current} can be reused in place of {@code copy}, false if the copy needs to be used.
196          */
197         boolean canReuseCurrent(@NonNull Current<A, D> copy, @NonNull Current<A, D> current,
198             @NonNull Collection<? extends EffectiveStatement<?, ?>> substatements);
199     }
200
201     private final @NonNull StatementPolicy<A, D> policy;
202     private final @NonNull StatementDefinition type;
203     private final @NonNull CopyPolicy copyPolicy;
204
205     @Beta
206     protected AbstractStatementSupport(final StatementDefinition publicDefinition, final StatementPolicy<A, D> policy) {
207         this.type = requireNonNull(publicDefinition);
208         this.policy = requireNonNull(policy);
209         this.copyPolicy = policy.copyPolicy;
210         checkArgument(publicDefinition != this);
211     }
212
213     @Beta
214     @Deprecated
215     // FIXME: remove this constructor
216     protected AbstractStatementSupport(final StatementDefinition publicDefinition, final CopyPolicy copyPolicy) {
217         this(publicDefinition, StatementPolicy.compat(copyPolicy));
218     }
219
220     @Override
221     public final StatementDefinition getPublicView() {
222         return type;
223     }
224
225     @Override
226     public final CopyPolicy copyPolicy() {
227         return copyPolicy;
228     }
229
230     @Override
231     public final boolean canReuseCurrent(final Current<A, D> copy, final Current<A, D> current,
232              final Collection<? extends EffectiveStatement<?, ?>> substatements) {
233         return policy.canReuseCurrent(copy, current, substatements);
234     }
235
236     @Override
237     public void onStatementAdded(final StmtContext.Mutable<A, D, E> stmt) {
238         // NOOP for most implementations
239     }
240
241     /**
242      * {@inheritDoc}.
243      *
244      * <p>
245      * Subclasses of this class may override this method to perform actions on this event or register a modification
246      * action using {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}.
247      */
248     @Override
249     public void onPreLinkageDeclared(final StmtContext.Mutable<A, D, E> stmt) {
250         // NOOP for most implementations
251     }
252
253     /**
254      * {@inheritDoc}.
255      *
256      * <p>
257      * Subclasses of this class may override this method to perform actions on this event or register a modification
258      * action using {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}.
259      */
260     @Override
261     public void onLinkageDeclared(final StmtContext.Mutable<A, D, E> stmt) {
262         // NOOP for most implementations
263     }
264
265     /**
266      * {@inheritDoc}.
267      *
268      * <p>
269      * Subclasses of this class may override this method to perform actions on this event or register a modification
270      * action using {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}.
271      */
272     @Override
273     public void onStatementDefinitionDeclared(final StmtContext.Mutable<A, D, E> stmt) {
274         // NOOP for most implementations
275     }
276
277     /**
278      * {@inheritDoc}.
279      *
280      * <p>
281      * Subclasses of this class may override this method to perform actions on this event or register a modification
282      * action using {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}.
283      */
284     @Override
285     public void onFullDefinitionDeclared(final StmtContext.Mutable<A, D, E> stmt) {
286         final SubstatementValidator validator = getSubstatementValidator();
287         if (validator != null) {
288             validator.validate(stmt);
289         }
290     }
291
292     @Override
293     public boolean hasArgumentSpecificSupports() {
294         // Most of statement supports don't have any argument specific supports, so return 'false'.
295         return false;
296     }
297
298     @Override
299     public StatementSupport<?, ?, ?> getSupportSpecificForArgument(final String argument) {
300         // Most of statement supports don't have any argument specific supports, so return null.
301         return null;
302     }
303
304     /**
305      * Returns corresponding substatement validator of a statement support.
306      *
307      * @return substatement validator or null, if substatement validator is not defined
308      */
309     protected abstract @Nullable SubstatementValidator getSubstatementValidator();
310 }