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.rfc7950.stmt.uses;
10 import com.google.common.collect.ImmutableSet;
11 import java.util.ArrayList;
12 import java.util.Collection;
14 import javax.annotation.Nonnull;
15 import org.opendaylight.yangtools.yang.common.QName;
16 import org.opendaylight.yangtools.yang.common.QNameModule;
17 import org.opendaylight.yangtools.yang.common.YangVersion;
18 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
19 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
20 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
21 import org.opendaylight.yangtools.yang.model.api.stmt.AugmentStatement;
22 import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionStatement;
23 import org.opendaylight.yangtools.yang.model.api.stmt.IfFeatureStatement;
24 import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceStatement;
25 import org.opendaylight.yangtools.yang.model.api.stmt.RefineStatement;
26 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
27 import org.opendaylight.yangtools.yang.model.api.stmt.StatusStatement;
28 import org.opendaylight.yangtools.yang.model.api.stmt.UsesStatement;
29 import org.opendaylight.yangtools.yang.model.api.stmt.WhenStatement;
30 import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractDeclaredStatement;
31 import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
32 import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException;
33 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
34 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
35 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
36 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToModuleQName;
37 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
38 import org.opendaylight.yangtools.yang.parser.spi.validation.ValidationBundlesNamespace;
39 import org.opendaylight.yangtools.yang.parser.spi.validation.ValidationBundlesNamespace.ValidationBundleType;
40 import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase;
41 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.Utils;
42 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangValidationBundles;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
46 final class UsesStatementImpl extends AbstractDeclaredStatement<QName> implements UsesStatement {
47 private static final Logger LOG = LoggerFactory.getLogger(UsesStatementImpl.class);
49 UsesStatementImpl(final StmtContext<QName, UsesStatement, ?> context) {
55 public QName getName() {
60 public WhenStatement getWhenStatement() {
61 return firstDeclared(WhenStatement.class);
66 public Collection<? extends IfFeatureStatement> getIfFeatures() {
67 return allDeclared(IfFeatureStatement.class);
71 public StatusStatement getStatus() {
72 return firstDeclared(StatusStatement.class);
76 public DescriptionStatement getDescription() {
77 return firstDeclared(DescriptionStatement.class);
81 public ReferenceStatement getReference() {
82 return firstDeclared(ReferenceStatement.class);
87 public Collection<? extends AugmentStatement> getAugments() {
88 return allDeclared(AugmentStatement.class);
93 public Collection<? extends RefineStatement> getRefines() {
94 return allDeclared(RefineStatement.class);
98 * Copy statements from a grouping to a target node.
100 * @param sourceGrpStmtCtx
101 * source grouping statement context
106 * @throws SourceException
107 * instance of SourceException
109 static void copyFromSourceToTarget(final Mutable<?, ?, ?> sourceGrpStmtCtx,
110 final StatementContextBase<?, ?, ?> targetCtx,
111 final Mutable<QName, UsesStatement, EffectiveStatement<QName, UsesStatement>> usesNode) {
112 final Collection<? extends Mutable<?, ?, ?>> declared = sourceGrpStmtCtx.mutableDeclaredSubstatements();
113 final Collection<? extends Mutable<?, ?, ?>> effective = sourceGrpStmtCtx.mutableEffectiveSubstatements();
114 final Collection<Mutable<?, ?, ?>> buffer = new ArrayList<>(declared.size() + effective.size());
115 final QNameModule newQNameModule = getNewQNameModule(targetCtx, sourceGrpStmtCtx);
117 for (final Mutable<?, ?, ?> original : declared) {
118 if (original.isSupportedByFeatures()) {
119 copyStatement(original, targetCtx, newQNameModule, buffer);
123 for (final Mutable<?, ?, ?> original : effective) {
124 copyStatement(original, targetCtx, newQNameModule, buffer);
127 targetCtx.addEffectiveSubstatements(buffer);
128 usesNode.addAsEffectOfStatement(buffer);
131 private static void copyStatement(final Mutable<?, ?, ?> original,
132 final StatementContextBase<?, ?, ?> targetCtx, final QNameModule targetModule,
133 final Collection<Mutable<?, ?, ?>> buffer) {
134 if (needToCopyByUses(original)) {
135 final Mutable<?, ?, ?> copy = targetCtx.childCopyOf(original, CopyType.ADDED_BY_USES, targetModule);
137 } else if (isReusedByUsesOnTop(original)) {
138 buffer.add(original);
142 private static final Set<YangStmtMapping> TOP_REUSED_DEF_SET = ImmutableSet.of(
143 YangStmtMapping.TYPE,
144 YangStmtMapping.TYPEDEF);
146 private static boolean isReusedByUsesOnTop(final StmtContext<?, ?, ?> stmtContext) {
147 return TOP_REUSED_DEF_SET.contains(stmtContext.getPublicDefinition());
150 private static final Set<YangStmtMapping> NOCOPY_FROM_GROUPING_SET = ImmutableSet.of(
151 YangStmtMapping.DESCRIPTION,
152 YangStmtMapping.REFERENCE,
153 YangStmtMapping.STATUS);
154 private static final Set<YangStmtMapping> REUSED_DEF_SET = ImmutableSet.of(
155 YangStmtMapping.TYPE,
156 YangStmtMapping.TYPEDEF,
157 YangStmtMapping.USES);
159 public static boolean needToCopyByUses(final StmtContext<?, ?, ?> stmtContext) {
160 final StatementDefinition def = stmtContext.getPublicDefinition();
161 if (REUSED_DEF_SET.contains(def)) {
162 LOG.debug("Will reuse {} statement {}", def, stmtContext);
165 if (NOCOPY_FROM_GROUPING_SET.contains(def)) {
166 return !YangStmtMapping.GROUPING.equals(stmtContext.getParentContext().getPublicDefinition());
169 LOG.debug("Will copy {} statement {}", def, stmtContext);
173 public static void resolveUsesNode(
174 final Mutable<QName, UsesStatement, EffectiveStatement<QName, UsesStatement>> usesNode,
175 final StmtContext<?, ?, ?> targetNodeStmtCtx) {
176 for (final Mutable<?, ?, ?> subStmtCtx : usesNode.mutableDeclaredSubstatements()) {
177 if (StmtContextUtils.producesDeclared(subStmtCtx, RefineStatement.class)
178 && areFeaturesSupported(subStmtCtx)) {
179 performRefine(subStmtCtx, targetNodeStmtCtx);
184 private static boolean areFeaturesSupported(final StmtContext<?, ?, ?> subStmtCtx) {
186 * In case of Yang 1.1, checks whether features are supported.
188 return !YangVersion.VERSION_1_1.equals(subStmtCtx.getRootVersion()) || subStmtCtx.isSupportedByFeatures();
191 private static void performRefine(final Mutable<?, ?, ?> subStmtCtx, final StmtContext<?, ?, ?> usesParentCtx) {
193 final Object refineArgument = subStmtCtx.getStatementArgument();
194 InferenceException.throwIf(!(refineArgument instanceof SchemaNodeIdentifier),
195 subStmtCtx.getStatementSourceReference(),
196 "Invalid refine argument %s. It must be instance of SchemaNodeIdentifier.", refineArgument);
198 final SchemaNodeIdentifier refineTargetNodeIdentifier = (SchemaNodeIdentifier) refineArgument;
199 final StatementContextBase<?, ?, ?> refineTargetNodeCtx = Utils.findNode(usesParentCtx,
200 refineTargetNodeIdentifier);
202 InferenceException.throwIfNull(refineTargetNodeCtx, subStmtCtx.getStatementSourceReference(),
203 "Refine target node %s not found.", refineTargetNodeIdentifier);
205 if (StmtContextUtils.isUnknownStatement(refineTargetNodeCtx)) {
206 LOG.debug("Refine node '{}' in uses '{}' has target node unknown statement '{}'. "
207 + "Refine has been skipped. At line: {}", subStmtCtx.getStatementArgument(),
208 subStmtCtx.getParentContext().getStatementArgument(),
209 refineTargetNodeCtx.getStatementArgument(), subStmtCtx.getStatementSourceReference());
210 subStmtCtx.addAsEffectOfStatement(refineTargetNodeCtx);
214 addOrReplaceNodes(subStmtCtx, refineTargetNodeCtx);
215 subStmtCtx.addAsEffectOfStatement(refineTargetNodeCtx);
218 private static void addOrReplaceNodes(final Mutable<?, ?, ?> subStmtCtx,
219 final StatementContextBase<?, ?, ?> refineTargetNodeCtx) {
220 for (final Mutable<?, ?, ?> refineSubstatementCtx : subStmtCtx.mutableDeclaredSubstatements()) {
221 if (isSupportedRefineSubstatement(refineSubstatementCtx)) {
222 addOrReplaceNode(refineSubstatementCtx, refineTargetNodeCtx);
227 private static void addOrReplaceNode(final Mutable<?, ?, ?> refineSubstatementCtx,
228 final StatementContextBase<?, ?, ?> refineTargetNodeCtx) {
230 final StatementDefinition refineSubstatementDef = refineSubstatementCtx.getPublicDefinition();
232 SourceException.throwIf(!isSupportedRefineTarget(refineSubstatementCtx, refineTargetNodeCtx),
233 refineSubstatementCtx.getStatementSourceReference(),
234 "Error in module '%s' in the refine of uses '%s': can not perform refine of '%s' for the target '%s'.",
235 refineSubstatementCtx.getRoot().getStatementArgument(), refineSubstatementCtx.getParentContext()
236 .getStatementArgument(), refineSubstatementCtx.getPublicDefinition(), refineTargetNodeCtx
237 .getPublicDefinition());
239 if (isAllowedToAddByRefine(refineSubstatementDef)) {
240 refineTargetNodeCtx.addEffectiveSubstatement(refineSubstatementCtx);
242 refineTargetNodeCtx.removeStatementFromEffectiveSubstatements(refineSubstatementDef);
243 refineTargetNodeCtx.addEffectiveSubstatement(refineSubstatementCtx);
247 private static final Set<YangStmtMapping> ALLOWED_TO_ADD_BY_REFINE_DEF_SET = ImmutableSet.of(YangStmtMapping.MUST);
249 private static boolean isAllowedToAddByRefine(final StatementDefinition publicDefinition) {
250 return ALLOWED_TO_ADD_BY_REFINE_DEF_SET.contains(publicDefinition);
253 private static boolean isSupportedRefineSubstatement(final StmtContext<?, ?, ?> refineSubstatementCtx) {
254 final Collection<?> supportedRefineSubstatements = refineSubstatementCtx.getFromNamespace(
255 ValidationBundlesNamespace.class, ValidationBundleType.SUPPORTED_REFINE_SUBSTATEMENTS);
257 return supportedRefineSubstatements == null || supportedRefineSubstatements.isEmpty()
258 || supportedRefineSubstatements.contains(refineSubstatementCtx.getPublicDefinition())
259 || StmtContextUtils.isUnknownStatement(refineSubstatementCtx);
262 private static boolean isSupportedRefineTarget(final StmtContext<?, ?, ?> refineSubstatementCtx,
263 final StmtContext<?, ?, ?> refineTargetNodeCtx) {
264 final Collection<?> supportedRefineTargets = YangValidationBundles.SUPPORTED_REFINE_TARGETS
265 .get(refineSubstatementCtx.getPublicDefinition());
267 return supportedRefineTargets == null || supportedRefineTargets.isEmpty()
268 || supportedRefineTargets.contains(refineTargetNodeCtx.getPublicDefinition());
272 private static QNameModule getNewQNameModule(final StmtContext<?, ?, ?> targetCtx,
273 final StmtContext<?, ?, ?> stmtContext) {
274 if (targetCtx.getParentContext() == null) {
275 return targetCtx.getFromNamespace(ModuleCtxToModuleQName.class, targetCtx);
277 if (targetCtx.getPublicDefinition() == YangStmtMapping.AUGMENT) {
278 return StmtContextUtils.getRootModuleQName(targetCtx);
281 final Object targetStmtArgument = targetCtx.getStatementArgument();
282 final Object sourceStmtArgument = stmtContext.getStatementArgument();
283 if (targetStmtArgument instanceof QName && sourceStmtArgument instanceof QName) {
284 return ((QName) targetStmtArgument).getModule();