Added uses to extends list.
[controller.git] / opendaylight / sal / yang-prototype / yang / yang-model-util / src / main / java / org / opendaylight / controller / yang / model / util / SchemaContextUtil.java
1 /*
2  * Copyright (c) 2013 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.controller.yang.model.util;
9
10 import java.net.URI;
11 import java.util.LinkedList;
12 import java.util.List;
13 import java.util.Queue;
14 import java.util.Set;
15
16 import org.opendaylight.controller.yang.common.QName;
17 import org.opendaylight.controller.yang.model.api.*;
18
19 public final class SchemaContextUtil {
20
21     private SchemaContextUtil() {
22     }
23
24     public static DataSchemaNode findDataSchemaNode(final SchemaContext context, final SchemaPath schemaPath) {
25         if (schemaPath != null) {
26             final Module module = resolveModuleFromSchemaPath(context, schemaPath);
27             final Queue<QName> prefixedPath = new LinkedList<>(schemaPath.getPath());
28
29             if ((module != null) && (prefixedPath != null)) {
30                 return findSchemaNodeForGivenPath(context, module, prefixedPath);
31             }
32         }
33         return null;
34     }
35
36     public static DataSchemaNode findDataSchemaNode(final SchemaContext context, final Module module,
37             final RevisionAwareXPath nonCondXPath) {
38         if (nonCondXPath != null) {
39             final String strXPath = nonCondXPath.toString();
40
41             if (strXPath != null) {
42                 if (strXPath.matches(".*//[.* | .*//].*")) {
43                     // TODO: function to escape conditions in path
44                 }
45                 if (nonCondXPath.isAbsolute()) {
46                     final Queue<QName> qnamedPath = xpathToQNamePath(context, module, strXPath);
47                     if (qnamedPath != null) {
48                         final DataSchemaNode dataNode = findSchemaNodeForGivenPath(context, module, qnamedPath);
49                         return dataNode;
50                     }
51                 }
52             }
53         }
54         return null;
55     }
56
57     public static DataSchemaNode findDataSchemaNodeForRelativeXPath(final SchemaContext context, final Module module,
58             final SchemaNode actualSchemaNode, final RevisionAwareXPath relativeXPath) {
59         if ((actualSchemaNode != null) && (relativeXPath != null) && !relativeXPath.isAbsolute()) {
60
61             final SchemaPath actualNodePath = actualSchemaNode.getPath();
62             if (actualNodePath != null) {
63                 final Queue<QName> qnamePath = resolveRelativeXPath(context, module, relativeXPath, actualNodePath);
64
65                 if (qnamePath != null) {
66                     final DataSchemaNode dataNode = findSchemaNodeForGivenPath(context, module, qnamePath);
67                     return dataNode;
68                 }
69             }
70         }
71
72         return null;
73     }
74
75     private static Module resolveModuleFromSchemaPath(final SchemaContext context, final SchemaPath schemaPath) {
76         if ((schemaPath != null) && (schemaPath.getPath() != null)) {
77             final List<QName> path = schemaPath.getPath();
78             if (!path.isEmpty()) {
79                 final QName qname = path.get(path.size() - 1);
80
81                 if ((qname != null) && (qname.getNamespace() != null)) {
82                     return context.findModuleByNamespace(qname.getNamespace());
83                 }
84             }
85         }
86         return null;
87     }
88
89     public static Module findParentModuleForTypeDefinition(final SchemaContext context, final TypeDefinition<?> type) {
90         final SchemaPath schemaPath = type.getPath();
91         if ((schemaPath != null) && (schemaPath.getPath() != null)) {
92             if (type instanceof ExtendedType) {
93                 List<QName> path = schemaPath.getPath();
94                 final QName qname = path.get(path.size() - 1);
95
96                 if ((qname != null) && (qname.getNamespace() != null)) {
97                     return context.findModuleByNamespace(qname.getNamespace());
98                 }
99             } else {
100                 List<QName> path = schemaPath.getPath();
101                 final QName qname = path.get(path.size() - 2);
102
103                 if ((qname != null) && (qname.getNamespace() != null)) {
104                     return context.findModuleByNamespace(qname.getNamespace());
105                 }
106             }
107
108         }
109         return null;
110     }
111
112     public static Module findParentModule(final SchemaContext context, final SchemaNode schemaNode) {
113         if (context == null) {
114             throw new IllegalArgumentException("Schema Context reference cannot be NULL!");
115         }
116         if (schemaNode == null) {
117             throw new IllegalArgumentException("Schema Node cannot be NULL!");
118         }
119
120         final SchemaPath schemaPath = schemaNode.getPath();
121         if (schemaPath == null) {
122             throw new IllegalStateException("Schema Path for Schema Node is not "
123                     + "set properly (Schema Path is NULL)");
124         }
125         final List<QName> qnamedPath = schemaPath.getPath();
126         if (qnamedPath == null || qnamedPath.isEmpty()) {
127             throw new IllegalStateException("Schema Path contains invalid state of path parts."
128                     + "The Schema Path MUST contain at least ONE QName which defines namespace and Local name"
129                     + "of path.");
130         }
131         final QName qname = qnamedPath.get(qnamedPath.size() - 1);
132         return context.findModuleByNamespace(qname.getNamespace());
133     }
134
135     private static DataSchemaNode findSchemaNodeForGivenPath(final SchemaContext context, final Module module,
136             final Queue<QName> qnamedPath) {
137         if ((module != null) && (module.getNamespace() != null) && (qnamedPath != null)) {
138             DataNodeContainer nextNode = module;
139             final URI moduleNamespace = module.getNamespace();
140
141             QName childNodeQName;
142             DataSchemaNode schemaNode = null;
143             while ((nextNode != null) && !qnamedPath.isEmpty()) {
144                 childNodeQName = qnamedPath.peek();
145                 if (childNodeQName != null) {
146                     final URI childNodeNamespace = childNodeQName.getNamespace();
147
148                     schemaNode = nextNode.getDataChildByName(childNodeQName);
149                     if (schemaNode != null) {
150                         if (schemaNode instanceof ContainerSchemaNode) {
151                             nextNode = (ContainerSchemaNode) schemaNode;
152                         } else if (schemaNode instanceof ListSchemaNode) {
153                             nextNode = (ListSchemaNode) schemaNode;
154                         } else if (schemaNode instanceof ChoiceNode) {
155                             final ChoiceNode choice = (ChoiceNode) schemaNode;
156                             qnamedPath.poll();
157                             if (!qnamedPath.isEmpty()) {
158                                 childNodeQName = qnamedPath.peek();
159                                 nextNode = choice.getCaseNodeByName(childNodeQName);
160                                 schemaNode = (DataSchemaNode)nextNode;
161                             }
162                         } else {
163                             nextNode = null;
164                         }
165                     } else if (!childNodeNamespace.equals(moduleNamespace)) {
166                         final Module nextModule = context.findModuleByNamespace(childNodeNamespace);
167                         schemaNode = findSchemaNodeForGivenPath(context, nextModule, qnamedPath);
168                         return schemaNode;
169                     }
170                     qnamedPath.poll();
171                 }
172             }
173             return schemaNode;
174         }
175         return null;
176     }
177
178     private static Queue<QName> xpathToQNamePath(final SchemaContext context, final Module parentModule,
179             final String xpath) {
180         final Queue<QName> path = new LinkedList<>();
181         if (xpath != null) {
182             final String[] prefixedPath = xpath.split("/");
183
184             for (int i = 0; i < prefixedPath.length; ++i) {
185                 if (!prefixedPath[i].isEmpty()) {
186                     path.add(stringPathPartToQName(context, parentModule, prefixedPath[i]));
187                 }
188             }
189         }
190         return path;
191     }
192
193     private static QName stringPathPartToQName(final SchemaContext context, final Module parentModule,
194             final String prefixedPathPart) {
195         if (parentModule != null && prefixedPathPart != null) {
196             if (prefixedPathPart.contains(":")) {
197                 final String[] prefixedName = prefixedPathPart.split(":");
198                 final Module module = resolveModuleForPrefix(context, parentModule, prefixedName[0]);
199                 if (module != null) {
200                     return new QName(module.getNamespace(), module.getRevision(), prefixedName[1]);
201                 }
202             } else {
203                 return new QName(parentModule.getNamespace(), parentModule.getRevision(), prefixedPathPart);
204             }
205         }
206         return null;
207     }
208
209     private static Module resolveModuleForPrefix(final SchemaContext context, final Module module, final String prefix) {
210         if ((module != null) && (prefix != null)) {
211             if (prefix.equals(module.getPrefix())) {
212                 return module;
213             }
214
215             final Set<ModuleImport> imports = module.getImports();
216
217             for (final ModuleImport mi : imports) {
218                 if (prefix.equals(mi.getPrefix())) {
219                     return context.findModuleByName(mi.getModuleName(), mi.getRevision());
220                 }
221             }
222         }
223         return null;
224     }
225
226     private static Queue<QName> resolveRelativeXPath(final SchemaContext context, final Module module,
227             final RevisionAwareXPath relativeXPath, final SchemaPath leafrefSchemaPath) {
228         final Queue<QName> absolutePath = new LinkedList<>();
229
230         if ((module != null) && (relativeXPath != null) && !relativeXPath.isAbsolute() && (leafrefSchemaPath != null)) {
231             final String strXPath = relativeXPath.toString();
232             if (strXPath != null) {
233                 final String[] xpaths = strXPath.split("/");
234
235                 if (xpaths != null) {
236                     int colCount = 0;
237                     while (xpaths[colCount].contains("..")) {
238                         ++colCount;
239                     }
240                     final List<QName> path = leafrefSchemaPath.getPath();
241                     if (path != null) {
242                         int lenght = path.size() - colCount - 1;
243                         for (int i = 0; i < lenght; ++i) {
244                             absolutePath.add(path.get(i));
245                         }
246                         for (int i = colCount; i < xpaths.length; ++i) {
247                             absolutePath.add(stringPathPartToQName(context, module, xpaths[i]));
248                         }
249                     }
250                 }
251             }
252         }
253         return absolutePath;
254     }
255 }