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