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