Rework LeafRefValidation
[yangtools.git] / yang / yang-data-impl / src / main / java / org / opendaylight / yangtools / yang / data / impl / leafref / LeafRefContextTreeBuilder.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. 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.data.impl.leafref;
9
10 import java.util.Collection;
11 import java.util.LinkedList;
12 import java.util.List;
13 import java.util.Set;
14 import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
15 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
16 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
17 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
18 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
19 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
20 import org.opendaylight.yangtools.yang.model.api.Module;
21 import org.opendaylight.yangtools.yang.model.api.PathExpression;
22 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
23 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
24 import org.opendaylight.yangtools.yang.model.api.TypedDataSchemaNode;
25 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
26
27 final class LeafRefContextTreeBuilder {
28     private final List<LeafRefContext> leafRefs = new LinkedList<>();
29     private final SchemaContext schemaContext;
30
31     LeafRefContextTreeBuilder(final SchemaContext schemaContext) {
32         this.schemaContext = schemaContext;
33     }
34
35     LeafRefContext buildLeafRefContextTree() throws LeafRefYangSyntaxErrorException {
36         final LeafRefContextBuilder rootBuilder = new LeafRefContextBuilder(schemaContext.getQName(),
37             schemaContext.getPath(), schemaContext);
38
39         final Set<Module> modules = schemaContext.getModules();
40         for (final Module module : modules) {
41             for (final DataSchemaNode childNode : module.getChildNodes()) {
42                 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(childNode, module);
43                 if (childLeafRefContext.hasReferencingChild() || childLeafRefContext.isReferencing()) {
44                     rootBuilder.addReferencingChild(childLeafRefContext, childLeafRefContext.getNodeName());
45                 }
46             }
47         }
48
49         for (final Module module : modules) {
50             final Collection<DataSchemaNode> childNodes = module.getChildNodes();
51             for (final DataSchemaNode childNode : childNodes) {
52                 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(childNode, module);
53
54                 if (childLeafRefContext.hasReferencedChild() || childLeafRefContext.isReferenced()) {
55                     rootBuilder.addReferencedByChild(childLeafRefContext, childLeafRefContext.getNodeName());
56                 }
57             }
58         }
59
60         // FIXME: it might be useful to merge these subtrees (i.e. referencing
61         // and referencedBy subtree)
62
63         return rootBuilder.build();
64     }
65
66     private LeafRefContext buildLeafRefContextReferencingTree(final DataSchemaNode node, final Module currentModule) {
67         final LeafRefContextBuilder currentLeafRefContextBuilder = new LeafRefContextBuilder(node.getQName(),
68             node.getPath(), schemaContext);
69
70         if (node instanceof DataNodeContainer) {
71             for (final DataSchemaNode childNode : ((DataNodeContainer) node).getChildNodes()) {
72                 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(childNode, currentModule);
73                 if (childLeafRefContext.hasReferencingChild() || childLeafRefContext.isReferencing()) {
74                     currentLeafRefContextBuilder.addReferencingChild(childLeafRefContext,
75                         childLeafRefContext.getNodeName());
76                 }
77             }
78         } else if (node instanceof ChoiceSchemaNode) {
79             // :FIXME choice without case
80             for (final CaseSchemaNode caseNode : ((ChoiceSchemaNode) node).getCases().values()) {
81                 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(caseNode, currentModule);
82                 if (childLeafRefContext.hasReferencingChild() || childLeafRefContext.isReferencing()) {
83                     currentLeafRefContextBuilder.addReferencingChild(childLeafRefContext,
84                         childLeafRefContext.getNodeName());
85                 }
86             }
87
88         } else if (node instanceof TypedDataSchemaNode) {
89             final TypedDataSchemaNode typedNode = (TypedDataSchemaNode) node;
90             final TypeDefinition<?> type = typedNode.getType();
91
92             // FIXME: fix case when type is e.g. typedef -> typedef -> leafref
93             if (type instanceof LeafrefTypeDefinition) {
94                 final LeafrefTypeDefinition leafrefType = (LeafrefTypeDefinition) type;
95                 final PathExpression path = leafrefType.getPathStatement();
96                 final LeafRefPathParserImpl leafRefPathParser = new LeafRefPathParserImpl(leafrefType, typedNode);
97                 final LeafRefPath leafRefPath = leafRefPathParser.parseLeafRefPath(path);
98
99                 currentLeafRefContextBuilder.setLeafRefTargetPathString(path.getOriginalString());
100                 currentLeafRefContextBuilder.setReferencing(true);
101                 currentLeafRefContextBuilder.setLeafRefTargetPath(leafRefPath);
102
103                 final LeafRefContext currentLeafRefContext = currentLeafRefContextBuilder.build();
104                 leafRefs.add(currentLeafRefContext);
105                 return currentLeafRefContext;
106             }
107         }
108
109         return currentLeafRefContextBuilder.build();
110     }
111
112     private LeafRefContext buildLeafRefContextReferencedByTree(final DataSchemaNode node, final Module currentModule)
113             throws LeafRefYangSyntaxErrorException {
114         final LeafRefContextBuilder currentLeafRefContextBuilder = new LeafRefContextBuilder(node.getQName(),
115             node.getPath(), schemaContext);
116         if (node instanceof DataNodeContainer) {
117             for (final DataSchemaNode childNode : ((DataNodeContainer) node).getChildNodes()) {
118                 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(childNode,
119                     currentModule);
120                 if (childLeafRefContext.hasReferencedChild() || childLeafRefContext.isReferenced()) {
121                     currentLeafRefContextBuilder.addReferencedByChild(childLeafRefContext,
122                         childLeafRefContext.getNodeName());
123                 }
124             }
125         } else if (node instanceof ChoiceSchemaNode) {
126             for (final CaseSchemaNode caseNode : ((ChoiceSchemaNode) node).getCases().values()) {
127                 final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(caseNode, currentModule);
128                 if (childLeafRefContext.hasReferencedChild() || childLeafRefContext.isReferenced()) {
129                     currentLeafRefContextBuilder.addReferencedByChild(childLeafRefContext,
130                         childLeafRefContext.getNodeName());
131                 }
132             }
133         } else if (node instanceof LeafSchemaNode || node instanceof LeafListSchemaNode) {
134             final List<LeafRefContext> foundLeafRefs = getLeafRefsFor(node, currentModule);
135             if (!foundLeafRefs.isEmpty()) {
136                 currentLeafRefContextBuilder.setReferencedBy(true);
137                 for (final LeafRefContext leafRef : foundLeafRefs) {
138                     currentLeafRefContextBuilder.addReferencedByLeafRefCtx(leafRef.getNodeName(), leafRef);
139                 }
140             }
141         }
142
143         return currentLeafRefContextBuilder.build();
144     }
145
146     private List<LeafRefContext> getLeafRefsFor(final DataSchemaNode node, final Module module) {
147         final LeafRefPath nodeXPath = LeafRefUtils.schemaPathToLeafRefPath(node.getPath(), module);
148         final List<LeafRefContext> foundLeafRefs = new LinkedList<>();
149         for (final LeafRefContext leafref : leafRefs) {
150             final LeafRefPath leafRefTargetPath = leafref.getAbsoluteLeafRefTargetPath();
151             if (leafRefTargetPath.equals(nodeXPath)) {
152                 foundLeafRefs.add(leafref);
153             }
154         }
155
156         return foundLeafRefs;
157     }
158 }