Merge "Fix bugs in yang files."
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / impl / YangParserImpl.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.yangtools.yang.parser.impl;
9
10 import static org.opendaylight.yangtools.yang.parser.util.ParserUtils.*;
11 import static org.opendaylight.yangtools.yang.parser.util.TypeUtils.resolveType;
12 import static org.opendaylight.yangtools.yang.parser.util.TypeUtils.resolveTypeUnion;
13 import static org.opendaylight.yangtools.yang.parser.util.TypeUtils.resolveTypeUnionWithContext;
14 import static org.opendaylight.yangtools.yang.parser.util.TypeUtils.resolveTypeWithContext;
15
16 import java.io.File;
17 import java.io.FileInputStream;
18 import java.io.FileNotFoundException;
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.net.URI;
22 import java.util.*;
23
24 import org.antlr.v4.runtime.ANTLRInputStream;
25 import org.antlr.v4.runtime.CommonTokenStream;
26 import org.antlr.v4.runtime.tree.ParseTree;
27 import org.antlr.v4.runtime.tree.ParseTreeWalker;
28 import org.opendaylight.yangtools.antlrv4.code.gen.YangLexer;
29 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser;
30 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.YangContext;
31 import org.opendaylight.yangtools.yang.common.QName;
32 import org.opendaylight.yangtools.yang.model.api.*;
33 import org.opendaylight.yangtools.yang.model.parser.api.YangModelParser;
34 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
35 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
36 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
37 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
38 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
39 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
40 import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder;
41 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
42 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
43 import org.opendaylight.yangtools.yang.parser.builder.impl.*;
44 import org.opendaylight.yangtools.yang.parser.util.Comparators;
45 import org.opendaylight.yangtools.yang.parser.util.GroupingSort;
46 import org.opendaylight.yangtools.yang.parser.util.GroupingUtils;
47 import org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort;
48 import org.opendaylight.yangtools.yang.parser.util.ParserUtils;
49 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
50 import org.opendaylight.yangtools.yang.validator.YangModelBasicValidator;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53
54 import com.google.common.base.Preconditions;
55
56
57 public final class YangParserImpl implements YangModelParser {
58     private static final Logger LOG = LoggerFactory.getLogger(YangParserImpl.class);
59
60     private static final String FAIL_DEVIATION_TARGET = "Failed to find deviation target.";
61
62     @Override
63     public Set<Module> parseYangModels(final File yangFile, final File directory) {
64         Preconditions.checkState(yangFile.exists(), yangFile + " does not exists");
65         Preconditions.checkState(directory.exists(), directory + " does not exists");
66         Preconditions.checkState(directory.isDirectory(), directory + " is not a directory");
67
68         final String yangFileName = yangFile.getName();
69         final String[] fileList = directory.list();
70         Preconditions.checkNotNull(fileList, directory + " not found");
71
72         FileInputStream yangFileStream = null;
73         LinkedHashMap<InputStream, File> streamToFileMap = new LinkedHashMap<>();
74         try {
75             yangFileStream = new FileInputStream(yangFile);
76             streamToFileMap.put(yangFileStream, yangFile);
77         } catch (FileNotFoundException e) {
78             LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
79         }
80
81         for (String fileName : fileList) {
82             if (fileName.equals(yangFileName)) {
83                 continue;
84             }
85             File dependency = new File(directory, fileName);
86             try {
87                 if (dependency.isFile()) {
88                     streamToFileMap.put(new FileInputStream(dependency), dependency);
89                 }
90             } catch (FileNotFoundException e) {
91                 LOG.warn("Exception while reading yang file: " + fileName, e);
92             }
93         }
94
95         Map<InputStream, ModuleBuilder> parsedBuilders = parseBuilders(new ArrayList<>(streamToFileMap.keySet()),
96                 new HashMap<ModuleBuilder, InputStream>());
97         ModuleBuilder main = parsedBuilders.get(yangFileStream);
98
99         List<ModuleBuilder> moduleBuilders = new ArrayList<>();
100         moduleBuilders.add(main);
101         filterImports(main, new ArrayList<>(parsedBuilders.values()), moduleBuilders);
102         Collection<ModuleBuilder> result = resolveSubmodules(moduleBuilders);
103
104         // module builders sorted by dependencies
105         ModuleBuilder[] builders = new ModuleBuilder[result.size()];
106         result.toArray(builders);
107         List<ModuleBuilder> sortedBuilders = ModuleDependencySort.sort(builders);
108         LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> modules = orderModules(sortedBuilders);
109         Collection<Module> unsorted = build(modules).values();
110         return new LinkedHashSet<>(ModuleDependencySort.sort(unsorted.toArray(new Module[unsorted.size()])));
111     }
112
113     @Override
114     public Set<Module> parseYangModels(final List<File> yangFiles) {
115         Collection<Module> unsorted = parseYangModelsMapped(yangFiles).values();
116         return new LinkedHashSet<>(ModuleDependencySort.sort(unsorted.toArray(new Module[unsorted.size()])));
117     }
118
119     @Override
120     public Set<Module> parseYangModels(final List<File> yangFiles, final SchemaContext context) {
121         if (yangFiles == null) {
122             return Collections.emptySet();
123         }
124
125         final Map<InputStream, File> inputStreams = new HashMap<>();
126         for (final File yangFile : yangFiles) {
127             try {
128                 inputStreams.put(new FileInputStream(yangFile), yangFile);
129             } catch (FileNotFoundException e) {
130                 LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
131             }
132         }
133
134         List<InputStream> yangModelStreams = new ArrayList<>(inputStreams.keySet());
135         Map<ModuleBuilder, InputStream> builderToStreamMap = new HashMap<>();
136         Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangModelStreams,
137                 builderToStreamMap, null);
138
139         for (InputStream is : inputStreams.keySet()) {
140             try {
141                 is.close();
142             } catch (IOException e) {
143                 LOG.debug("Failed to close stream.");
144             }
145         }
146
147         final Collection<Module> unsorted = buildWithContext(modules, context).values();
148         if (context != null) {
149             for (Module m : context.getModules()) {
150                 if (!unsorted.contains(m)) {
151                     unsorted.add(m);
152                 }
153             }
154         }
155         return new LinkedHashSet<>(ModuleDependencySort.sort(unsorted.toArray(new Module[unsorted.size()])));
156     }
157
158     @Override
159     public Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams) {
160         Collection<Module> unsorted = parseYangModelsFromStreamsMapped(yangModelStreams).values();
161         return new LinkedHashSet<>(ModuleDependencySort.sort(unsorted.toArray(new Module[unsorted.size()])));
162     }
163
164     @Override
165     public Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams, SchemaContext context) {
166         if (yangModelStreams == null) {
167             return Collections.emptySet();
168         }
169
170         final Map<ModuleBuilder, InputStream> builderToStreamMap = new HashMap<>();
171         final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangModelStreams,
172                 builderToStreamMap, context);
173         final Set<Module> unsorted = new LinkedHashSet<>(buildWithContext(modules, context).values());
174         if (context != null) {
175             for (Module m : context.getModules()) {
176                 if (!unsorted.contains(m)) {
177                     unsorted.add(m);
178                 }
179             }
180         }
181         return new LinkedHashSet<>(ModuleDependencySort.sort(unsorted.toArray(new Module[unsorted.size()])));
182     }
183
184     @Override
185     public Map<File, Module> parseYangModelsMapped(List<File> yangFiles) {
186         if (yangFiles == null) {
187             return Collections.emptyMap();
188         }
189
190         final Map<InputStream, File> inputStreams = new HashMap<>();
191         for (final File yangFile : yangFiles) {
192             try {
193                 inputStreams.put(new FileInputStream(yangFile), yangFile);
194             } catch (FileNotFoundException e) {
195                 LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
196             }
197         }
198
199         List<InputStream> yangModelStreams = new ArrayList<>(inputStreams.keySet());
200         Map<ModuleBuilder, InputStream> builderToStreamMap = new HashMap<>();
201         Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangModelStreams, builderToStreamMap,
202                 null);
203
204         for (InputStream is : inputStreams.keySet()) {
205             try {
206                 is.close();
207             } catch (IOException e) {
208                 LOG.debug("Failed to close stream.");
209             }
210         }
211
212         Map<File, Module> result = new LinkedHashMap<>();
213         Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
214         Set<ModuleBuilder> keyset = builderToModuleMap.keySet();
215         List<ModuleBuilder> sorted = ModuleDependencySort.sort(keyset.toArray(new ModuleBuilder[keyset.size()]));
216         for (ModuleBuilder key : sorted) {
217             result.put(inputStreams.get(builderToStreamMap.get(key)), builderToModuleMap.get(key));
218         }
219         return result;
220     }
221
222     @Override
223     public Map<InputStream, Module> parseYangModelsFromStreamsMapped(final List<InputStream> yangModelStreams) {
224         if (yangModelStreams == null) {
225             return Collections.emptyMap();
226         }
227
228         Map<ModuleBuilder, InputStream> builderToStreamMap = new HashMap<>();
229         Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangModelStreams, builderToStreamMap,
230                 null);
231         Map<InputStream, Module> result = new LinkedHashMap<>();
232         Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
233         Set<ModuleBuilder> keyset = builderToModuleMap.keySet();
234         List<ModuleBuilder> sorted = ModuleDependencySort.sort(keyset.toArray(new ModuleBuilder[keyset.size()]));
235         for (ModuleBuilder key : sorted) {
236             result.put(builderToStreamMap.get(key), builderToModuleMap.get(key));
237         }
238         return result;
239     }
240
241     @Override
242     public SchemaContext resolveSchemaContext(final Set<Module> modules) {
243         return new SchemaContextImpl(modules);
244     }
245
246     private Map<InputStream, ModuleBuilder> parseModuleBuilders(List<InputStream> inputStreams,
247             Map<ModuleBuilder, InputStream> streamToBuilderMap) {
248         Map<InputStream, ModuleBuilder> modules = parseBuilders(inputStreams, streamToBuilderMap);
249         Map<InputStream, ModuleBuilder> result = resolveSubmodules(modules);
250         return result;
251     }
252
253     private Map<InputStream, ModuleBuilder> parseBuilders(List<InputStream> inputStreams,
254             Map<ModuleBuilder, InputStream> streamToBuilderMap) {
255         final ParseTreeWalker walker = new ParseTreeWalker();
256         final Map<InputStream, ParseTree> trees = parseStreams(inputStreams);
257         final Map<InputStream, ModuleBuilder> builders = new LinkedHashMap<>();
258
259         // validate yang
260         new YangModelBasicValidator(walker).validate(new ArrayList<>(trees.values()));
261
262         YangParserListenerImpl yangModelParser;
263         for (Map.Entry<InputStream, ParseTree> entry : trees.entrySet()) {
264             yangModelParser = new YangParserListenerImpl();
265             walker.walk(yangModelParser, entry.getValue());
266             ModuleBuilder moduleBuilder = yangModelParser.getModuleBuilder();
267
268             // We expect the order of trees and streams has to be the same
269             streamToBuilderMap.put(moduleBuilder, entry.getKey());
270
271             builders.put(entry.getKey(), moduleBuilder);
272         }
273
274         return builders;
275     }
276
277     private Map<InputStream, ModuleBuilder> resolveSubmodules(Map<InputStream, ModuleBuilder> builders) {
278         Map<InputStream, ModuleBuilder> modules = new HashMap<>();
279         Set<ModuleBuilder> submodules = new HashSet<>();
280         for (Map.Entry<InputStream, ModuleBuilder> entry : builders.entrySet()) {
281             ModuleBuilder moduleBuilder = entry.getValue();
282             if (moduleBuilder.isSubmodule()) {
283                 submodules.add(moduleBuilder);
284             } else {
285                 modules.put(entry.getKey(), moduleBuilder);
286             }
287         }
288
289         Collection<ModuleBuilder> values = modules.values();
290         for (ModuleBuilder submodule : submodules) {
291             for (ModuleBuilder module : values) {
292                 if (module.getName().equals(submodule.getBelongsTo())) {
293                     addSubmoduleToModule(submodule, module);
294                 }
295             }
296         }
297         return modules;
298     }
299
300     private Collection<ModuleBuilder> resolveSubmodules(Collection<ModuleBuilder> builders) {
301         Collection<ModuleBuilder> modules = new HashSet<>();
302         Set<ModuleBuilder> submodules = new HashSet<>();
303         for (ModuleBuilder moduleBuilder : builders) {
304             if (moduleBuilder.isSubmodule()) {
305                 submodules.add(moduleBuilder);
306             } else {
307                 modules.add(moduleBuilder);
308             }
309         }
310
311         for (ModuleBuilder submodule : submodules) {
312             for (ModuleBuilder module : modules) {
313                 if (module.getName().equals(submodule.getBelongsTo())) {
314                     addSubmoduleToModule(submodule, module);
315                 }
316             }
317         }
318         return modules;
319     }
320
321     private void addSubmoduleToModule(ModuleBuilder submodule, ModuleBuilder module) {
322         submodule.setParent(module);
323         module.getDirtyNodes().addAll(submodule.getDirtyNodes());
324         module.getModuleImports().addAll(submodule.getModuleImports());
325         module.getAugments().addAll(submodule.getAugments());
326         module.getAugmentBuilders().addAll(submodule.getAugmentBuilders());
327         module.getAllAugments().addAll(submodule.getAllAugments());
328         module.getChildNodeBuilders().addAll(submodule.getChildNodeBuilders());
329         module.getChildNodes().addAll(submodule.getChildNodes());
330         module.getGroupings().addAll(submodule.getGroupings());
331         module.getGroupingBuilders().addAll(submodule.getGroupingBuilders());
332         module.getTypeDefinitions().addAll(submodule.getTypeDefinitions());
333         module.getTypeDefinitionBuilders().addAll(submodule.getTypeDefinitionBuilders());
334         module.getUsesNodes().addAll(submodule.getUsesNodes());
335         module.getUsesNodeBuilders().addAll(submodule.getUsesNodeBuilders());
336         module.getAllGroupings().addAll(submodule.getAllGroupings());
337         module.getAllUsesNodes().addAll(submodule.getAllUsesNodes());
338         module.getRpcs().addAll(submodule.getRpcs());
339         module.getAddedRpcs().addAll(submodule.getAddedRpcs());
340         module.getNotifications().addAll(submodule.getNotifications());
341         module.getAddedNotifications().addAll(submodule.getAddedNotifications());
342         module.getIdentities().addAll(submodule.getIdentities());
343         module.getAddedIdentities().addAll(submodule.getAddedIdentities());
344         module.getFeatures().addAll(submodule.getFeatures());
345         module.getAddedFeatures().addAll(submodule.getAddedFeatures());
346         module.getDeviations().addAll(submodule.getDeviations());
347         module.getDeviationBuilders().addAll(submodule.getDeviationBuilders());
348         module.getExtensions().addAll(submodule.getExtensions());
349         module.getAddedExtensions().addAll(submodule.getAddedExtensions());
350         module.getUnknownNodes().addAll(submodule.getUnknownNodes());
351         module.getAllUnknownNodes().addAll(submodule.getAllUnknownNodes());
352     }
353
354     private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(final List<InputStream> yangFileStreams,
355             final Map<ModuleBuilder, InputStream> streamToBuilderMap, final SchemaContext context) {
356         Map<InputStream, ModuleBuilder> parsedBuilders = parseModuleBuilders(yangFileStreams, streamToBuilderMap);
357         ModuleBuilder[] builders = new ModuleBuilder[parsedBuilders.size()];
358         parsedBuilders.values().toArray(builders);
359
360         // module dependency graph sorted
361         List<ModuleBuilder> sorted;
362         if (context == null) {
363             sorted = ModuleDependencySort.sort(builders);
364         } else {
365             sorted = ModuleDependencySort.sortWithContext(context, builders);
366         }
367         return orderModules(sorted);
368     }
369
370     /**
371      * Order modules by name and revision.
372      *
373      * @param modules
374      *            modules to order
375      * @return modules ordered by name and revision
376      */
377     private LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> orderModules(List<ModuleBuilder> modules) {
378         final LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> result = new LinkedHashMap<>();
379         for (final ModuleBuilder builder : modules) {
380             if (builder == null) {
381                 continue;
382             }
383             final String builderName = builder.getName();
384             Date builderRevision = builder.getRevision();
385             if (builderRevision == null) {
386                 builderRevision = new Date(0L);
387             }
388             TreeMap<Date, ModuleBuilder> builderByRevision = result.get(builderName);
389             if (builderByRevision == null) {
390                 builderByRevision = new TreeMap<>();
391             }
392             builderByRevision.put(builderRevision, builder);
393             result.put(builderName, builderByRevision);
394         }
395         return result;
396     }
397
398     private void filterImports(ModuleBuilder main, List<ModuleBuilder> other, List<ModuleBuilder> filtered) {
399         Set<ModuleImport> imports = main.getModuleImports();
400
401         // if this is submodule, add parent to filtered and pick its imports
402         if (main.isSubmodule()) {
403             TreeMap<Date, ModuleBuilder> dependencies = new TreeMap<>();
404             for (ModuleBuilder mb : other) {
405                 if (mb.getName().equals(main.getBelongsTo())) {
406                     dependencies.put(mb.getRevision(), mb);
407                 }
408             }
409             ModuleBuilder parent = dependencies.get(dependencies.firstKey());
410             filtered.add(parent);
411             imports.addAll(parent.getModuleImports());
412         }
413
414         for (ModuleImport mi : imports) {
415             for (ModuleBuilder builder : other) {
416                 if (mi.getModuleName().equals(builder.getModuleName())) {
417                     if (mi.getRevision() == null) {
418                         if (!filtered.contains(builder)) {
419                             filtered.add(builder);
420                             filterImports(builder, other, filtered);
421                         }
422                     } else {
423                         if (mi.getRevision().equals(builder.getRevision())) {
424                             if (!filtered.contains(builder)) {
425                                 filtered.add(builder);
426                                 filterImports(builder, other, filtered);
427                             }
428                         }
429                     }
430                 }
431             }
432         }
433     }
434
435     private Map<InputStream, ParseTree> parseStreams(final List<InputStream> yangStreams) {
436         final Map<InputStream, ParseTree> trees = new HashMap<>();
437         for (InputStream yangStream : yangStreams) {
438             trees.put(yangStream, parseStream(yangStream));
439         }
440         return trees;
441     }
442
443     private ParseTree parseStream(final InputStream yangStream) {
444         ParseTree result = null;
445         try {
446             final ANTLRInputStream input = new ANTLRInputStream(yangStream);
447             final YangLexer lexer = new YangLexer(input);
448             final CommonTokenStream tokens = new CommonTokenStream(lexer);
449             final YangParser parser = new YangParser(tokens);
450             parser.removeErrorListeners();
451             YangErrorListener errorListener = new YangErrorListener();
452             parser.addErrorListener(errorListener);
453             result = parser.yang();
454             errorListener.validate();
455         } catch (IOException e) {
456             LOG.warn("Exception while reading yang file: " + yangStream, e);
457         }
458         return result;
459     }
460
461     public static YangContext parseStreamWithoutErrorListeners(final InputStream yangStream) {
462         YangContext result = null;
463         try {
464             final ANTLRInputStream input = new ANTLRInputStream(yangStream);
465             final YangLexer lexer = new YangLexer(input);
466             final CommonTokenStream tokens = new CommonTokenStream(lexer);
467             final YangParser parser = new YangParser(tokens);
468             parser.removeErrorListeners();
469             result = parser.yang();
470         } catch (IOException e) {
471             LOG.warn("Exception while reading yang file: " + yangStream, e);
472         }
473         return result;
474     }
475
476     private Map<ModuleBuilder, Module> build(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
477         // fix unresolved nodes
478         resolveDirtyNodes(modules);
479         resolveAugmentsTargetPath(modules, null);
480         resolveUsesTargetGrouping(modules, null);
481         resolveUsesForGroupings(modules, null);
482         resolveUsesForNodes(modules, null);
483         resolveAugments(modules, null);
484         resolveDeviations(modules);
485
486         // build
487         final Map<ModuleBuilder, Module> result = new LinkedHashMap<>();
488         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
489             for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
490                 final ModuleBuilder moduleBuilder = childEntry.getValue();
491                 final Module module = moduleBuilder.build();
492                 result.put(moduleBuilder, module);
493             }
494         }
495         return result;
496     }
497
498     private Map<ModuleBuilder, Module> buildWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
499             final SchemaContext context) {
500         // fix unresolved nodes
501         resolvedDirtyNodesWithContext(modules, context);
502         resolveAugmentsTargetPath(modules, context);
503         resolveUsesTargetGrouping(modules, context);
504         resolveUsesForGroupings(modules, context);
505         resolveUsesForNodes(modules, context);
506         resolveAugments(modules, context);
507         resolveDeviationsWithContext(modules, context);
508
509         // build
510         final Map<ModuleBuilder, Module> result = new LinkedHashMap<>();
511         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
512             for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
513                 final ModuleBuilder moduleBuilder = childEntry.getValue();
514                 final Module module = moduleBuilder.build();
515                 result.put(moduleBuilder, module);
516             }
517         }
518         return result;
519     }
520
521     private void resolveDirtyNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
522         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
523             for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
524                 final ModuleBuilder module = childEntry.getValue();
525                 resolveUnknownNodes(modules, module);
526                 resolveIdentities(modules, module);
527                 resolveDirtyNodes(modules, module);
528             }
529         }
530     }
531
532     private void resolvedDirtyNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
533             final SchemaContext context) {
534         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
535             for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
536                 final ModuleBuilder module = childEntry.getValue();
537                 resolveUnknownNodesWithContext(modules, module, context);
538                 resolveIdentitiesWithContext(modules, module, context);
539                 resolveDirtyNodesWithContext(modules, module, context);
540             }
541         }
542     }
543
544     /**
545      * Search for dirty nodes (node which contains UnknownType) and resolve
546      * unknown types.
547      *
548      * @param modules
549      *            all available modules
550      * @param module
551      *            current module
552      */
553     private void resolveDirtyNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
554         final Set<TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
555         if (!dirtyNodes.isEmpty()) {
556             for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
557                 if (nodeToResolve instanceof UnionTypeBuilder) {
558                     // special handling for union types
559                     resolveTypeUnion((UnionTypeBuilder) nodeToResolve, modules, module);
560                 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
561                     // special handling for identityref types
562                     IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
563                     IdentitySchemaNodeBuilder identity = findBaseIdentity(modules, module, idref.getBaseString(),
564                             idref.getLine());
565                     if (identity == null) {
566                         throw new YangParseException(module.getName(), idref.getLine(), "Failed to find base identity");
567                     }
568                     idref.setBaseIdentity(identity);
569                     nodeToResolve.setType(idref.build());
570                 } else {
571                     resolveType(nodeToResolve, modules, module);
572                 }
573             }
574         }
575     }
576
577     private void resolveDirtyNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
578             final ModuleBuilder module, SchemaContext context) {
579         final Set<TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
580         if (!dirtyNodes.isEmpty()) {
581             for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
582                 if (nodeToResolve instanceof UnionTypeBuilder) {
583                     // special handling for union types
584                     resolveTypeUnionWithContext((UnionTypeBuilder) nodeToResolve, modules, module, context);
585                 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
586                     // special handling for identityref types
587                     IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
588                     IdentitySchemaNodeBuilder identity = findBaseIdentity(modules, module, idref.getBaseString(),
589                             idref.getLine());
590                     idref.setBaseIdentity(identity);
591                     nodeToResolve.setType(idref.build());
592                 } else {
593                     resolveTypeWithContext(nodeToResolve, modules, module, context);
594                 }
595             }
596         }
597     }
598
599     /**
600      * Correct augment target path.
601      *
602      * @param modules
603      *            all loaded modules
604      */
605     private void resolveAugmentsTargetPath(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
606             SchemaContext context) {
607         // collect augments from all loaded modules
608         final List<AugmentationSchemaBuilder> allAugments = new ArrayList<>();
609         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
610             for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
611                 allAugments.addAll(inner.getValue().getAllAugments());
612             }
613         }
614
615         for (AugmentationSchemaBuilder augment : allAugments) {
616             setCorrectAugmentTargetPath(modules, augment, context);
617         }
618     }
619
620     private void setCorrectAugmentTargetPath(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
621             final AugmentationSchemaBuilder augment, final SchemaContext context) {
622         ModuleBuilder module = ParserUtils.getParentModule(augment);
623         SchemaPath oldSchemaPath = augment.getTargetPath();
624         List<QName> oldPath = oldSchemaPath.getPath();
625         List<QName> newPath = new ArrayList<>();
626
627         Builder parent = augment.getParent();
628         if (parent instanceof UsesNodeBuilder) {
629             DataNodeContainerBuilder usesParent = ((UsesNodeBuilder) parent).getParent();
630             newPath.addAll(usesParent.getPath().getPath());
631
632             URI ns;
633             Date revision;
634             String prefix;
635             QName baseQName = usesParent.getQName();
636             if (baseQName == null) {
637                 ModuleBuilder m = ParserUtils.getParentModule(usesParent);
638                 ns = m.getNamespace();
639                 revision = m.getRevision();
640                 prefix = m.getPrefix();
641             } else {
642                 ns = baseQName.getNamespace();
643                 revision = baseQName.getRevision();
644                 prefix = baseQName.getPrefix();
645             }
646
647             for (QName qn : oldSchemaPath.getPath()) {
648                 newPath.add(new QName(ns, revision, prefix, qn.getLocalName()));
649             }
650         } else {
651
652             for (QName qn : oldPath) {
653                 URI ns = module.getNamespace();
654                 Date rev = module.getRevision();
655                 String pref = module.getPrefix();
656                 String localPrefix = qn.getPrefix();
657                 if (localPrefix != null && !("".equals(localPrefix))) {
658                     ModuleBuilder currentModule = ParserUtils.findModuleFromBuilders(modules, module, localPrefix,
659                             augment.getLine());
660                     if (currentModule == null) {
661                         Module m = ParserUtils.findModuleFromContext(context, module, localPrefix, augment.getLine());
662                         if (m == null) {
663                             throw new YangParseException(module.getName(), augment.getLine(), "Module with prefix "
664                                     + localPrefix + " not found.");
665                         }
666                         ns = m.getNamespace();
667                         rev = m.getRevision();
668                         pref = m.getPrefix();
669                     } else {
670                         ns = currentModule.getNamespace();
671                         rev = currentModule.getRevision();
672                         pref = currentModule.getPrefix();
673                     }
674                 }
675                 newPath.add(new QName(ns, rev, pref, qn.getLocalName()));
676             }
677         }
678         augment.setTargetNodeSchemaPath(new SchemaPath(newPath, augment.getTargetPath().isAbsolute()));
679
680         for (DataSchemaNodeBuilder childNode : augment.getChildNodeBuilders()) {
681             correctPathForAugmentNodes(childNode, augment.getTargetNodeSchemaPath());
682         }
683     }
684
685     private void correctPathForAugmentNodes(DataSchemaNodeBuilder node, SchemaPath parentPath) {
686         SchemaPath newPath = ParserUtils.createSchemaPath(parentPath, node.getQName());
687         node.setPath(newPath);
688         if (node instanceof DataNodeContainerBuilder) {
689             for (DataSchemaNodeBuilder child : ((DataNodeContainerBuilder) node).getChildNodeBuilders()) {
690                 correctPathForAugmentNodes(child, node.getPath());
691             }
692         }
693         if (node instanceof ChoiceBuilder) {
694             for (ChoiceCaseBuilder child : ((ChoiceBuilder)node).getCases()) {
695                 correctPathForAugmentNodes(child, node.getPath());
696             }
697         }
698     }
699
700     /**
701      * Check augments for mandatory nodes. If the target node is in another
702      * module, then nodes added by the augmentation MUST NOT be mandatory nodes.
703      * If mandatory node is found, throw an exception.
704      *
705      * @param augments
706      *            augments to check
707      */
708     private void checkAugmentMandatoryNodes(Collection<AugmentationSchemaBuilder> augments) {
709         for (AugmentationSchemaBuilder augment : augments) {
710             String augmentPrefix = augment.getTargetPath().getPath().get(0).getPrefix();
711             ModuleBuilder module = ParserUtils.getParentModule(augment);
712             String modulePrefix = module.getPrefix();
713
714             if (augmentPrefix == null || augmentPrefix.isEmpty() || augmentPrefix.equals(modulePrefix)) {
715                 continue;
716             }
717
718             for (DataSchemaNodeBuilder childNode : augment.getChildNodeBuilders()) {
719                 if (childNode.getConstraints().isMandatory()) {
720                     throw new YangParseException(augment.getModuleName(), augment.getLine(),
721                             "Error in augment parsing: cannot augment mandatory node "
722                                     + childNode.getQName().getLocalName());
723                 }
724             }
725         }
726     }
727
728     /**
729      * Go through all augment definitions and resolve them. This method works in
730      * same way as {@link #resolveAugments(Map)} except that if target node is
731      * not found in loaded modules, it search for target node in given context.
732      *
733      * @param modules
734      *            all loaded modules
735      * @param context
736      *            SchemaContext containing already resolved modules
737      */
738     private void resolveAugments(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final SchemaContext context) {
739         List<ModuleBuilder> all = new ArrayList<>();
740         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
741             for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
742                 all.add(inner.getValue());
743             }
744         }
745
746         List<ModuleBuilder> sorted;
747         if (context == null) {
748             sorted = ModuleDependencySort.sort(all.toArray(new ModuleBuilder[all.size()]));
749         } else {
750             sorted = ModuleDependencySort.sortWithContext(context, all.toArray(new ModuleBuilder[all.size()]));
751         }
752
753         for (ModuleBuilder mb : sorted) {
754             if (mb != null) {
755                 List<AugmentationSchemaBuilder> augments = mb.getAllAugments();
756                 checkAugmentMandatoryNodes(augments);
757                 Collections.sort(augments, Comparators.AUGMENT_COMP);
758                 for (AugmentationSchemaBuilder augment : augments) {
759                     if (!(augment.isResolved())) {
760                         boolean resolved = resolveAugment(augment, mb, modules, context);
761                         if (!resolved) {
762                             throw new YangParseException(augment.getModuleName(), augment.getLine(),
763                                     "Error in augment parsing: failed to find augment target: " + augment);
764                         }
765                     }
766                 }
767             }
768         }
769     }
770
771     private boolean resolveUsesAugment(final AugmentationSchemaBuilder augment, final ModuleBuilder module,
772             final Map<String, TreeMap<Date, ModuleBuilder>> modules, final SchemaContext context) {
773         if (augment.isResolved()) {
774             return true;
775         }
776
777         UsesNodeBuilder usesNode = (UsesNodeBuilder) augment.getParent();
778         DataNodeContainerBuilder parentNode = usesNode.getParent();
779         SchemaNodeBuilder targetNode;
780         if (parentNode instanceof ModuleBuilder) {
781             targetNode = findSchemaNodeInModule(augment.getTargetPath().getPath(), (ModuleBuilder)parentNode);
782         } else {
783             targetNode = findSchemaNode(augment.getTargetPath().getPath(), (SchemaNodeBuilder)parentNode);
784         }
785
786         fillAugmentTarget(augment, targetNode);
787         augment.setResolved(true);
788         return true;
789     }
790
791     private boolean resolveAugment(final AugmentationSchemaBuilder augment, final ModuleBuilder module,
792             final Map<String, TreeMap<Date, ModuleBuilder>> modules, final SchemaContext context) {
793         if (augment.isResolved()) {
794             return true;
795         }
796
797         List<QName> targetPath = augment.getTargetPath().getPath();
798         ModuleBuilder targetModule = findTargetModule(targetPath.get(0), module, modules, context, augment.getLine());
799         if (targetModule == null) {
800             throw new YangParseException(module.getModuleName(), augment.getLine(), "Failed to resolve augment "
801                     + augment);
802         }
803
804         return processAugmentation(augment, targetModule);
805     }
806
807     /**
808      * Find module from loaded modules or from context based on given qname. If
809      * module is found in context, create wrapper over this module and add it to
810      * collection of loaded modules.
811      *
812      * @param qname
813      * @param module
814      *            current module
815      * @param modules
816      *            all loaded modules
817      * @param context
818      *            schema context
819      * @param line
820      *            current line
821      * @return
822      */
823     private ModuleBuilder findTargetModule(final QName qname, final ModuleBuilder module,
824             final Map<String, TreeMap<Date, ModuleBuilder>> modules, final SchemaContext context, final int line) {
825         ModuleBuilder targetModule = null;
826
827         String prefix = qname.getPrefix();
828         if (prefix == null || prefix.equals("")) {
829             targetModule = module;
830         } else {
831             targetModule = findModuleFromBuilders(modules, module, qname.getPrefix(), line);
832         }
833
834         if (targetModule == null && context != null) {
835             Module m = findModuleFromContext(context, module, prefix, line);
836             targetModule = new ModuleBuilder(m);
837             DataSchemaNode firstNode = m.getDataChildByName(qname.getLocalName());
838             DataSchemaNodeBuilder firstNodeWrapped = wrapChildNode(targetModule.getModuleName(), line, firstNode,
839                     targetModule.getPath(), firstNode.getQName());
840             targetModule.addChildNode(firstNodeWrapped);
841
842             TreeMap<Date, ModuleBuilder> map = new TreeMap<>();
843             map.put(targetModule.getRevision(), targetModule);
844             modules.put(targetModule.getModuleName(), map);
845         }
846
847         return targetModule;
848     }
849
850     /**
851      * Go through identity statements defined in current module and resolve
852      * their 'base' statement if present.
853      *
854      * @param modules
855      *            all modules
856      * @param module
857      *            module being resolved
858      */
859     private void resolveIdentities(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
860         final Set<IdentitySchemaNodeBuilder> identities = module.getAddedIdentities();
861         for (IdentitySchemaNodeBuilder identity : identities) {
862             final String baseIdentityName = identity.getBaseIdentityName();
863             final int line = identity.getLine();
864             if (baseIdentityName != null) {
865                 IdentitySchemaNodeBuilder baseIdentity = findBaseIdentity(modules, module, baseIdentityName, line);
866                 if (baseIdentity == null) {
867                     throw new YangParseException(module.getName(), identity.getLine(), "Failed to find base identity");
868                 } else {
869                     identity.setBaseIdentity(baseIdentity);
870                 }
871             }
872         }
873     }
874
875     /**
876      * Go through identity statements defined in current module and resolve
877      * their 'base' statement. Method tries to find base identity in given
878      * modules. If base identity is not found, method will search it in context.
879      *
880      * @param modules
881      *            all loaded modules
882      * @param module
883      *            current module
884      * @param context
885      *            SchemaContext containing already resolved modules
886      */
887     private void resolveIdentitiesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
888             final ModuleBuilder module, final SchemaContext context) {
889         final Set<IdentitySchemaNodeBuilder> identities = module.getAddedIdentities();
890         for (IdentitySchemaNodeBuilder identity : identities) {
891             final String baseIdentityName = identity.getBaseIdentityName();
892             final int line = identity.getLine();
893             if (baseIdentityName != null) {
894                 IdentitySchemaNodeBuilder baseIdentity = findBaseIdentity(modules, module, baseIdentityName, line);
895                 if (baseIdentity == null) {
896                     IdentitySchemaNode baseId = findBaseIdentityFromContext(modules, module, baseIdentityName, line,
897                             context);
898                     identity.setBaseIdentity(baseId);
899                 } else {
900                     identity.setBaseIdentity(baseIdentity);
901                 }
902             }
903         }
904     }
905
906     /**
907      * Find and add reference of uses target grouping.
908      *
909      * @param modules
910      *            all loaded modules
911      * @param context
912      *            SchemaContext containing already resolved modules or null if
913      *            context is not available
914      */
915     private void resolveUsesTargetGrouping(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
916             final SchemaContext context) {
917         final List<UsesNodeBuilder> allUses = new ArrayList<>();
918         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
919             for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
920                 allUses.addAll(inner.getValue().getAllUsesNodes());
921             }
922         }
923         for (UsesNodeBuilder usesNode : allUses) {
924             ModuleBuilder module = ParserUtils.getParentModule(usesNode);
925             final GroupingBuilder targetGroupingBuilder = GroupingUtils.getTargetGroupingFromModules(usesNode, modules,
926                     module);
927             if (targetGroupingBuilder == null) {
928                 if (context == null) {
929                     throw new YangParseException(module.getName(), usesNode.getLine(), "Referenced grouping '"
930                             + usesNode.getGroupingPathAsString() + "' not found.");
931                 } else {
932                     GroupingDefinition targetGroupingDefinition = GroupingUtils.getTargetGroupingFromContext(usesNode,
933                             module, context);
934                     usesNode.setGroupingDefinition(targetGroupingDefinition);
935                 }
936             } else {
937                 usesNode.setGrouping(targetGroupingBuilder);
938             }
939         }
940     }
941
942     private void resolveUsesForGroupings(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final SchemaContext context) {
943         final Set<GroupingBuilder> allGroupings = new HashSet<>();
944         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
945             for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
946                 ModuleBuilder module = inner.getValue();
947                 allGroupings.addAll(module.getAllGroupings());
948             }
949         }
950         final List<GroupingBuilder> sorted = GroupingSort.sort(allGroupings);
951         for (GroupingBuilder gb : sorted) {
952             List<UsesNodeBuilder> usesNodes = new ArrayList<>(GroupingSort.getAllUsesNodes(gb));
953             Collections.sort(usesNodes, new GroupingUtils.UsesComparator());
954             for (UsesNodeBuilder usesNode : usesNodes) {
955                 resolveUses(usesNode, modules, context);
956             }
957         }
958     }
959
960     private void resolveUsesForNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final SchemaContext context) {
961         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
962             for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
963                 ModuleBuilder module = inner.getValue();
964                 List<UsesNodeBuilder> usesNodes = module.getAllUsesNodes();
965                 Collections.sort(usesNodes, new GroupingUtils.UsesComparator());
966                 for (UsesNodeBuilder usesNode : usesNodes) {
967                     resolveUses(usesNode, modules, context);
968                 }
969             }
970         }
971     }
972
973     private void resolveUses(UsesNodeBuilder usesNode,
974             final Map<String, TreeMap<Date, ModuleBuilder>> modules, final SchemaContext context) {
975         if (!usesNode.isResolved()) {
976             DataNodeContainerBuilder parent = usesNode.getParent();
977             ModuleBuilder module = ParserUtils.getParentModule(parent);
978             GroupingBuilder target = GroupingUtils.getTargetGroupingFromModules(usesNode, modules, module);
979             if (target == null) {
980                 resolveUsesWithContext(usesNode);
981                 usesNode.setResolved(true);
982                 for (AugmentationSchemaBuilder augment : usesNode.getAugmentations()) {
983                     resolveUsesAugment(augment, module, modules, context);
984                 }
985             } else {
986                 parent.getChildNodeBuilders().addAll(target.instantiateChildNodes(parent));
987                 parent.getTypeDefinitionBuilders().addAll(target.instantiateTypedefs(parent));
988                 parent.getGroupingBuilders().addAll(target.instantiateGroupings(parent));
989                 parent.getUnknownNodes().addAll(target.instantiateUnknownNodes(parent));
990                 usesNode.setResolved(true);
991                 for (AugmentationSchemaBuilder augment : usesNode.getAugmentations()) {
992                     resolveUsesAugment(augment, module, modules, context);
993                 }
994             }
995             GroupingUtils.performRefine(usesNode);
996         }
997     }
998
999     private void resolveUsesWithContext(UsesNodeBuilder usesNode) {
1000         final int line = usesNode.getLine();
1001         DataNodeContainerBuilder parent = usesNode.getParent();
1002         ModuleBuilder module = ParserUtils.getParentModule(parent);
1003         SchemaPath parentPath;
1004         URI ns = null;
1005         Date rev = null;
1006         String pref = null;
1007         if (parent instanceof AugmentationSchemaBuilder || parent instanceof ModuleBuilder) {
1008             ns = module.getNamespace();
1009             rev = module.getRevision();
1010             pref = module.getPrefix();
1011             if (parent instanceof AugmentationSchemaBuilder) {
1012                 parentPath = ((AugmentationSchemaBuilder)parent).getTargetNodeSchemaPath();
1013             } else {
1014                 parentPath = ((ModuleBuilder)parent).getPath();
1015             }
1016         } else {
1017             ns = ((DataSchemaNodeBuilder) parent).getQName().getNamespace();
1018             rev = ((DataSchemaNodeBuilder) parent).getQName().getRevision();
1019             pref = ((DataSchemaNodeBuilder) parent).getQName().getPrefix();
1020             parentPath = ((DataSchemaNodeBuilder)parent).getPath();
1021         }
1022
1023         GroupingDefinition gd = usesNode.getGroupingDefinition();
1024
1025         Set<DataSchemaNodeBuilder> childNodes = wrapChildNodes(module.getModuleName(), line,
1026                 gd.getChildNodes(), parentPath, ns, rev, pref);
1027         parent.getChildNodeBuilders().addAll(childNodes);
1028         for (DataSchemaNodeBuilder childNode : childNodes) {
1029             setNodeAddedByUses(childNode);
1030         }
1031
1032         Set<TypeDefinitionBuilder> typedefs = wrapTypedefs(module.getModuleName(), line, gd, parentPath, ns,
1033                 rev, pref);
1034         parent.getTypeDefinitionBuilders().addAll(typedefs);
1035         for (TypeDefinitionBuilder typedef : typedefs) {
1036             setNodeAddedByUses(typedef);
1037         }
1038
1039         Set<GroupingBuilder> groupings = wrapGroupings(module.getModuleName(), line, usesNode
1040                 .getGroupingDefinition().getGroupings(), parentPath, ns, rev, pref);
1041         parent.getGroupingBuilders().addAll(groupings);
1042         for (GroupingBuilder gb : groupings) {
1043             setNodeAddedByUses(gb);
1044         }
1045
1046         List<UnknownSchemaNodeBuilder> unknownNodes = wrapUnknownNodes(module.getModuleName(), line,
1047                 gd.getUnknownSchemaNodes(), parentPath, ns, rev, pref);
1048         parent.getUnknownNodes().addAll(unknownNodes);
1049         for (UnknownSchemaNodeBuilder un : unknownNodes) {
1050             un.setAddedByUses(true);
1051         }
1052     }
1053
1054     private void resolveUnknownNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
1055         for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) {
1056             QName nodeType = usnb.getNodeType();
1057             try {
1058                 ModuleBuilder dependentModule = findModuleFromBuilders(modules, module, nodeType.getPrefix(),
1059                         usnb.getLine());
1060                 for (ExtensionBuilder extension : dependentModule.getAddedExtensions()) {
1061                     if (extension.getQName().getLocalName().equals(nodeType.getLocalName())) {
1062                         usnb.setNodeType(extension.getQName());
1063                         usnb.setExtensionBuilder(extension);
1064                         break;
1065                     }
1066                 }
1067             } catch (YangParseException e) {
1068                 throw new YangParseException(module.getName(), usnb.getLine(), "Failed to resolve node " + usnb
1069                         + ": no such extension definition found.", e);
1070             }
1071         }
1072     }
1073
1074     private void resolveUnknownNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1075             final ModuleBuilder module, final SchemaContext context) {
1076         for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) {
1077             QName nodeType = usnb.getNodeType();
1078             try {
1079                 ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module, nodeType.getPrefix(),
1080                         usnb.getLine());
1081
1082                 if (dependentModuleBuilder == null) {
1083                     Module dependentModule = findModuleFromContext(context, module, nodeType.getPrefix(),
1084                             usnb.getLine());
1085                     for (ExtensionDefinition e : dependentModule.getExtensionSchemaNodes()) {
1086                         if (e.getQName().getLocalName().equals(nodeType.getLocalName())) {
1087                             usnb.setNodeType(new QName(e.getQName().getNamespace(), e.getQName().getRevision(),
1088                                     nodeType.getPrefix(), e.getQName().getLocalName()));
1089                             usnb.setExtensionDefinition(e);
1090                             break;
1091                         }
1092                     }
1093                 } else {
1094                     for (ExtensionBuilder extension : dependentModuleBuilder.getAddedExtensions()) {
1095                         if (extension.getQName().getLocalName().equals(nodeType.getLocalName())) {
1096                             usnb.setExtensionBuilder(extension);
1097                             break;
1098                         }
1099                     }
1100                 }
1101
1102             } catch (YangParseException e) {
1103                 throw new YangParseException(module.getName(), usnb.getLine(), "Failed to resolve node " + usnb
1104                         + ": no such extension definition found.", e);
1105             }
1106
1107         }
1108     }
1109
1110     /**
1111      * Traverse through modules and resolve their deviation statements.
1112      *
1113      * @param modules
1114      *            all loaded modules
1115      */
1116     private void resolveDeviations(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
1117         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
1118             for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
1119                 ModuleBuilder b = inner.getValue();
1120                 resolveDeviation(modules, b);
1121             }
1122         }
1123     }
1124
1125     /**
1126      * Traverse through module and resolve its deviation statements.
1127      *
1128      * @param modules
1129      *            all loaded modules
1130      * @param module
1131      *            module in which resolve deviations
1132      */
1133     private void resolveDeviation(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
1134         for (DeviationBuilder dev : module.getDeviationBuilders()) {
1135             int line = dev.getLine();
1136             SchemaPath targetPath = dev.getTargetPath();
1137             List<QName> path = targetPath.getPath();
1138             QName q0 = path.get(0);
1139             String prefix = q0.getPrefix();
1140             if (prefix == null) {
1141                 prefix = module.getPrefix();
1142             }
1143
1144             ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module, prefix, line);
1145             processDeviation(dev, dependentModuleBuilder, path, module);
1146         }
1147     }
1148
1149     /**
1150      * Traverse through modules and resolve their deviation statements with
1151      * given context.
1152      *
1153      * @param modules
1154      *            all loaded modules
1155      * @param context
1156      *            already resolved context
1157      */
1158     private void resolveDeviationsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1159             final SchemaContext context) {
1160         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
1161             for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
1162                 ModuleBuilder b = inner.getValue();
1163                 resolveDeviationWithContext(modules, b, context);
1164             }
1165         }
1166     }
1167
1168     /**
1169      * Traverse through module and resolve its deviation statements with given
1170      * context.
1171      *
1172      * @param modules
1173      *            all loaded modules
1174      * @param module
1175      *            module in which resolve deviations
1176      * @param context
1177      *            already resolved context
1178      */
1179     private void resolveDeviationWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1180             final ModuleBuilder module, final SchemaContext context) {
1181         for (DeviationBuilder dev : module.getDeviationBuilders()) {
1182             int line = dev.getLine();
1183             SchemaPath targetPath = dev.getTargetPath();
1184             List<QName> path = targetPath.getPath();
1185             QName q0 = path.get(0);
1186             String prefix = q0.getPrefix();
1187             if (prefix == null) {
1188                 prefix = module.getPrefix();
1189             }
1190
1191             ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module, prefix, line);
1192             if (dependentModuleBuilder == null) {
1193                 Object currentParent = findModuleFromContext(context, module, prefix, line);
1194
1195                 for (QName q : path) {
1196                     if (currentParent == null) {
1197                         throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
1198                     }
1199                     String name = q.getLocalName();
1200                     if (currentParent instanceof DataNodeContainer) {
1201                         currentParent = ((DataNodeContainer) currentParent).getDataChildByName(name);
1202                     }
1203                 }
1204
1205                 if (currentParent == null) {
1206                     throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
1207                 }
1208                 if (currentParent instanceof SchemaNode) {
1209                     dev.setTargetPath(((SchemaNode) currentParent).getPath());
1210                 }
1211
1212             } else {
1213                 processDeviation(dev, dependentModuleBuilder, path, module);
1214             }
1215         }
1216     }
1217
1218     /**
1219      * Correct deviation target path in deviation builder.
1220      *
1221      * @param dev
1222      *            deviation
1223      * @param dependentModuleBuilder
1224      *            module containing deviation target
1225      * @param path
1226      *            current deviation target path
1227      * @param module
1228      *            current module
1229      */
1230     private void processDeviation(final DeviationBuilder dev, final ModuleBuilder dependentModuleBuilder,
1231             final List<QName> path, final ModuleBuilder module) {
1232         final int line = dev.getLine();
1233         Builder currentParent = dependentModuleBuilder;
1234
1235         for (QName q : path) {
1236             if (currentParent == null) {
1237                 throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
1238             }
1239             String name = q.getLocalName();
1240             if (currentParent instanceof DataNodeContainerBuilder) {
1241                 currentParent = ((DataNodeContainerBuilder) currentParent).getDataChildByName(name);
1242             }
1243         }
1244
1245         if (!(currentParent instanceof SchemaNodeBuilder)) {
1246             throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
1247         }
1248         dev.setTargetPath(((SchemaNodeBuilder) currentParent).getPath());
1249     }
1250
1251 }