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.base.Verify;
11 import com.google.common.collect.ImmutableSet;
12 import java.util.ArrayList;
13 import java.util.Collection;
14 import java.util.Optional;
16 import org.opendaylight.yangtools.yang.common.QName;
17 import org.opendaylight.yangtools.yang.common.QNameModule;
18 import org.opendaylight.yangtools.yang.common.YangVersion;
19 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
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.model.api.stmt.RefineStatement;
23 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
24 import org.opendaylight.yangtools.yang.model.api.stmt.UsesStatement;
25 import org.opendaylight.yangtools.yang.parser.rfc7950.namespace.ChildSchemaNodeNamespace;
26 import org.opendaylight.yangtools.yang.parser.rfc7950.reactor.YangValidationBundles;
27 import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractDeclaredStatement;
28 import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
29 import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException;
30 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
31 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
32 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
33 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToModuleQName;
34 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
35 import org.opendaylight.yangtools.yang.parser.spi.validation.ValidationBundlesNamespace;
36 import org.opendaylight.yangtools.yang.parser.spi.validation.ValidationBundlesNamespace.ValidationBundleType;
37 import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
41 final class UsesStatementImpl extends AbstractDeclaredStatement<QName> implements UsesStatement {
42 private static final Logger LOG = LoggerFactory.getLogger(UsesStatementImpl.class);
44 UsesStatementImpl(final StmtContext<QName, UsesStatement, ?> context) {
49 * Copy statements from a grouping to a target node.
51 * @param sourceGrpStmtCtx
52 * source grouping statement context
57 * @throws SourceException
58 * instance of SourceException
60 static void copyFromSourceToTarget(final Mutable<?, ?, ?> sourceGrpStmtCtx,
61 final StatementContextBase<?, ?, ?> targetCtx,
62 final Mutable<QName, UsesStatement, EffectiveStatement<QName, UsesStatement>> usesNode) {
63 final Collection<? extends Mutable<?, ?, ?>> declared = sourceGrpStmtCtx.mutableDeclaredSubstatements();
64 final Collection<? extends Mutable<?, ?, ?>> effective = sourceGrpStmtCtx.mutableEffectiveSubstatements();
65 final Collection<Mutable<?, ?, ?>> buffer = new ArrayList<>(declared.size() + effective.size());
66 final QNameModule newQNameModule = getNewQNameModule(targetCtx, sourceGrpStmtCtx);
68 for (final Mutable<?, ?, ?> original : declared) {
69 if (original.isSupportedByFeatures()) {
70 copyStatement(original, targetCtx, newQNameModule, buffer);
74 for (final Mutable<?, ?, ?> original : effective) {
75 copyStatement(original, targetCtx, newQNameModule, buffer);
78 targetCtx.addEffectiveSubstatements(buffer);
79 usesNode.addAsEffectOfStatement(buffer);
82 private static void copyStatement(final Mutable<?, ?, ?> original,
83 final StatementContextBase<?, ?, ?> targetCtx, final QNameModule targetModule,
84 final Collection<Mutable<?, ?, ?>> buffer) {
85 if (needToCopyByUses(original)) {
86 final Mutable<?, ?, ?> copy = targetCtx.childCopyOf(original, CopyType.ADDED_BY_USES, targetModule);
88 } else if (isReusedByUsesOnTop(original)) {
93 private static final Set<YangStmtMapping> TOP_REUSED_DEF_SET = ImmutableSet.of(
95 YangStmtMapping.TYPEDEF);
97 private static boolean isReusedByUsesOnTop(final StmtContext<?, ?, ?> stmtContext) {
98 return TOP_REUSED_DEF_SET.contains(stmtContext.getPublicDefinition());
101 private static final Set<YangStmtMapping> NOCOPY_FROM_GROUPING_SET = ImmutableSet.of(
102 YangStmtMapping.DESCRIPTION,
103 YangStmtMapping.REFERENCE,
104 YangStmtMapping.STATUS);
105 private static final Set<YangStmtMapping> REUSED_DEF_SET = ImmutableSet.of(
106 YangStmtMapping.TYPE,
107 YangStmtMapping.TYPEDEF,
108 YangStmtMapping.USES);
110 public static boolean needToCopyByUses(final StmtContext<?, ?, ?> stmtContext) {
111 final StatementDefinition def = stmtContext.getPublicDefinition();
112 if (REUSED_DEF_SET.contains(def)) {
113 LOG.trace("Will reuse {} statement {}", def, stmtContext);
116 if (NOCOPY_FROM_GROUPING_SET.contains(def)) {
117 return !YangStmtMapping.GROUPING.equals(stmtContext.coerceParentContext().getPublicDefinition());
120 LOG.trace("Will copy {} statement {}", def, stmtContext);
124 public static void resolveUsesNode(
125 final Mutable<QName, UsesStatement, EffectiveStatement<QName, UsesStatement>> usesNode,
126 final StmtContext<?, ?, ?> targetNodeStmtCtx) {
127 for (final Mutable<?, ?, ?> subStmtCtx : usesNode.mutableDeclaredSubstatements()) {
128 if (StmtContextUtils.producesDeclared(subStmtCtx, RefineStatement.class)
129 && areFeaturesSupported(subStmtCtx)) {
130 performRefine(subStmtCtx, targetNodeStmtCtx);
135 private static boolean areFeaturesSupported(final StmtContext<?, ?, ?> subStmtCtx) {
137 * In case of Yang 1.1, checks whether features are supported.
139 return !YangVersion.VERSION_1_1.equals(subStmtCtx.getRootVersion()) || subStmtCtx.isSupportedByFeatures();
142 private static void performRefine(final Mutable<?, ?, ?> subStmtCtx, final StmtContext<?, ?, ?> usesParentCtx) {
143 final Object refineArgument = subStmtCtx.getStatementArgument();
144 InferenceException.throwIf(!(refineArgument instanceof SchemaNodeIdentifier),
145 subStmtCtx.getStatementSourceReference(),
146 "Invalid refine argument %s. It must be instance of SchemaNodeIdentifier.", refineArgument);
148 final Optional<StmtContext<?, ?, ?>> optRefineTargetCtx = ChildSchemaNodeNamespace.findNode(
149 usesParentCtx, (SchemaNodeIdentifier) refineArgument);
150 InferenceException.throwIf(!optRefineTargetCtx.isPresent(), subStmtCtx.getStatementSourceReference(),
151 "Refine target node %s not found.", refineArgument);
153 final StmtContext<?, ?, ?> refineTargetNodeCtx = optRefineTargetCtx.get();
154 if (StmtContextUtils.isUnknownStatement(refineTargetNodeCtx)) {
155 LOG.trace("Refine node '{}' in uses '{}' has target node unknown statement '{}'. "
156 + "Refine has been skipped. At line: {}", subStmtCtx.getStatementArgument(),
157 subStmtCtx.coerceParentContext().getStatementArgument(),
158 refineTargetNodeCtx.getStatementArgument(), subStmtCtx.getStatementSourceReference());
159 subStmtCtx.addAsEffectOfStatement(refineTargetNodeCtx);
163 Verify.verify(refineTargetNodeCtx instanceof StatementContextBase);
164 addOrReplaceNodes(subStmtCtx, (StatementContextBase<?, ?, ?>) refineTargetNodeCtx);
165 subStmtCtx.addAsEffectOfStatement(refineTargetNodeCtx);
168 private static void addOrReplaceNodes(final Mutable<?, ?, ?> subStmtCtx,
169 final StatementContextBase<?, ?, ?> refineTargetNodeCtx) {
170 for (final Mutable<?, ?, ?> refineSubstatementCtx : subStmtCtx.mutableDeclaredSubstatements()) {
171 if (isSupportedRefineSubstatement(refineSubstatementCtx)) {
172 addOrReplaceNode(refineSubstatementCtx, refineTargetNodeCtx);
177 private static void addOrReplaceNode(final Mutable<?, ?, ?> refineSubstatementCtx,
178 final StatementContextBase<?, ?, ?> refineTargetNodeCtx) {
180 final StatementDefinition refineSubstatementDef = refineSubstatementCtx.getPublicDefinition();
182 SourceException.throwIf(!isSupportedRefineTarget(refineSubstatementCtx, refineTargetNodeCtx),
183 refineSubstatementCtx.getStatementSourceReference(),
184 "Error in module '%s' in the refine of uses '%s': can not perform refine of '%s' for the target '%s'.",
185 refineSubstatementCtx.getRoot().getStatementArgument(),
186 refineSubstatementCtx.coerceParentContext().getStatementArgument(),
187 refineSubstatementCtx.getPublicDefinition(), refineTargetNodeCtx.getPublicDefinition());
189 if (isAllowedToAddByRefine(refineSubstatementDef)) {
190 refineTargetNodeCtx.addEffectiveSubstatement(refineSubstatementCtx);
192 refineTargetNodeCtx.removeStatementFromEffectiveSubstatements(refineSubstatementDef);
193 refineTargetNodeCtx.addEffectiveSubstatement(refineSubstatementCtx);
197 private static final Set<YangStmtMapping> ALLOWED_TO_ADD_BY_REFINE_DEF_SET = ImmutableSet.of(YangStmtMapping.MUST);
199 private static boolean isAllowedToAddByRefine(final StatementDefinition publicDefinition) {
200 return ALLOWED_TO_ADD_BY_REFINE_DEF_SET.contains(publicDefinition);
203 private static boolean isSupportedRefineSubstatement(final StmtContext<?, ?, ?> refineSubstatementCtx) {
204 final Collection<?> supportedRefineSubstatements = refineSubstatementCtx.getFromNamespace(
205 ValidationBundlesNamespace.class, ValidationBundleType.SUPPORTED_REFINE_SUBSTATEMENTS);
207 return supportedRefineSubstatements == null || supportedRefineSubstatements.isEmpty()
208 || supportedRefineSubstatements.contains(refineSubstatementCtx.getPublicDefinition())
209 || StmtContextUtils.isUnknownStatement(refineSubstatementCtx);
212 private static boolean isSupportedRefineTarget(final StmtContext<?, ?, ?> refineSubstatementCtx,
213 final StmtContext<?, ?, ?> refineTargetNodeCtx) {
214 final Collection<?> supportedRefineTargets = YangValidationBundles.SUPPORTED_REFINE_TARGETS
215 .get(refineSubstatementCtx.getPublicDefinition());
217 return supportedRefineTargets == null || supportedRefineTargets.isEmpty()
218 || supportedRefineTargets.contains(refineTargetNodeCtx.getPublicDefinition());
222 private static QNameModule getNewQNameModule(final StmtContext<?, ?, ?> targetCtx,
223 final StmtContext<?, ?, ?> stmtContext) {
224 if (targetCtx.getParentContext() == null) {
225 return targetCtx.getFromNamespace(ModuleCtxToModuleQName.class, targetCtx);
227 if (targetCtx.getPublicDefinition() == YangStmtMapping.AUGMENT) {
228 return StmtContextUtils.getRootModuleQName(targetCtx);
231 final Object targetStmtArgument = targetCtx.getStatementArgument();
232 final Object sourceStmtArgument = stmtContext.getStatementArgument();
233 if (targetStmtArgument instanceof QName && sourceStmtArgument instanceof QName) {
234 return ((QName) targetStmtArgument).getModule();