Added 'code-generator' and 'model' projects from controller project.
[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                     throw new YangParseException("Failed to resolve augments in module '" + module.getName() + "'.", e);
434                 }
435                 // then try to resolve first module again
436                 resolveAugment(modules, module);
437             }
438         }
439     }
440
441     /**
442      * Tries to resolve augments in given module. If augment target node is not
443      * found, do nothing.
444      *
445      * @param modules
446      *            all available modules
447      * @param module
448      *            current module
449      */
450     private void resolveAugment(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
451         if (module.getAugmentsResolved() < module.getAllAugments().size()) {
452             for (AugmentationSchemaBuilder augmentBuilder : module.getAllAugments()) {
453
454                 if (!augmentBuilder.isResolved()) {
455                     final SchemaPath augmentTargetSchemaPath = augmentBuilder.getTargetPath();
456                     final List<QName> path = augmentTargetSchemaPath.getPath();
457
458                     final QName qname = path.get(0);
459                     String prefix = qname.getPrefix();
460                     if (prefix == null) {
461                         prefix = module.getPrefix();
462                     }
463
464                     final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, prefix,
465                             augmentBuilder.getLine());
466                     processAugmentation(augmentBuilder, path, module, dependentModule);
467                 }
468
469             }
470         }
471     }
472
473     /**
474      * Go through all augment definitions and resolve them. This method works in
475      * same way as {@link #resolveAugments(Map)} except that if target node is
476      * not found in loaded modules, it search for target node in given context.
477      *
478      * @param modules
479      *            all loaded modules
480      * @param context
481      *            SchemaContext containing already resolved modules
482      */
483     private void resolveAugmentsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
484             final SchemaContext context) {
485         final List<ModuleBuilder> allModulesList = new ArrayList<ModuleBuilder>();
486         final Set<ModuleBuilder> allModulesSet = new HashSet<ModuleBuilder>();
487         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
488             for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
489                 allModulesList.add(inner.getValue());
490                 allModulesSet.add(inner.getValue());
491             }
492         }
493
494         for (int i = 0; i < allModulesList.size(); i++) {
495             final ModuleBuilder module = allModulesList.get(i);
496             // try to resolve augments in module
497             resolveAugmentWithContext(modules, module, context);
498             // while all augments are not resolved
499             final Iterator<ModuleBuilder> allModulesIterator = allModulesSet.iterator();
500             while (!(module.getAugmentsResolved() == module.getAllAugments().size())) {
501                 ModuleBuilder nextModule = null;
502                 // try resolve other module augments
503                 try {
504                     nextModule = allModulesIterator.next();
505                     resolveAugmentWithContext(modules, nextModule, context);
506                 } catch (NoSuchElementException e) {
507                     throw new YangParseException("Failed to resolve augments in module '" + module.getName() + "'.", e);
508                 }
509                 // then try to resolve first module again
510                 resolveAugmentWithContext(modules, module, context);
511             }
512         }
513     }
514
515     /**
516      * Tries to resolve augments in given module. If augment target node is not
517      * found, do nothing.
518      *
519      * @param modules
520      *            all available modules
521      * @param module
522      *            current module
523      */
524     private void resolveAugmentWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
525             final ModuleBuilder module, final SchemaContext context) {
526         if (module.getAugmentsResolved() < module.getAllAugments().size()) {
527
528             for (AugmentationSchemaBuilder augmentBuilder : module.getAllAugments()) {
529                 final int line = augmentBuilder.getLine();
530
531                 if (!augmentBuilder.isResolved()) {
532                     final List<QName> path = augmentBuilder.getTargetPath().getPath();
533                     final QName qname = path.get(0);
534                     String prefix = qname.getPrefix();
535                     if (prefix == null) {
536                         prefix = module.getPrefix();
537                     }
538
539                     // try to find augment target module in loaded modules...
540                     final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix,
541                             line);
542                     if (dependentModuleBuilder == null) {
543                         // perform augmentation on module from context and
544                         // continue to next augment
545                         processAugmentationOnContext(augmentBuilder, path, module, prefix, line, context);
546                         continue;
547                     } else {
548                         processAugmentation(augmentBuilder, path, module, dependentModuleBuilder);
549                     }
550                 }
551
552             }
553         }
554     }
555
556     /**
557      * Go through identity statements defined in current module and resolve
558      * their 'base' statement if present.
559      *
560      * @param modules
561      *            all modules
562      * @param module
563      *            module being resolved
564      */
565     private void resolveIdentities(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
566         final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
567         for (IdentitySchemaNodeBuilder identity : identities) {
568             final String baseIdentityName = identity.getBaseIdentityName();
569             if (baseIdentityName != null) {
570                 String baseIdentityPrefix = null;
571                 String baseIdentityLocalName = null;
572                 if (baseIdentityName.contains(":")) {
573                     final String[] splitted = baseIdentityName.split(":");
574                     baseIdentityPrefix = splitted[0];
575                     baseIdentityLocalName = splitted[1];
576                 } else {
577                     baseIdentityPrefix = module.getPrefix();
578                     baseIdentityLocalName = baseIdentityName;
579                 }
580                 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, baseIdentityPrefix,
581                         identity.getLine());
582
583                 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule.getIdentities();
584                 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
585                     if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
586                         identity.setBaseIdentity(idBuilder);
587                     }
588                 }
589             }
590         }
591     }
592
593     /**
594      * Go through identity statements defined in current module and resolve
595      * their 'base' statement. Method tries to find base identity in given
596      * modules. If base identity is not found, method will search it in context.
597      *
598      * @param modules
599      *            all loaded modules
600      * @param module
601      *            current module
602      * @param context
603      *            SchemaContext containing already resolved modules
604      */
605     private void resolveIdentitiesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
606             final ModuleBuilder module, final SchemaContext context) {
607         final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
608         for (IdentitySchemaNodeBuilder identity : identities) {
609             final String baseIdentityName = identity.getBaseIdentityName();
610             if (baseIdentityName != null) {
611                 String baseIdentityPrefix = null;
612                 String baseIdentityLocalName = null;
613                 if (baseIdentityName.contains(":")) {
614                     final String[] splitted = baseIdentityName.split(":");
615                     baseIdentityPrefix = splitted[0];
616                     baseIdentityLocalName = splitted[1];
617                 } else {
618                     baseIdentityPrefix = module.getPrefix();
619                     baseIdentityLocalName = baseIdentityName;
620                 }
621                 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
622                         baseIdentityPrefix, identity.getLine());
623
624                 if (dependentModuleBuilder == null) {
625                     final Module dependentModule = findModuleFromContext(context, module, baseIdentityPrefix,
626                             identity.getLine());
627                     final Set<IdentitySchemaNode> dependentModuleIdentities = dependentModule.getIdentities();
628                     for (IdentitySchemaNode idNode : dependentModuleIdentities) {
629                         if (idNode.getQName().getLocalName().equals(baseIdentityLocalName)) {
630                             identity.setBaseIdentity(idNode);
631                         }
632                     }
633                 } else {
634                     final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModuleBuilder
635                             .getIdentities();
636                     for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
637                         if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
638                             identity.setBaseIdentity(idBuilder);
639                         }
640                     }
641                 }
642             }
643         }
644     }
645
646     /**
647      * Go through uses statements defined in current module and resolve their
648      * refine statements.
649      *
650      * @param modules
651      *            all modules
652      * @param module
653      *            module being resolved
654      */
655     private void resolveUsesNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
656         final List<UsesNodeBuilder> allModuleUses = module.getAllUsesNodes();
657         for (UsesNodeBuilder usesNode : allModuleUses) {
658             // process uses operation
659             final GroupingBuilder targetGrouping = getTargetGroupingFromModules(usesNode, modules, module);
660             usesNode.setGroupingPath(targetGrouping.getPath());
661             processUsesNode(module, usesNode, targetGrouping);
662             // refine
663             for (RefineHolder refine : usesNode.getRefines()) {
664                 DataSchemaNodeBuilder nodeToRefine = null;
665                 for (DataSchemaNodeBuilder dsnb : usesNode.getTargetChildren()) {
666                     if (refine.getName().equals(dsnb.getQName().getLocalName())) {
667                         nodeToRefine = dsnb;
668                         break;
669                     }
670                 }
671                 if (nodeToRefine == null) {
672                     throw new YangParseException(refine.getModuleName(), refine.getLine(), "Refine target node '"
673                             + refine.getName() + "' not found");
674                 }
675                 if (nodeToRefine instanceof GroupingMember) {
676                     ((GroupingMember) nodeToRefine).setAddedByUses(true);
677                 }
678                 RefineUtils.performRefine(nodeToRefine, refine);
679                 usesNode.addRefineNode(nodeToRefine);
680             }
681         }
682         for (UsesNodeBuilder usesNode : allModuleUses) {
683             final GroupingBuilder targetGrouping = getTargetGroupingFromModules(usesNode, modules, module);
684             processUsesTarget(module, usesNode, targetGrouping);
685         }
686     }
687
688     /**
689      * Tries to search target grouping in given modules and resolve refine
690      * nodes. If grouping is not found in modules, method tries to find it in
691      * modules from context.
692      *
693      * @param modules
694      *            all loaded modules
695      * @param module
696      *            current module
697      * @param context
698      *            SchemaContext containing already resolved modules
699      */
700     private void resolveUsesNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
701             final ModuleBuilder module, final SchemaContext context) {
702         final List<UsesNodeBuilder> moduleUses = module.getAllUsesNodes();
703         for (UsesNodeBuilder usesNode : moduleUses) {
704             final GroupingBuilder targetGroupingBuilder = getTargetGroupingFromModules(usesNode, modules, module);
705             if (targetGroupingBuilder == null) {
706                 final GroupingDefinition targetGrouping = getTargetGroupingFromContext(usesNode, module, context);
707                 usesNode.setGroupingPath(targetGrouping.getPath());
708                 processUsesNode(usesNode, targetGrouping);
709                 for (RefineHolder refine : usesNode.getRefines()) {
710                     DataSchemaNodeBuilder nodeToRefine = null;
711                     for (DataSchemaNodeBuilder dsnb : usesNode.getTargetChildren()) {
712                         if (refine.getName().equals(dsnb.getQName().getLocalName())) {
713                             nodeToRefine = dsnb;
714                             break;
715                         }
716                     }
717                     if (nodeToRefine == null) {
718                         throw new YangParseException(refine.getModuleName(), refine.getLine(), "Refine target node '"
719                                 + refine.getName() + "' not found");
720                     }
721                     if (nodeToRefine instanceof GroupingMember) {
722                         ((GroupingMember) nodeToRefine).setAddedByUses(true);
723                     }
724                     RefineUtils.performRefine(nodeToRefine, refine);
725                     usesNode.addRefineNode(nodeToRefine);
726                 }
727             } else {
728                 usesNode.setGroupingPath(targetGroupingBuilder.getPath());
729                 processUsesNode(module, usesNode, targetGroupingBuilder);
730                 for (RefineHolder refine : usesNode.getRefines()) {
731                     DataSchemaNodeBuilder nodeToRefine = null;
732                     for (DataSchemaNodeBuilder dsnb : usesNode.getTargetChildren()) {
733                         if (refine.getName().equals(dsnb.getQName().getLocalName())) {
734                             nodeToRefine = dsnb;
735                             break;
736                         }
737                     }
738                     if (nodeToRefine == null) {
739                         throw new YangParseException(refine.getModuleName(), refine.getLine(), "Refine target node '"
740                                 + refine.getName() + "' not found");
741                     }
742                     if (nodeToRefine instanceof GroupingMember) {
743                         ((GroupingMember) nodeToRefine).setAddedByUses(true);
744                     }
745                     RefineUtils.performRefine(nodeToRefine, refine);
746                     usesNode.addRefineNode(nodeToRefine);
747                 }
748             }
749         }
750     }
751
752     /**
753      * Add nodes defined in target grouping to current context.
754      *
755      * @param module
756      *            current module
757      * @param usesNode
758      * @param targetGrouping
759      */
760     private void processUsesNode(final ModuleBuilder module, final UsesNodeBuilder usesNode,
761             final GroupingBuilder targetGrouping) {
762         DataNodeContainerBuilder parent = usesNode.getParent();
763         URI namespace = null;
764         Date revision = null;
765         String prefix = null;
766         if (parent instanceof ModuleBuilder || parent instanceof AugmentationSchemaBuilder) {
767             namespace = module.getNamespace();
768             revision = module.getRevision();
769             prefix = module.getPrefix();
770         } else {
771             QName parentQName = parent.getQName();
772             namespace = parentQName.getNamespace();
773             revision = parentQName.getRevision();
774             prefix = parentQName.getPrefix();
775         }
776         SchemaPath parentPath = parent.getPath();
777         // child nodes
778         Set<DataSchemaNodeBuilder> newChildren = processUsesDataSchemaNode(usesNode,
779                 targetGrouping.getChildNodeBuilders(), parentPath, namespace, revision, prefix);
780         usesNode.getTargetChildren().addAll(newChildren);
781         // groupings
782         Set<GroupingBuilder> newGroupings = processUsesGroupings(targetGrouping.getGroupingBuilders(), parentPath,
783                 namespace, revision, prefix);
784         usesNode.getTargetGroupings().addAll(newGroupings);
785         // typedefs
786         Set<TypeDefinitionBuilder> newTypedefs = processUsesTypedefs(targetGrouping.getTypeDefinitionBuilders(),
787                 parentPath, namespace, revision, prefix);
788         usesNode.getTargetTypedefs().addAll(newTypedefs);
789         // unknown nodes
790         List<UnknownSchemaNodeBuilder> newUnknownNodes = processUsesUnknownNodes(
791                 targetGrouping.getUnknownNodeBuilders(), parentPath, namespace, revision, prefix);
792         usesNode.getTargetUnknownNodes().addAll(newUnknownNodes);
793     }
794
795     /**
796      * Check if target grouping contains uses nodes and if it does, merge
797      * current uses with them.
798      *
799      * @param module
800      * @param usesNode
801      * @param targetGrouping
802      */
803     private void processUsesTarget(final ModuleBuilder module, final UsesNodeBuilder usesNode,
804             final GroupingBuilder targetGrouping) {
805         DataNodeContainerBuilder parent = usesNode.getParent();
806         URI namespace = null;
807         Date revision = null;
808         String prefix = null;
809         if (parent instanceof ModuleBuilder || parent instanceof AugmentationSchemaBuilder) {
810             namespace = module.getNamespace();
811             revision = module.getRevision();
812             prefix = module.getPrefix();
813         } else {
814             QName parentQName = parent.getQName();
815             namespace = parentQName.getNamespace();
816             revision = parentQName.getRevision();
817             prefix = parentQName.getPrefix();
818         }
819         SchemaPath parentPath = parent.getPath();
820
821         for (UsesNodeBuilder unb : targetGrouping.getUses()) {
822             Set<DataSchemaNodeBuilder> newChildren = processUsesDataSchemaNode(usesNode, unb.getTargetChildren(),
823                     parentPath, namespace, revision, prefix);
824             usesNode.getTargetChildren().addAll(newChildren);
825
826             Set<GroupingBuilder> newGroupings = processUsesGroupings(unb.getTargetGroupings(), parentPath, namespace,
827                     revision, prefix);
828             usesNode.getTargetGroupings().addAll(newGroupings);
829
830             Set<TypeDefinitionBuilder> newTypedefs = processUsesTypedefs(unb.getTargetTypedefs(), parentPath,
831                     namespace, revision, prefix);
832             usesNode.getTargetTypedefs().addAll(newTypedefs);
833
834             List<UnknownSchemaNodeBuilder> newUnknownNodes = processUsesUnknownNodes(unb.getTargetUnknownNodes(),
835                     parentPath, namespace, revision, prefix);
836             usesNode.getTargetUnknownNodes().addAll(newUnknownNodes);
837         }
838     }
839
840     private void processUsesNode(final UsesNodeBuilder usesNode, final GroupingDefinition targetGrouping) {
841         final String moduleName = usesNode.getModuleName();
842         final int line = usesNode.getLine();
843         DataNodeContainerBuilder parent = usesNode.getParent();
844         URI namespace = null;
845         Date revision = null;
846         String prefix = null;
847         if (parent instanceof ModuleBuilder) {
848             ModuleBuilder m = (ModuleBuilder) parent;
849             namespace = m.getNamespace();
850             revision = m.getRevision();
851             prefix = m.getPrefix();
852         } else {
853             QName parentQName = parent.getQName();
854             namespace = parentQName.getNamespace();
855             revision = parentQName.getRevision();
856             prefix = parentQName.getPrefix();
857         }
858         SchemaPath parentPath = parent.getPath();
859
860         final Set<DataSchemaNodeBuilder> newChildren = new HashSet<>();
861         for (DataSchemaNode child : targetGrouping.getChildNodes()) {
862             if (child != null) {
863                 DataSchemaNodeBuilder newChild = null;
864                 QName newQName = new QName(namespace, revision, prefix, child.getQName().getLocalName());
865                 if (child instanceof AnyXmlSchemaNode) {
866                     newChild = createAnyXml((AnyXmlSchemaNode) child, newQName, moduleName, line);
867                 } else if (child instanceof ChoiceNode) {
868                     newChild = createChoice((ChoiceNode) child, newQName, moduleName, line);
869                 } else if (child instanceof ContainerSchemaNode) {
870                     newChild = createContainer((ContainerSchemaNode) child, newQName, moduleName, line);
871                 } else if (child instanceof LeafListSchemaNode) {
872                     newChild = createLeafList((LeafListSchemaNode) child, newQName, moduleName, line);
873                 } else if (child instanceof LeafSchemaNode) {
874                     newChild = createLeafBuilder((LeafSchemaNode) child, newQName, moduleName, line);
875                 } else if (child instanceof ListSchemaNode) {
876                     newChild = createList((ListSchemaNode) child, newQName, moduleName, line);
877                 }
878
879                 if (newChild == null) {
880                     throw new YangParseException(moduleName, line,
881                             "Unknown member of target grouping while resolving uses node.");
882                 }
883                 if (newChild instanceof GroupingMember) {
884                     ((GroupingMember) newChild).setAddedByUses(true);
885                 }
886
887                 newChild.setPath(createSchemaPath(parentPath, newQName));
888                 newChildren.add(newChild);
889             }
890         }
891         usesNode.getTargetChildren().addAll(newChildren);
892
893         final Set<GroupingBuilder> newGroupings = new HashSet<>();
894         for (GroupingDefinition g : targetGrouping.getGroupings()) {
895             QName newQName = new QName(namespace, revision, prefix, g.getQName().getLocalName());
896             GroupingBuilder newGrouping = createGrouping(g, newQName, moduleName, line);
897             newGrouping.setAddedByUses(true);
898             newGrouping.setPath(createSchemaPath(parentPath, newQName));
899             newGroupings.add(newGrouping);
900         }
901         usesNode.getTargetGroupings().addAll(newGroupings);
902
903         final Set<TypeDefinitionBuilder> newTypedefs = new HashSet<>();
904         for (TypeDefinition<?> td : targetGrouping.getTypeDefinitions()) {
905             QName newQName = new QName(namespace, revision, prefix, td.getQName().getLocalName());
906             TypeDefinitionBuilder newType = createTypedef((ExtendedType) td, newQName, moduleName, line);
907             newType.setAddedByUses(true);
908             newType.setPath(createSchemaPath(parentPath, newQName));
909             newTypedefs.add(newType);
910         }
911         usesNode.getTargetTypedefs().addAll(newTypedefs);
912
913         final List<UnknownSchemaNodeBuilder> newUnknownNodes = new ArrayList<>();
914         for (UnknownSchemaNode un : targetGrouping.getUnknownSchemaNodes()) {
915             QName newQName = new QName(namespace, revision, prefix, un.getQName().getLocalName());
916             UnknownSchemaNodeBuilder newNode = createUnknownSchemaNode(un, newQName, moduleName, line);
917             newNode.setAddedByUses(true);
918             newNode.setPath(createSchemaPath(parentPath, newQName));
919             newUnknownNodes.add(newNode);
920         }
921         usesNode.getTargetUnknownNodes().addAll(newUnknownNodes);
922     }
923
924     private void resolveUnknownNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
925         for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) {
926             QName nodeType = usnb.getNodeType();
927             if (nodeType.getNamespace() == null || nodeType.getRevision() == null) {
928                 try {
929                     ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, nodeType.getPrefix(),
930                             usnb.getLine());
931                     QName newNodeType = new QName(dependentModule.getNamespace(), dependentModule.getRevision(),
932                             nodeType.getPrefix(), nodeType.getLocalName());
933                     usnb.setNodeType(newNodeType);
934                 } catch (YangParseException e) {
935                     LOG.debug(module.getName(), usnb.getLine(), "Failed to find unknown node type: " + nodeType);
936                 }
937             }
938         }
939     }
940
941     private void resolveUnknownNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
942             final ModuleBuilder module, final SchemaContext context) {
943         for (UnknownSchemaNodeBuilder unknownNodeBuilder : module.getAllUnknownNodes()) {
944             QName nodeType = unknownNodeBuilder.getNodeType();
945             if (nodeType.getNamespace() == null || nodeType.getRevision() == null) {
946                 try {
947                     ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
948                             nodeType.getPrefix(), unknownNodeBuilder.getLine());
949
950                     QName newNodeType = null;
951                     if (dependentModuleBuilder == null) {
952                         Module dependentModule = findModuleFromContext(context, module, nodeType.getPrefix(),
953                                 unknownNodeBuilder.getLine());
954                         newNodeType = new QName(dependentModule.getNamespace(), dependentModule.getRevision(),
955                                 nodeType.getPrefix(), nodeType.getLocalName());
956                     } else {
957                         newNodeType = new QName(dependentModuleBuilder.getNamespace(),
958                                 dependentModuleBuilder.getRevision(), nodeType.getPrefix(), nodeType.getLocalName());
959                     }
960
961                     unknownNodeBuilder.setNodeType(newNodeType);
962                 } catch (YangParseException e) {
963                     LOG.debug(module.getName(), unknownNodeBuilder.getLine(), "Failed to find unknown node type: "
964                             + nodeType);
965                 }
966             }
967         }
968     }
969
970     /**
971      * Traverse through modules and resolve their deviation statements.
972      *
973      * @param modules
974      *            all loaded modules
975      */
976     private void resolveDeviations(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
977         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
978             for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
979                 ModuleBuilder b = inner.getValue();
980                 resolveDeviation(modules, b);
981             }
982         }
983     }
984
985     /**
986      * Traverse through module and resolve its deviation statements.
987      *
988      * @param modules
989      *            all loaded modules
990      * @param module
991      *            module in which resolve deviations
992      */
993     private void resolveDeviation(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
994         for (DeviationBuilder dev : module.getDeviations()) {
995             int line = dev.getLine();
996             SchemaPath targetPath = dev.getTargetPath();
997             List<QName> path = targetPath.getPath();
998             QName q0 = path.get(0);
999             String prefix = q0.getPrefix();
1000             if (prefix == null) {
1001                 prefix = module.getPrefix();
1002             }
1003
1004             ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, line);
1005             processDeviation(dev, dependentModuleBuilder, path, module);
1006         }
1007     }
1008
1009     /**
1010      * Traverse through modules and resolve their deviation statements with
1011      * given context.
1012      *
1013      * @param modules
1014      *            all loaded modules
1015      * @param context
1016      *            already resolved context
1017      */
1018     private void resolveDeviationsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1019             final SchemaContext context) {
1020         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
1021             for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
1022                 ModuleBuilder b = inner.getValue();
1023                 resolveDeviationWithContext(modules, b, context);
1024             }
1025         }
1026     }
1027
1028     /**
1029      * Traverse through module and resolve its deviation statements with given
1030      * context.
1031      *
1032      * @param modules
1033      *            all loaded modules
1034      * @param module
1035      *            module in which resolve deviations
1036      * @param context
1037      *            already resolved context
1038      */
1039     private void resolveDeviationWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1040             final ModuleBuilder module, final SchemaContext context) {
1041         for (DeviationBuilder dev : module.getDeviations()) {
1042             int line = dev.getLine();
1043             SchemaPath targetPath = dev.getTargetPath();
1044             List<QName> path = targetPath.getPath();
1045             QName q0 = path.get(0);
1046             String prefix = q0.getPrefix();
1047             if (prefix == null) {
1048                 prefix = module.getPrefix();
1049             }
1050             String name = null;
1051
1052             ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, line);
1053             if (dependentModuleBuilder == null) {
1054                 Module dependentModule = findModuleFromContext(context, module, prefix, line);
1055                 Object currentParent = dependentModule;
1056
1057                 for (int i = 0; i < path.size(); i++) {
1058                     if (currentParent == null) {
1059                         throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
1060                     }
1061                     QName q = path.get(i);
1062                     name = q.getLocalName();
1063                     if (currentParent instanceof DataNodeContainer) {
1064                         currentParent = ((DataNodeContainer) currentParent).getDataChildByName(name);
1065                     }
1066                 }
1067
1068                 if (currentParent == null) {
1069                     throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
1070                 }
1071                 if (currentParent instanceof SchemaNode) {
1072                     dev.setTargetPath(((SchemaNode) currentParent).getPath());
1073                 }
1074
1075             } else {
1076                 processDeviation(dev, dependentModuleBuilder, path, module);
1077             }
1078         }
1079     }
1080
1081     /**
1082      * Correct deviation target path in deviation builder.
1083      *
1084      * @param dev
1085      *            deviation
1086      * @param dependentModuleBuilder
1087      *            module containing deviation target
1088      * @param path
1089      *            current deviation target path
1090      * @param module
1091      *            current module
1092      */
1093     private void processDeviation(final DeviationBuilder dev, final ModuleBuilder dependentModuleBuilder,
1094             final List<QName> path, final ModuleBuilder module) {
1095         final int line = dev.getLine();
1096         Builder currentParent = dependentModuleBuilder;
1097
1098         for (int i = 0; i < path.size(); i++) {
1099             if (currentParent == null) {
1100                 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
1101             }
1102             QName q = path.get(i);
1103             String name = q.getLocalName();
1104             if (currentParent instanceof DataNodeContainerBuilder) {
1105                 currentParent = ((DataNodeContainerBuilder) currentParent).getDataChildByName(name);
1106             }
1107         }
1108
1109         if (currentParent == null || !(currentParent instanceof SchemaNodeBuilder)) {
1110             throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
1111         }
1112         dev.setTargetPath(((SchemaNodeBuilder) currentParent).getPath());
1113     }
1114
1115 }