Move case statement implementations
[yangtools.git] / yang / yang-parser-rfc7950 / src / main / java / org / opendaylight / yangtools / yang / parser / rfc7950 / stmt / meta / CaseStatementSupport.java
1 /*
2  * Copyright (c) 2017 Pantheon Technologies, s.r.o. 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.rfc7950.stmt.meta;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.annotations.Beta;
13 import com.google.common.collect.ImmutableList;
14 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
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.yang.common.QName;
20 import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
21 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
22 import org.opendaylight.yangtools.yang.model.api.Status;
23 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
24 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
25 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
26 import org.opendaylight.yangtools.yang.model.api.meta.StatementSource;
27 import org.opendaylight.yangtools.yang.model.api.stmt.CaseEffectiveStatement;
28 import org.opendaylight.yangtools.yang.model.api.stmt.CaseStatement;
29 import org.opendaylight.yangtools.yang.model.api.stmt.StatusEffectiveStatement;
30 import org.opendaylight.yangtools.yang.model.ri.stmt.DeclaredStatements;
31 import org.opendaylight.yangtools.yang.model.ri.stmt.EffectiveStatements;
32 import org.opendaylight.yangtools.yang.model.ri.stmt.ImplicitStatements;
33 import org.opendaylight.yangtools.yang.model.spi.meta.EffectiveStatementMixins.EffectiveStatementWithFlags.FlagsBuilder;
34 import org.opendaylight.yangtools.yang.model.spi.meta.SubstatementIndexingException;
35 import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.BaseImplicitStatementSupport;
36 import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current;
37 import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Parent.EffectiveConfig;
38 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
39 import org.opendaylight.yangtools.yang.parser.spi.meta.SubstatementValidator;
40 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
41
42 @Beta
43 public final class CaseStatementSupport
44         extends BaseImplicitStatementSupport<CaseStatement, CaseEffectiveStatement> {
45     private static final @NonNull CaseStatementSupport RFC6020_INSTANCE = new CaseStatementSupport(
46         SubstatementValidator.builder(YangStmtMapping.CASE)
47             .addAny(YangStmtMapping.ANYXML)
48             .addAny(YangStmtMapping.CHOICE)
49             .addAny(YangStmtMapping.CONTAINER)
50             .addOptional(YangStmtMapping.DESCRIPTION)
51             .addAny(YangStmtMapping.IF_FEATURE)
52             .addAny(YangStmtMapping.LEAF)
53             .addAny(YangStmtMapping.LEAF_LIST)
54             .addAny(YangStmtMapping.LIST)
55             .addOptional(YangStmtMapping.REFERENCE)
56             .addOptional(YangStmtMapping.STATUS)
57             .addAny(YangStmtMapping.USES)
58             .addOptional(YangStmtMapping.WHEN)
59             .build());
60     private static final @NonNull CaseStatementSupport RFC7950_INSTANCE = new CaseStatementSupport(
61         SubstatementValidator.builder(YangStmtMapping.CASE)
62             .addAny(YangStmtMapping.ANYDATA)
63             .addAny(YangStmtMapping.ANYXML)
64             .addAny(YangStmtMapping.CHOICE)
65             .addAny(YangStmtMapping.CONTAINER)
66             .addOptional(YangStmtMapping.DESCRIPTION)
67             .addAny(YangStmtMapping.IF_FEATURE)
68             .addAny(YangStmtMapping.LEAF)
69             .addAny(YangStmtMapping.LEAF_LIST)
70             .addAny(YangStmtMapping.LIST)
71             .addOptional(YangStmtMapping.REFERENCE)
72             .addOptional(YangStmtMapping.STATUS)
73             .addAny(YangStmtMapping.USES)
74             .addOptional(YangStmtMapping.WHEN)
75             .build());
76
77     private final SubstatementValidator validator;
78
79     private CaseStatementSupport(final SubstatementValidator validator) {
80         super(YangStmtMapping.CASE, instantiatedPolicy());
81         this.validator = requireNonNull(validator);
82     }
83
84     public static @NonNull CaseStatementSupport rfc6020Instance() {
85         return RFC6020_INSTANCE;
86     }
87
88     public static @NonNull CaseStatementSupport rfc7950Instance() {
89         return RFC7950_INSTANCE;
90     }
91
92     @Override
93     protected SubstatementValidator getSubstatementValidator() {
94         return validator;
95     }
96
97     @Override
98     protected CaseStatement createDeclared(final StmtContext<QName, CaseStatement, ?> ctx,
99             final ImmutableList<? extends DeclaredStatement<?>> substatements) {
100         final StatementSource source = ctx.source();
101         switch (source) {
102             case CONTEXT:
103                 return ImplicitStatements.createCase(ctx.getArgument(), substatements);
104             case DECLARATION:
105                 return DeclaredStatements.createCase(ctx.getArgument(), substatements);
106             default:
107                 throw new IllegalStateException("Unhandled statement source " + source);
108         }
109     }
110
111     @Override
112     protected CaseEffectiveStatement copyDeclaredEffective(final Current<QName, CaseStatement> stmt,
113             final CaseEffectiveStatement original) {
114         return EffectiveStatements.copyCase(original, stmt.effectivePath(),
115             computeFlags(stmt, original.effectiveSubstatements()), stmt.original(CaseSchemaNode.class));
116     }
117
118     @Override
119     protected CaseEffectiveStatement copyUndeclaredEffective(final Current<QName, CaseStatement> stmt,
120             final CaseEffectiveStatement original) {
121         return EffectiveStatements.copyCase(original, stmt.effectivePath(),
122             computeFlags(stmt, original.effectiveSubstatements()), stmt.original(CaseSchemaNode.class));
123     }
124
125     @Override
126     protected CaseEffectiveStatement createDeclaredEffective(final Current<QName, CaseStatement> stmt,
127             final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
128         try {
129             return EffectiveStatements.createCase(stmt.declared(), stmt.effectivePath(),
130                 computeFlags(stmt, substatements), substatements, stmt.original(CaseSchemaNode.class));
131         } catch (SubstatementIndexingException e) {
132             throw new SourceException(e.getMessage(), stmt, e);
133         }
134     }
135
136     @Override
137     protected CaseEffectiveStatement createUndeclaredEffective(final Current<QName, CaseStatement> stmt,
138             final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
139         try {
140             return EffectiveStatements.createCase(stmt.effectivePath(), computeFlags(stmt, substatements),
141                 substatements, stmt.original(CaseSchemaNode.class));
142         } catch (SubstatementIndexingException e) {
143             throw new SourceException(e.getMessage(), stmt, e);
144         }
145     }
146
147     private static int computeFlags(final Current<?, ?> stmt,
148             final Collection<? extends EffectiveStatement<?, ?>> substatements) {
149         final Boolean config;
150         final EffectiveConfig effective = stmt.effectiveConfig();
151         switch (effective) {
152             case FALSE:
153                 config = Boolean.FALSE;
154                 break;
155             case IGNORED:
156                 config = null;
157                 break;
158             case TRUE:
159                 final Boolean sub = substatementEffectiveConfig(substatements);
160                 config = sub != null ? sub : Boolean.TRUE;
161                 break;
162             case UNDETERMINED:
163                 config = substatementEffectiveConfig(substatements);
164                 break;
165             default:
166                 throw new IllegalStateException("Unhandled effective config " + effective);
167         }
168
169         return new FlagsBuilder()
170                 .setHistory(stmt.history())
171                 .setStatus(findFirstArgument(substatements, StatusEffectiveStatement.class, Status.CURRENT))
172                 .setConfiguration(config)
173                 .toFlags();
174     }
175
176     @SuppressFBWarnings(value = "NP_BOOLEAN_RETURN_NULL", justification = "Internal use tagged with @Nullable")
177     private static @Nullable Boolean substatementEffectiveConfig(
178             final Collection<? extends EffectiveStatement<?, ?>> substatements) {
179         for (EffectiveStatement<?, ?> stmt : substatements) {
180             if (stmt instanceof DataSchemaNode) {
181                 final Optional<Boolean> opt = ((DataSchemaNode) stmt).effectiveConfig();
182                 if (opt.isPresent()) {
183                     return opt.orElseThrow();
184                 }
185             }
186         }
187         return null;
188     }
189 }