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