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