Merge "Bug 2900: Fixed incorrect instanceof check in xml codec."
[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.Set;
13
14 import org.opendaylight.yangtools.yang.common.QName;
15 import org.opendaylight.yangtools.yang.common.QNameModule;
16 import org.opendaylight.yangtools.yang.model.api.Rfc6020Mapping;
17 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
18 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
19 import org.opendaylight.yangtools.yang.model.api.stmt.AugmentStatement;
20 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
21 import org.opendaylight.yangtools.yang.parser.spi.NamespaceToModule;
22 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
23 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
24 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToModuleQName;
25 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
26 import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase;
27
28 public final class AugmentUtils {
29
30     private AugmentUtils() {
31     }
32
33     private static final String REGEX_PATH_REL1 = "\\.\\.?\\s*/(.+)";
34     private static final String REGEX_PATH_REL2 = "//.*";
35
36     public static Iterable<QName> parseAugmentPath(StmtContext<?, ?, ?> ctx, String path) {
37
38         if (path.matches(REGEX_PATH_REL1) || path.matches(REGEX_PATH_REL2)) {
39             throw new IllegalArgumentException(
40                     "An argument for augment can be only absolute path; or descendant if used in uses");
41         }
42
43         return Utils.parseXPath(ctx, path);
44     }
45
46     public static void copyFromSourceToTarget(StatementContextBase<?, ?, ?> sourceCtx,
47             StatementContextBase<?, ?, ?> targetCtx) throws SourceException {
48
49         QNameModule newQNameModule = getNewQNameModule(targetCtx, sourceCtx);
50         copyDeclaredStmts(sourceCtx, targetCtx, newQNameModule);
51         copyEffectiveStmts(sourceCtx, targetCtx, newQNameModule);
52
53     }
54
55     public static void copyDeclaredStmts(StatementContextBase<?, ?, ?> sourceCtx,
56             StatementContextBase<?, ?, ?> targetCtx, QNameModule newQNameModule) throws SourceException {
57         Collection<? extends StatementContextBase<?, ?, ?>> declaredSubstatements = sourceCtx.declaredSubstatements();
58         for (StatementContextBase<?, ?, ?> originalStmtCtx : declaredSubstatements) {
59             if (needToCopyByAugment(originalStmtCtx)) {
60                 StatementContextBase<?, ?, ?> copy = originalStmtCtx.createCopy(newQNameModule, targetCtx);
61                 targetCtx.addEffectiveSubstatement(copy);
62             } else if (isReusedByAugment(originalStmtCtx)) {
63                 targetCtx.addEffectiveSubstatement(originalStmtCtx);
64             }
65         }
66     }
67
68     public static void copyEffectiveStmts(StatementContextBase<?, ?, ?> sourceCtx,
69             StatementContextBase<?, ?, ?> targetCtx, QNameModule newQNameModule) throws SourceException {
70         Collection<? extends StatementContextBase<?, ?, ?>> effectiveSubstatements = sourceCtx.effectiveSubstatements();
71         for (StatementContextBase<?, ?, ?> originalStmtCtx : effectiveSubstatements) {
72             if (needToCopyByAugment(originalStmtCtx)) {
73                 StatementContextBase<?, ?, ?> copy = originalStmtCtx.createCopy(newQNameModule, targetCtx);
74                 targetCtx.addEffectiveSubstatement(copy);
75             } else if (isReusedByAugment(originalStmtCtx)) {
76                 targetCtx.addEffectiveSubstatement(originalStmtCtx);
77             }
78         }
79     }
80
81     public static QNameModule getNewQNameModule(StatementContextBase<?, ?, ?> targetCtx,
82             StatementContextBase<?, ?, ?> sourceCtx) {
83         Object targetStmtArgument = targetCtx.getStatementArgument();
84
85         final StatementContextBase<?, ?, ?> root = sourceCtx.getRoot();
86         final String moduleName = (String) root.getStatementArgument();
87         final QNameModule sourceQNameModule = root.getFromNamespace(ModuleNameToModuleQName.class, moduleName);
88
89         if (targetStmtArgument instanceof QName) {
90             QName targetQName = (QName) targetStmtArgument;
91             QNameModule targetQNameModule = targetQName.getModule();
92
93             if (targetQNameModule.equals(sourceQNameModule)) {
94                 return null;
95             } else {
96                 return targetQNameModule;
97             }
98         } else {
99             return null;
100         }
101     }
102
103     public static boolean needToCopyByAugment(StmtContext<?, ?, ?> stmtContext) {
104
105         Set<StatementDefinition> noCopyDefSet = new HashSet<>();
106         noCopyDefSet.add(Rfc6020Mapping.USES);
107
108         StatementDefinition def = stmtContext.getPublicDefinition();
109         return (!noCopyDefSet.contains(def));
110     }
111
112     public static boolean isReusedByAugment(StmtContext<?, ?, ?> stmtContext) {
113
114         HashSet<StatementDefinition> reusedDefSet = new HashSet<>();
115         reusedDefSet.add(Rfc6020Mapping.TYPEDEF);
116
117         StatementDefinition def = stmtContext.getPublicDefinition();
118         if (reusedDefSet.contains(def))
119             return true;
120         else
121             return false;
122     }
123
124     public static StatementContextBase<?, ?, ?> getAugmentTargetCtx(
125             final Mutable<SchemaNodeIdentifier, AugmentStatement, EffectiveStatement<SchemaNodeIdentifier, AugmentStatement>> augmentNode) {
126
127         final SchemaNodeIdentifier augmentTargetPath = augmentNode.getStatementArgument();
128
129         QNameModule module;
130         if (augmentTargetPath != null) {
131             module = augmentTargetPath.getPathFromRoot().iterator().next().getModule();
132         } else {
133             throw new IllegalArgumentException(
134                     "Augment argument null, something bad happened in some of previous parsing phases");
135         }
136
137         StatementContextBase<?, ?, ?> rootStatementCtx = (StatementContextBase<?, ?, ?>) augmentNode.getFromNamespace(
138                 NamespaceToModule.class, module);
139
140         final StatementContextBase<?, ?, ?> augmentTargetCtx = Utils.findCtxOfNodeInRoot(rootStatementCtx,
141                 augmentTargetPath);
142
143         if (augmentTargetCtx == null) {
144
145             throw new NullPointerException(String.format(
146                     "Augment path %s not found in target model so its resulting context is null",
147                     augmentNode.rawStatementArgument()));
148
149         }
150
151         return augmentTargetCtx;
152     }
153 }