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