Sonar issues clean-up
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / rfc6020 / AugmentUtils.java
1 /**
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  * <p/>
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.stmt.rfc6020;
9
10 import java.util.Collection;
11 import java.util.HashSet;
12 import java.util.LinkedList;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.Set;
16
17 import org.opendaylight.yangtools.yang.common.QName;
18 import org.opendaylight.yangtools.yang.common.QNameModule;
19 import org.opendaylight.yangtools.yang.model.api.Rfc6020Mapping;
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.AugmentStatement;
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.spi.NamespaceToModule;
26 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
27 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
28 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
29 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToModuleQName;
30 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
31 import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase;
32
33 public final class AugmentUtils {
34
35     private static final String REGEX_PATH_REL1 = "\\.\\.?\\s*/(.+)";
36     private static final String REGEX_PATH_REL2 = "//.*";
37
38     private AugmentUtils() {
39     }
40
41     public static Iterable<QName> parseAugmentPath(StmtContext<?, ?, ?> ctx, String path) {
42
43         if (path.matches(REGEX_PATH_REL1) || path.matches(REGEX_PATH_REL2)) {
44             throw new IllegalArgumentException(
45                     "An argument for augment can be only absolute path; or descendant if used in uses");
46         }
47
48         return Utils.parseXPath(ctx, path);
49     }
50
51     public static void copyFromSourceToTarget(StatementContextBase<?, ?, ?> sourceCtx,
52                                               StatementContextBase<?, ?, ?> targetCtx) throws SourceException {
53
54         QNameModule newQNameModule = getNewQNameModule(targetCtx, sourceCtx);
55         copyDeclaredStmts(sourceCtx, targetCtx, newQNameModule);
56         copyEffectiveStmts(sourceCtx, targetCtx, newQNameModule);
57
58     }
59
60     public static void copyDeclaredStmts(StatementContextBase<?, ?, ?> sourceCtx,
61                                          StatementContextBase<?, ?, ?> targetCtx, QNameModule newQNameModule) throws SourceException {
62         Collection<? extends StatementContextBase<?, ?, ?>> declaredSubstatements = sourceCtx.declaredSubstatements();
63         for (StatementContextBase<?, ?, ?> originalStmtCtx : declaredSubstatements) {
64             if (needToCopyByAugment(originalStmtCtx)) {
65                 StatementContextBase<?, ?, ?> copy = originalStmtCtx.createCopy(newQNameModule, targetCtx);
66                 targetCtx.addEffectiveSubstatement(copy);
67             } else if (isReusedByAugment(originalStmtCtx)) {
68                 targetCtx.addEffectiveSubstatement(originalStmtCtx);
69             }
70         }
71     }
72
73     public static void copyEffectiveStmts(StatementContextBase<?, ?, ?> sourceCtx,
74                                           StatementContextBase<?, ?, ?> targetCtx, QNameModule newQNameModule) throws SourceException {
75         Collection<? extends StatementContextBase<?, ?, ?>> effectiveSubstatements = sourceCtx.effectiveSubstatements();
76         for (StatementContextBase<?, ?, ?> originalStmtCtx : effectiveSubstatements) {
77             if (needToCopyByAugment(originalStmtCtx)) {
78                 StatementContextBase<?, ?, ?> copy = originalStmtCtx.createCopy(newQNameModule, targetCtx);
79                 targetCtx.addEffectiveSubstatement(copy);
80             } else if (isReusedByAugment(originalStmtCtx)) {
81                 targetCtx.addEffectiveSubstatement(originalStmtCtx);
82             }
83         }
84     }
85
86     public static QNameModule getNewQNameModule(StatementContextBase<?, ?, ?> targetCtx,
87                                                 StatementContextBase<?, ?, ?> sourceCtx) {
88         Object targetStmtArgument = targetCtx.getStatementArgument();
89
90         final StatementContextBase<?, ?, ?> root = sourceCtx.getRoot();
91         final String moduleName = (String) root.getStatementArgument();
92         final QNameModule sourceQNameModule = root.getFromNamespace(ModuleNameToModuleQName.class, moduleName);
93
94         if (targetStmtArgument instanceof QName) {
95             QName targetQName = (QName) targetStmtArgument;
96             QNameModule targetQNameModule = targetQName.getModule();
97
98             if (targetQNameModule.equals(sourceQNameModule)) {
99                 return null;
100             } else {
101                 return targetQNameModule;
102             }
103         } else {
104             return null;
105         }
106     }
107
108     public static boolean needToCopyByAugment(StmtContext<?, ?, ?> stmtContext) {
109
110         Set<StatementDefinition> noCopyDefSet = new HashSet<>();
111         noCopyDefSet.add(Rfc6020Mapping.USES);
112
113         StatementDefinition def = stmtContext.getPublicDefinition();
114         return !noCopyDefSet.contains(def);
115     }
116
117     public static boolean isReusedByAugment(StmtContext<?, ?, ?> stmtContext) {
118
119         Set<StatementDefinition> reusedDefSet = new HashSet<>();
120         reusedDefSet.add(Rfc6020Mapping.TYPEDEF);
121
122         StatementDefinition def = stmtContext.getPublicDefinition();
123
124         return reusedDefSet.contains(def);
125     }
126
127     public static StatementContextBase<?, ?, ?> getAugmentTargetCtx(
128             final Mutable<SchemaNodeIdentifier, AugmentStatement, EffectiveStatement<SchemaNodeIdentifier, AugmentStatement>> augmentNode) {
129
130         final SchemaNodeIdentifier augmentTargetNode = augmentNode.getStatementArgument();
131
132         List<StatementContextBase<?, ?, ?>> rootStatementCtxList = new LinkedList<>();
133
134         if (augmentTargetNode.isAbsolute()) {
135
136             QNameModule module;
137             if (augmentTargetNode != null) {
138                 module = augmentTargetNode.getPathFromRoot().iterator().next().getModule();
139             } else {
140                 throw new IllegalArgumentException(
141                         "Augment argument null, something bad happened in some of previous parsing phases");
142             }
143
144             StatementContextBase<?, ?, ?> rootStatementCtx = (StatementContextBase<?, ?, ?>) augmentNode.getFromNamespace(
145                     NamespaceToModule.class, module);
146             rootStatementCtxList.add(rootStatementCtx);
147
148             final Map<?, ?> subModules = rootStatementCtx.getAllFromNamespace(IncludedModuleContext.class);
149             if (subModules != null) {
150                 rootStatementCtxList.addAll((Collection<? extends StatementContextBase<?, ?, ?>>) subModules.values());
151             }
152
153         } else {
154             StatementContextBase<?, ?, ?> parent = (StatementContextBase<?, ?, ?>) augmentNode.getParentContext();
155             if (StmtContextUtils.producesDeclared(parent, UsesStatement.class)) {
156                 rootStatementCtxList.add(parent.getParentContext());
157             } else {
158                 //error
159             }
160         }
161
162         List<QName> augmentTargetPath = new LinkedList<>();
163
164         augmentTargetPath.addAll((Collection<? extends QName>) augmentTargetNode.getPathFromRoot());
165
166         StatementContextBase<?, ?, ?> augmentTargetCtx = null;
167         for (final StatementContextBase<?, ?, ?> rootStatementCtx : rootStatementCtxList) {
168             augmentTargetCtx = Utils.findCtxOfNodeInRoot(rootStatementCtx,
169                     augmentTargetPath);
170             if (augmentTargetCtx != null) break;
171         }
172
173
174         if (augmentTargetCtx == null) {
175
176             throw new NullPointerException(String.format(
177                     "Augment path %s not found in target model so its resulting context is null",
178                     augmentNode.rawStatementArgument()));
179
180         }
181
182         return augmentTargetCtx;
183     }
184 }