Moved parsing of unknown nodes from implementation to abstract classes.
[controller.git] / opendaylight / sal / yang-prototype / code-generator / yang-model-parser-impl / src / main / java / org / opendaylight / controller / 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.controller.yang.parser.impl;
9
10 import static org.opendaylight.controller.yang.parser.util.ParserUtils.*;
11
12 import java.io.File;
13 import java.io.FileInputStream;
14 import java.io.FileNotFoundException;
15 import java.io.IOException;
16 import java.io.InputStream;
17 import java.util.ArrayList;
18 import java.util.Collections;
19 import java.util.Date;
20 import java.util.HashMap;
21 import java.util.HashSet;
22 import java.util.Iterator;
23 import java.util.LinkedHashMap;
24 import java.util.LinkedHashSet;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Map.Entry;
28 import java.util.NoSuchElementException;
29 import java.util.Set;
30 import java.util.TreeMap;
31
32 import org.antlr.v4.runtime.ANTLRInputStream;
33 import org.antlr.v4.runtime.CommonTokenStream;
34 import org.antlr.v4.runtime.tree.ParseTree;
35 import org.antlr.v4.runtime.tree.ParseTreeWalker;
36 import org.opendaylight.controller.antlrv4.code.gen.YangLexer;
37 import org.opendaylight.controller.antlrv4.code.gen.YangParser;
38 import org.opendaylight.controller.yang.common.QName;
39 import org.opendaylight.controller.yang.model.api.AnyXmlSchemaNode;
40 import org.opendaylight.controller.yang.model.api.ChoiceNode;
41 import org.opendaylight.controller.yang.model.api.ContainerSchemaNode;
42 import org.opendaylight.controller.yang.model.api.DataNodeContainer;
43 import org.opendaylight.controller.yang.model.api.DataSchemaNode;
44 import org.opendaylight.controller.yang.model.api.GroupingDefinition;
45 import org.opendaylight.controller.yang.model.api.IdentitySchemaNode;
46 import org.opendaylight.controller.yang.model.api.LeafListSchemaNode;
47 import org.opendaylight.controller.yang.model.api.LeafSchemaNode;
48 import org.opendaylight.controller.yang.model.api.ListSchemaNode;
49 import org.opendaylight.controller.yang.model.api.Module;
50 import org.opendaylight.controller.yang.model.api.SchemaContext;
51 import org.opendaylight.controller.yang.model.api.SchemaNode;
52 import org.opendaylight.controller.yang.model.api.SchemaPath;
53 import org.opendaylight.controller.yang.model.api.TypeDefinition;
54 import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
55 import org.opendaylight.controller.yang.model.api.UsesNode;
56 import org.opendaylight.controller.yang.model.parser.api.YangModelParser;
57 import org.opendaylight.controller.yang.model.util.ExtendedType;
58 import org.opendaylight.controller.yang.model.util.IdentityrefType;
59 import org.opendaylight.controller.yang.model.util.UnknownType;
60 import org.opendaylight.controller.yang.parser.builder.api.AugmentationSchemaBuilder;
61 import org.opendaylight.controller.yang.parser.builder.api.Builder;
62 import org.opendaylight.controller.yang.parser.builder.api.DataNodeContainerBuilder;
63 import org.opendaylight.controller.yang.parser.builder.api.DataSchemaNodeBuilder;
64 import org.opendaylight.controller.yang.parser.builder.api.GroupingBuilder;
65 import org.opendaylight.controller.yang.parser.builder.api.GroupingMember;
66 import org.opendaylight.controller.yang.parser.builder.api.SchemaNodeBuilder;
67 import org.opendaylight.controller.yang.parser.builder.api.TypeAwareBuilder;
68 import org.opendaylight.controller.yang.parser.builder.api.TypeDefinitionBuilder;
69 import org.opendaylight.controller.yang.parser.builder.api.UsesNodeBuilder;
70 import org.opendaylight.controller.yang.parser.builder.impl.AnyXmlBuilder;
71 import org.opendaylight.controller.yang.parser.builder.impl.ChoiceBuilder;
72 import org.opendaylight.controller.yang.parser.builder.impl.ContainerSchemaNodeBuilder;
73 import org.opendaylight.controller.yang.parser.builder.impl.DeviationBuilder;
74 import org.opendaylight.controller.yang.parser.builder.impl.GroupingBuilderImpl;
75 import org.opendaylight.controller.yang.parser.builder.impl.IdentitySchemaNodeBuilder;
76 import org.opendaylight.controller.yang.parser.builder.impl.IdentityrefTypeBuilder;
77 import org.opendaylight.controller.yang.parser.builder.impl.LeafListSchemaNodeBuilder;
78 import org.opendaylight.controller.yang.parser.builder.impl.LeafSchemaNodeBuilder;
79 import org.opendaylight.controller.yang.parser.builder.impl.ListSchemaNodeBuilder;
80 import org.opendaylight.controller.yang.parser.builder.impl.ModuleBuilder;
81 import org.opendaylight.controller.yang.parser.builder.impl.RpcDefinitionBuilder;
82 import org.opendaylight.controller.yang.parser.builder.impl.TypeDefinitionBuilderImpl;
83 import org.opendaylight.controller.yang.parser.builder.impl.UnionTypeBuilder;
84 import org.opendaylight.controller.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
85 import org.opendaylight.controller.yang.parser.builder.impl.UsesNodeBuilderImpl;
86 import org.opendaylight.controller.yang.parser.builder.impl.UsesNodeBuilderImpl.UsesNodeImpl;
87 import org.opendaylight.controller.yang.parser.util.ModuleDependencySort;
88 import org.opendaylight.controller.yang.parser.util.RefineHolder;
89 import org.opendaylight.controller.yang.parser.util.RefineUtils;
90 import org.opendaylight.controller.yang.parser.util.TypeConstraints;
91 import org.opendaylight.controller.yang.parser.util.YangParseException;
92 import org.opendaylight.controller.yang.validator.YangModelBasicValidator;
93 import org.slf4j.Logger;
94 import org.slf4j.LoggerFactory;
95
96 import com.google.common.collect.Lists;
97 import com.google.common.collect.Maps;
98 import com.google.common.collect.Sets;
99
100 public final class YangParserImpl implements YangModelParser {
101     private static final Logger LOG = LoggerFactory.getLogger(YangParserImpl.class);
102
103     @Override
104     public Set<Module> parseYangModels(final List<File> yangFiles) {
105         return Sets.newLinkedHashSet(parseYangModelsMapped(yangFiles).values());
106     }
107
108     @Override
109     public Set<Module> parseYangModels(final List<File> yangFiles, final SchemaContext context) {
110         if (yangFiles != null) {
111             final Map<InputStream, File> inputStreams = Maps.newHashMap();
112
113             for (final File yangFile : yangFiles) {
114                 try {
115                     inputStreams.put(new FileInputStream(yangFile), yangFile);
116                 } catch (FileNotFoundException e) {
117                     LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
118                 }
119             }
120
121             Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
122
123             final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
124                     Lists.newArrayList(inputStreams.keySet()), builderToStreamMap);
125
126             for (InputStream is : inputStreams.keySet()) {
127                 try {
128                     is.close();
129                 } catch (IOException e) {
130                     LOG.debug("Failed to close stream.");
131                 }
132             }
133
134             return new LinkedHashSet<Module>(buildWithContext(modules, context).values());
135         }
136         return Collections.emptySet();
137     }
138
139     @Override
140     public Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams) {
141         return Sets.newHashSet(parseYangModelsFromStreamsMapped(yangModelStreams).values());
142     }
143
144     @Override
145     public Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams, SchemaContext context) {
146         if (yangModelStreams != null) {
147             Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
148             final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersWithContext(
149                     yangModelStreams, builderToStreamMap, context);
150             return new LinkedHashSet<Module>(buildWithContext(modules, context).values());
151         }
152         return Collections.emptySet();
153     }
154
155     @Override
156     public Map<File, Module> parseYangModelsMapped(List<File> yangFiles) {
157         if (yangFiles != null) {
158             final Map<InputStream, File> inputStreams = Maps.newHashMap();
159
160             for (final File yangFile : yangFiles) {
161                 try {
162                     inputStreams.put(new FileInputStream(yangFile), yangFile);
163                 } catch (FileNotFoundException e) {
164                     LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
165                 }
166             }
167
168             Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
169             final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
170                     Lists.newArrayList(inputStreams.keySet()), builderToStreamMap);
171
172             for (InputStream is : inputStreams.keySet()) {
173                 try {
174                     is.close();
175                 } catch (IOException e) {
176                     LOG.debug("Failed to close stream.");
177                 }
178             }
179
180             Map<File, Module> retVal = Maps.newLinkedHashMap();
181             Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
182
183             for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap.entrySet()) {
184                 retVal.put(inputStreams.get(builderToStreamMap.get(builderToModule.getKey())),
185                         builderToModule.getValue());
186             }
187
188             return retVal;
189         }
190         return Collections.emptyMap();
191     }
192
193     @Override
194     public Map<InputStream, Module> parseYangModelsFromStreamsMapped(final List<InputStream> yangModelStreams) {
195         Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
196
197         final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangModelStreams,
198                 builderToStreamMap);
199         Map<InputStream, Module> retVal = Maps.newLinkedHashMap();
200         Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
201
202         for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap.entrySet()) {
203             retVal.put(builderToStreamMap.get(builderToModule.getKey()), builderToModule.getValue());
204         }
205         return retVal;
206     }
207
208     @Override
209     public SchemaContext resolveSchemaContext(final Set<Module> modules) {
210         return new SchemaContextImpl(modules);
211     }
212
213     private ModuleBuilder[] parseModuleBuilders(List<InputStream> inputStreams,
214             Map<ModuleBuilder, InputStream> streamToBuilderMap) {
215
216         final ParseTreeWalker walker = new ParseTreeWalker();
217         final List<ParseTree> trees = parseStreams(inputStreams);
218         final ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
219
220         // validate yang
221         new YangModelBasicValidator(walker).validate(trees);
222
223         YangParserListenerImpl yangModelParser = null;
224         for (int i = 0; i < trees.size(); i++) {
225             yangModelParser = new YangParserListenerImpl();
226             walker.walk(yangModelParser, trees.get(i));
227             ModuleBuilder moduleBuilder = yangModelParser.getModuleBuilder();
228
229             // We expect the order of trees and streams has to be the same
230             streamToBuilderMap.put(moduleBuilder, inputStreams.get(i));
231             builders[i] = moduleBuilder;
232         }
233         return builders;
234     }
235
236     private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(final List<InputStream> yangFileStreams,
237             Map<ModuleBuilder, InputStream> streamToBuilderMap) {
238         return resolveModuleBuildersWithContext(yangFileStreams, streamToBuilderMap, null);
239     }
240
241     private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuildersWithContext(
242             final List<InputStream> yangFileStreams, final Map<ModuleBuilder, InputStream> streamToBuilderMap,
243             final SchemaContext context) {
244         final ModuleBuilder[] builders = parseModuleBuilders(yangFileStreams, streamToBuilderMap);
245
246         // Linked Hash Map MUST be used because Linked Hash Map preserves ORDER
247         // of items stored in map.
248         final LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> modules = new LinkedHashMap<String, TreeMap<Date, ModuleBuilder>>();
249
250         // module dependency graph sorted
251         List<ModuleBuilder> sorted = null;
252         if (context == null) {
253             sorted = ModuleDependencySort.sort(builders);
254         } else {
255             sorted = ModuleDependencySort.sortWithContext(context, builders);
256         }
257
258         for (final ModuleBuilder builder : sorted) {
259             if (builder == null) {
260                 continue;
261             }
262             final String builderName = builder.getName();
263             Date builderRevision = builder.getRevision();
264             if (builderRevision == null) {
265                 builderRevision = new Date(0L);
266             }
267             TreeMap<Date, ModuleBuilder> builderByRevision = modules.get(builderName);
268             if (builderByRevision == null) {
269                 builderByRevision = new TreeMap<Date, ModuleBuilder>();
270             }
271             builderByRevision.put(builderRevision, builder);
272             modules.put(builderName, builderByRevision);
273         }
274         return modules;
275     }
276
277     private List<ParseTree> parseStreams(final List<InputStream> yangStreams) {
278         final List<ParseTree> trees = new ArrayList<ParseTree>();
279         for (InputStream yangStream : yangStreams) {
280             trees.add(parseStream(yangStream));
281         }
282         return trees;
283     }
284
285     private ParseTree parseStream(final InputStream yangStream) {
286         ParseTree result = null;
287         try {
288             final ANTLRInputStream input = new ANTLRInputStream(yangStream);
289             final YangLexer lexer = new YangLexer(input);
290             final CommonTokenStream tokens = new CommonTokenStream(lexer);
291             final YangParser parser = new YangParser(tokens);
292             parser.removeErrorListeners();
293             parser.addErrorListener(new YangErrorListener());
294
295             result = parser.yang();
296         } catch (IOException e) {
297             LOG.warn("Exception while reading yang file: " + yangStream, e);
298         }
299         return result;
300     }
301
302     private Map<ModuleBuilder, Module> build(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
303         // fix unresolved nodes
304         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
305             for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
306                 final ModuleBuilder moduleBuilder = childEntry.getValue();
307                 fixUnresolvedNodes(modules, moduleBuilder);
308             }
309         }
310         resolveAugments(modules);
311         resolveDeviations(modules);
312
313         // build
314         // LinkedHashMap MUST be used otherwise the values will not maintain
315         // order!
316         // http://docs.oracle.com/javase/6/docs/api/java/util/LinkedHashMap.html
317         final Map<ModuleBuilder, Module> result = new LinkedHashMap<ModuleBuilder, Module>();
318         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
319             final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
320             for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
321                 final ModuleBuilder moduleBuilder = childEntry.getValue();
322                 final Module module = moduleBuilder.build();
323                 modulesByRevision.put(childEntry.getKey(), module);
324                 result.put(moduleBuilder, module);
325             }
326         }
327         return result;
328     }
329
330     private Map<ModuleBuilder, Module> buildWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
331             SchemaContext context) {
332         // fix unresolved nodes
333         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
334             for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
335                 final ModuleBuilder moduleBuilder = childEntry.getValue();
336                 fixUnresolvedNodesWithContext(modules, moduleBuilder, context);
337             }
338         }
339         resolveAugmentsWithContext(modules, context);
340         resolveDeviationsWithContext(modules, context);
341
342         // build
343         // LinkedHashMap MUST be used otherwise the values will not maintain
344         // order!
345         // http://docs.oracle.com/javase/6/docs/api/java/util/LinkedHashMap.html
346         final Map<ModuleBuilder, Module> result = new LinkedHashMap<ModuleBuilder, Module>();
347         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
348             final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
349             for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
350                 final ModuleBuilder moduleBuilder = childEntry.getValue();
351                 final Module module = moduleBuilder.build();
352                 modulesByRevision.put(childEntry.getKey(), module);
353                 result.put(moduleBuilder, module);
354             }
355         }
356         return result;
357     }
358
359     private void fixUnresolvedNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder builder) {
360         resolveDirtyNodes(modules, builder);
361         resolveIdentities(modules, builder);
362         resolveUsesRefine(modules, builder);
363         resolveUnknownNodes(modules, builder);
364     }
365
366     private void fixUnresolvedNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
367             final ModuleBuilder builder, final SchemaContext context) {
368         resolveDirtyNodesWithContext(modules, builder, context);
369         resolveIdentitiesWithContext(modules, builder, context);
370         resolveUsesRefineWithContext(modules, builder, context);
371         resolveUnknownNodesWithContext(modules, builder, context);
372     }
373
374     /**
375      * Search for dirty nodes (node which contains UnknownType) and resolve
376      * unknown types.
377      *
378      * @param modules
379      *            all available modules
380      * @param module
381      *            current module
382      */
383     private void resolveDirtyNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
384         final Set<TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
385         if (!dirtyNodes.isEmpty()) {
386             for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
387                 if (nodeToResolve instanceof UnionTypeBuilder) {
388                     // special handling for union types
389                     resolveTypeUnion((UnionTypeBuilder) nodeToResolve, modules, module);
390                 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
391                     // special handling for identityref types
392                     IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
393                     nodeToResolve.setType(new IdentityrefType(findFullQName(modules, module, idref), idref.getPath()));
394                 } else {
395                     resolveType(nodeToResolve, modules, module);
396                 }
397             }
398         }
399     }
400
401     private void resolveDirtyNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
402             final ModuleBuilder module, SchemaContext context) {
403         final Set<TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
404         if (!dirtyNodes.isEmpty()) {
405             for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
406                 if (nodeToResolve instanceof UnionTypeBuilder) {
407                     // special handling for union types
408                     resolveTypeUnionWithContext((UnionTypeBuilder) nodeToResolve, modules, module, context);
409                 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
410                     // special handling for identityref types
411                     IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
412                     nodeToResolve.setType(new IdentityrefType(findFullQName(modules, module, idref), idref.getPath()));
413                 } else {
414                     resolveTypeWithContext(nodeToResolve, modules, module, context);
415                 }
416             }
417         }
418     }
419
420     /**
421      * Resolve unknown type of node. It is assumed that type of node is either
422      * UnknownType or ExtendedType with UnknownType as base type.
423      *
424      * @param nodeToResolve
425      *            node with type to resolve
426      * @param modules
427      *            all loaded modules
428      * @param module
429      *            current module
430      */
431     private void resolveType(final TypeAwareBuilder nodeToResolve,
432             final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
433         TypeDefinitionBuilder resolvedType = null;
434         final int line = nodeToResolve.getLine();
435         final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
436         final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
437         final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, unknownTypeQName.getPrefix(),
438                 line);
439
440         final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(nodeToResolve, dependentModule,
441                 unknownTypeQName.getLocalName(), module.getName(), line);
442
443         if (nodeToResolveType instanceof ExtendedType) {
444             final ExtendedType extType = (ExtendedType) nodeToResolveType;
445             final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder, extType,
446                     modules, module, nodeToResolve.getLine());
447             resolvedType = newType;
448         } else {
449             resolvedType = targetTypeBuilder;
450         }
451
452         // validate constraints
453         final TypeConstraints constraints = findConstraintsFromTypeBuilder(nodeToResolve,
454                 new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module, null);
455         constraints.validateConstraints();
456
457         nodeToResolve.setTypedef(resolvedType);
458     }
459
460     /**
461      * Resolve unknown type of node. It is assumed that type of node is either
462      * UnknownType or ExtendedType with UnknownType as base type.
463      *
464      * @param nodeToResolve
465      *            node with type to resolve
466      * @param modules
467      *            all loaded modules
468      * @param module
469      *            current module
470      * @param context
471      *            SchemaContext containing already resolved modules
472      */
473     private void resolveTypeWithContext(final TypeAwareBuilder nodeToResolve,
474             final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
475             final SchemaContext context) {
476         TypeDefinitionBuilder resolvedType = null;
477         final int line = nodeToResolve.getLine();
478         final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
479         final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
480         final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
481                 unknownTypeQName.getPrefix(), line);
482
483         if (dependentModuleBuilder == null) {
484             final Module dependentModule = findModuleFromContext(context, module, unknownTypeQName.getPrefix(), line);
485             final Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
486             final TypeDefinition<?> type = findTypeByName(types, unknownTypeQName.getLocalName());
487
488             if (nodeToResolveType instanceof ExtendedType) {
489                 final ExtendedType extType = (ExtendedType) nodeToResolveType;
490                 final TypeDefinitionBuilder newType = extendedTypeWithNewBaseType(type, extType, module,
491                         nodeToResolve.getLine());
492
493                 nodeToResolve.setTypedef(newType);
494             } else {
495                 if (nodeToResolve instanceof TypeDefinitionBuilder) {
496                     TypeDefinitionBuilder tdb = (TypeDefinitionBuilder) nodeToResolve;
497                     TypeConstraints tc = findConstraintsFromTypeBuilder(nodeToResolve,
498                             new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module, context);
499                     tdb.setLengths(tc.getLength());
500                     tdb.setPatterns(tc.getPatterns());
501                     tdb.setRanges(tc.getRange());
502                     tdb.setFractionDigits(tc.getFractionDigits());
503                 }
504                 nodeToResolve.setType(type);
505             }
506
507         } else {
508             final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(nodeToResolve,
509                     dependentModuleBuilder, unknownTypeQName.getLocalName(), module.getName(), line);
510
511             if (nodeToResolveType instanceof ExtendedType) {
512                 final ExtendedType extType = (ExtendedType) nodeToResolveType;
513                 final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder, extType,
514                         modules, module, nodeToResolve.getLine());
515                 resolvedType = newType;
516             } else {
517                 resolvedType = targetTypeBuilder;
518             }
519
520             // validate constraints
521             final TypeConstraints constraints = findConstraintsFromTypeBuilder(nodeToResolve, new TypeConstraints(
522                     module.getName(), nodeToResolve.getLine()), modules, module, context);
523             constraints.validateConstraints();
524
525             nodeToResolve.setTypedef(resolvedType);
526         }
527     }
528
529     private void resolveTypeUnion(final UnionTypeBuilder union,
530             final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder builder) {
531
532         final List<TypeDefinition<?>> unionTypes = union.getTypes();
533         final List<TypeDefinition<?>> toRemove = new ArrayList<TypeDefinition<?>>();
534         for (TypeDefinition<?> unionType : unionTypes) {
535             if (unionType instanceof UnknownType) {
536                 final UnknownType ut = (UnknownType) unionType;
537                 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, builder, ut.getQName()
538                         .getPrefix(), union.getLine());
539                 final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union, dependentModule, ut
540                         .getQName().getLocalName(), builder.getName(), union.getLine());
541                 union.setTypedef(resolvedType);
542                 toRemove.add(ut);
543             } else if (unionType instanceof ExtendedType) {
544                 final ExtendedType extType = (ExtendedType) unionType;
545                 final TypeDefinition<?> extTypeBase = extType.getBaseType();
546                 if (extTypeBase instanceof UnknownType) {
547                     final UnknownType ut = (UnknownType) extTypeBase;
548                     final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, builder, ut.getQName()
549                             .getPrefix(), union.getLine());
550                     final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union, dependentModule,
551                             ut.getQName().getLocalName(), builder.getName(), union.getLine());
552
553                     final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder,
554                             extType, modules, builder, union.getLine());
555
556                     union.setTypedef(newType);
557                     toRemove.add(extType);
558                 }
559             }
560         }
561         unionTypes.removeAll(toRemove);
562     }
563
564     private void resolveTypeUnionWithContext(final UnionTypeBuilder union,
565             final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder builder,
566             final SchemaContext context) {
567
568         final List<TypeDefinition<?>> unionTypes = union.getTypes();
569         final List<TypeDefinition<?>> toRemove = new ArrayList<TypeDefinition<?>>();
570         for (TypeDefinition<?> unionType : unionTypes) {
571             if (unionType instanceof UnknownType) {
572                 final UnknownType ut = (UnknownType) unionType;
573                 final QName utQName = ut.getQName();
574                 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, builder,
575                         utQName.getPrefix(), union.getLine());
576
577                 if (dependentModuleBuilder == null) {
578                     Module dependentModule = findModuleFromContext(context, builder, utQName.getPrefix(),
579                             union.getLine());
580                     Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
581                     TypeDefinition<?> type = findTypeByName(types, utQName.getLocalName());
582                     union.setType(type);
583                     toRemove.add(ut);
584                 } else {
585                     final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union, dependentModuleBuilder,
586                             utQName.getLocalName(), builder.getName(), union.getLine());
587                     union.setTypedef(resolvedType);
588                     toRemove.add(ut);
589                 }
590
591             } else if (unionType instanceof ExtendedType) {
592                 final ExtendedType extType = (ExtendedType) unionType;
593                 TypeDefinition<?> extTypeBase = extType.getBaseType();
594                 if (extTypeBase instanceof UnknownType) {
595                     final UnknownType ut = (UnknownType) extTypeBase;
596                     final QName utQName = ut.getQName();
597                     final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, builder,
598                             utQName.getPrefix(), union.getLine());
599
600                     if (dependentModuleBuilder == null) {
601                         final Module dependentModule = findModuleFromContext(context, builder, utQName.getPrefix(),
602                                 union.getLine());
603                         Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
604                         TypeDefinition<?> type = findTypeByName(types, utQName.getLocalName());
605                         final TypeDefinitionBuilder newType = extendedTypeWithNewBaseType(type, extType, builder, 0);
606
607                         union.setTypedef(newType);
608                         toRemove.add(extType);
609                     } else {
610                         final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union,
611                                 dependentModuleBuilder, utQName.getLocalName(), builder.getName(), union.getLine());
612
613                         final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder,
614                                 extType, modules, builder, union.getLine());
615
616                         union.setTypedef(newType);
617                         toRemove.add(extType);
618                     }
619                 }
620             }
621         }
622         unionTypes.removeAll(toRemove);
623     }
624
625     /**
626      * Go through all augment definitions and resolve them. It is expected that
627      * modules are already sorted by their dependencies. This method also finds
628      * augment target node and add child nodes to it.
629      *
630      * @param modules
631      *            all available modules
632      */
633     private void resolveAugments(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
634         final List<ModuleBuilder> allModulesList = new ArrayList<ModuleBuilder>();
635         final Set<ModuleBuilder> allModulesSet = new HashSet<ModuleBuilder>();
636         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
637             for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
638                 allModulesList.add(inner.getValue());
639                 allModulesSet.add(inner.getValue());
640             }
641         }
642
643         for (int i = 0; i < allModulesList.size(); i++) {
644             final ModuleBuilder module = allModulesList.get(i);
645             // try to resolve augments in module
646             resolveAugment(modules, module);
647             // while all augments are not resolved
648             final Iterator<ModuleBuilder> allModulesIterator = allModulesSet.iterator();
649             while (!(module.getAugmentsResolved() == module.getAllAugments().size())) {
650                 ModuleBuilder nextModule = null;
651                 // try resolve other module augments
652                 try {
653                     nextModule = allModulesIterator.next();
654                     resolveAugment(modules, nextModule);
655                 } catch (NoSuchElementException e) {
656                     throw new YangParseException("Failed to resolve augments in module '" + module.getName() + "'.", e);
657                 }
658                 // then try to resolve first module again
659                 resolveAugment(modules, module);
660             }
661         }
662     }
663
664     /**
665      * Tries to resolve augments in given module. If augment target node is not
666      * found, do nothing.
667      *
668      * @param modules
669      *            all available modules
670      * @param module
671      *            current module
672      */
673     private void resolveAugment(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
674         if (module.getAugmentsResolved() < module.getAllAugments().size()) {
675             for (AugmentationSchemaBuilder augmentBuilder : module.getAllAugments()) {
676
677                 if (!augmentBuilder.isResolved()) {
678                     final SchemaPath augmentTargetSchemaPath = augmentBuilder.getTargetPath();
679                     final List<QName> path = augmentTargetSchemaPath.getPath();
680
681                     final QName qname = path.get(0);
682                     String prefix = qname.getPrefix();
683                     if (prefix == null) {
684                         prefix = module.getPrefix();
685                     }
686
687                     final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, prefix,
688                             augmentBuilder.getLine());
689                     processAugmentation(augmentBuilder, path, module, dependentModule);
690                 }
691
692             }
693         }
694     }
695
696     /**
697      * Go through all augment definitions and resolve them. This method works in
698      * same way as {@link #resolveAugments(Map)} except that if target node is
699      * not found in loaded modules, it search for target node in given context.
700      *
701      * @param modules
702      *            all loaded modules
703      * @param context
704      *            SchemaContext containing already resolved modules
705      */
706     private void resolveAugmentsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
707             final SchemaContext context) {
708         final List<ModuleBuilder> allModulesList = new ArrayList<ModuleBuilder>();
709         final Set<ModuleBuilder> allModulesSet = new HashSet<ModuleBuilder>();
710         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
711             for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
712                 allModulesList.add(inner.getValue());
713                 allModulesSet.add(inner.getValue());
714             }
715         }
716
717         for (int i = 0; i < allModulesList.size(); i++) {
718             final ModuleBuilder module = allModulesList.get(i);
719             // try to resolve augments in module
720             resolveAugmentWithContext(modules, module, context);
721             // while all augments are not resolved
722             final Iterator<ModuleBuilder> allModulesIterator = allModulesSet.iterator();
723             while (!(module.getAugmentsResolved() == module.getAllAugments().size())) {
724                 ModuleBuilder nextModule = null;
725                 // try resolve other module augments
726                 try {
727                     nextModule = allModulesIterator.next();
728                     resolveAugmentWithContext(modules, nextModule, context);
729                 } catch (NoSuchElementException e) {
730                     throw new YangParseException("Failed to resolve augments in module '" + module.getName() + "'.", e);
731                 }
732                 // then try to resolve first module again
733                 resolveAugmentWithContext(modules, module, context);
734             }
735         }
736     }
737
738     /**
739      * Tries to resolve augments in given module. If augment target node is not
740      * found, do nothing.
741      *
742      * @param modules
743      *            all available modules
744      * @param module
745      *            current module
746      */
747     private void resolveAugmentWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
748             final ModuleBuilder module, final SchemaContext context) {
749         if (module.getAugmentsResolved() < module.getAllAugments().size()) {
750
751             for (AugmentationSchemaBuilder augmentBuilder : module.getAllAugments()) {
752                 final int line = augmentBuilder.getLine();
753
754                 if (!augmentBuilder.isResolved()) {
755                     final List<QName> path = augmentBuilder.getTargetPath().getPath();
756                     final QName qname = path.get(0);
757                     String prefix = qname.getPrefix();
758                     if (prefix == null) {
759                         prefix = module.getPrefix();
760                     }
761
762                     // try to find augment target module in loaded modules...
763                     final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix,
764                             line);
765                     if (dependentModuleBuilder == null) {
766                         // perform augmentation on module from context and
767                         // continue to next augment
768                         processAugmentationOnContext(augmentBuilder, path, module, prefix, line, context);
769                         continue;
770                     } else {
771                         processAugmentation(augmentBuilder, path, module, dependentModuleBuilder);
772                     }
773                 }
774
775             }
776         }
777     }
778
779     /**
780      * Go through identity statements defined in current module and resolve
781      * their 'base' statement if present.
782      *
783      * @param modules
784      *            all modules
785      * @param module
786      *            module being resolved
787      */
788     private void resolveIdentities(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
789         final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
790         for (IdentitySchemaNodeBuilder identity : identities) {
791             final String baseIdentityName = identity.getBaseIdentityName();
792             if (baseIdentityName != null) {
793                 String baseIdentityPrefix = null;
794                 String baseIdentityLocalName = null;
795                 if (baseIdentityName.contains(":")) {
796                     final String[] splitted = baseIdentityName.split(":");
797                     baseIdentityPrefix = splitted[0];
798                     baseIdentityLocalName = splitted[1];
799                 } else {
800                     baseIdentityPrefix = module.getPrefix();
801                     baseIdentityLocalName = baseIdentityName;
802                 }
803                 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, baseIdentityPrefix,
804                         identity.getLine());
805
806                 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule.getIdentities();
807                 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
808                     if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
809                         identity.setBaseIdentity(idBuilder);
810                     }
811                 }
812             }
813         }
814     }
815
816     /**
817      * Go through identity statements defined in current module and resolve
818      * their 'base' statement. Method tries to find base identity in given
819      * modules. If base identity is not found, method will search it in context.
820      *
821      * @param modules
822      *            all loaded modules
823      * @param module
824      *            current module
825      * @param context
826      *            SchemaContext containing already resolved modules
827      */
828     private void resolveIdentitiesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
829             final ModuleBuilder module, final SchemaContext context) {
830         final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
831         for (IdentitySchemaNodeBuilder identity : identities) {
832             final String baseIdentityName = identity.getBaseIdentityName();
833             if (baseIdentityName != null) {
834                 String baseIdentityPrefix = null;
835                 String baseIdentityLocalName = null;
836                 if (baseIdentityName.contains(":")) {
837                     final String[] splitted = baseIdentityName.split(":");
838                     baseIdentityPrefix = splitted[0];
839                     baseIdentityLocalName = splitted[1];
840                 } else {
841                     baseIdentityPrefix = module.getPrefix();
842                     baseIdentityLocalName = baseIdentityName;
843                 }
844                 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
845                         baseIdentityPrefix, identity.getLine());
846
847                 if (dependentModuleBuilder == null) {
848                     final Module dependentModule = findModuleFromContext(context, module, baseIdentityPrefix,
849                             identity.getLine());
850                     final Set<IdentitySchemaNode> dependentModuleIdentities = dependentModule.getIdentities();
851                     for (IdentitySchemaNode idNode : dependentModuleIdentities) {
852                         if (idNode.getQName().getLocalName().equals(baseIdentityLocalName)) {
853                             identity.setBaseIdentity(idNode);
854                         }
855                     }
856                 } else {
857                     final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModuleBuilder
858                             .getIdentities();
859                     for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
860                         if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
861                             identity.setBaseIdentity(idBuilder);
862                         }
863                     }
864                 }
865             }
866         }
867     }
868
869     /**
870      * Go through uses statements defined in current module and resolve their
871      * refine statements.
872      *
873      * @param modules
874      *            all modules
875      * @param module
876      *            module being resolved
877      */
878     private void resolveUsesRefine(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
879         final List<UsesNodeBuilder> allModuleUses = module.getAllUsesNodes();
880         for (UsesNodeBuilder usesNode : allModuleUses) {
881             // refine
882             final int line = usesNode.getLine();
883             final GroupingBuilder targetGrouping = getTargetGroupingFromModules(usesNode, modules, module);
884             usesNode.setGroupingPath(targetGrouping.getPath());
885             for (RefineHolder refine : usesNode.getRefines()) {
886                 final SchemaNodeBuilder nodeToRefine = RefineUtils.getRefineNodeFromGroupingBuilder(targetGrouping,
887                         refine, module.getName());
888                 if (nodeToRefine instanceof GroupingMember) {
889                     ((GroupingMember) nodeToRefine).setAddedByUses(true);
890                 }
891                 RefineUtils.performRefine(nodeToRefine, refine, line);
892                 usesNode.addRefineNode(nodeToRefine);
893             }
894
895             // child nodes
896             processUsesNode(usesNode, targetGrouping);
897         }
898     }
899
900     /**
901      * Tries to search target grouping in given modules and resolve refine
902      * nodes. If grouping is not found in modules, method tries to find it in
903      * modules from context.
904      *
905      * @param modules
906      *            all loaded modules
907      * @param module
908      *            current module
909      * @param context
910      *            SchemaContext containing already resolved modules
911      */
912     private void resolveUsesRefineWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
913             final ModuleBuilder module, final SchemaContext context) {
914         final List<UsesNodeBuilder> moduleUses = module.getAllUsesNodes();
915         for (UsesNodeBuilder usesNode : moduleUses) {
916             final int line = usesNode.getLine();
917
918             final GroupingBuilder targetGroupingBuilder = getTargetGroupingFromModules(usesNode, modules, module);
919             if (targetGroupingBuilder == null) {
920                 final GroupingDefinition targetGrouping = getTargetGroupingFromContext(usesNode, module, context);
921                 usesNode.setGroupingPath(targetGrouping.getPath());
922                 for (RefineHolder refine : usesNode.getRefines()) {
923                     final SchemaNodeBuilder nodeToRefine = RefineUtils.getRefineNodeFromGroupingDefinition(
924                             targetGrouping, refine, module.getName());
925                     if (nodeToRefine instanceof GroupingMember) {
926                         ((GroupingMember) nodeToRefine).setAddedByUses(true);
927                     }
928                     RefineUtils.performRefine(nodeToRefine, refine, line);
929                     usesNode.addRefineNode(nodeToRefine);
930                 }
931
932                 processUsesNode(usesNode, targetGrouping);
933             } else {
934                 usesNode.setGroupingPath(targetGroupingBuilder.getPath());
935                 for (RefineHolder refine : usesNode.getRefines()) {
936                     final SchemaNodeBuilder nodeToRefine = RefineUtils.getRefineNodeFromGroupingBuilder(
937                             targetGroupingBuilder, refine, module.getName());
938                     if (nodeToRefine instanceof GroupingMember) {
939                         ((GroupingMember) nodeToRefine).setAddedByUses(true);
940                     }
941                     RefineUtils.performRefine(nodeToRefine, refine, line);
942                     usesNode.addRefineNode(nodeToRefine);
943                 }
944
945                 processUsesNode(usesNode, targetGroupingBuilder);
946             }
947         }
948     }
949
950     /**
951      * Search given modules for grouping by name defined in uses node.
952      *
953      * @param usesBuilder
954      *            builder of uses statement
955      * @param modules
956      *            all loaded modules
957      * @param module
958      *            current module
959      * @return grouping with given name if found, null otherwise
960      */
961     private GroupingBuilder getTargetGroupingFromModules(final UsesNodeBuilder usesBuilder,
962             final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
963         final int line = usesBuilder.getLine();
964         final String groupingString = usesBuilder.getGroupingName();
965         String groupingPrefix;
966         String groupingName;
967
968         if (groupingString.contains(":")) {
969             String[] splitted = groupingString.split(":");
970             if (splitted.length != 2 || groupingString.contains("/")) {
971                 throw new YangParseException(module.getName(), line, "Invalid name of target grouping");
972             }
973             groupingPrefix = splitted[0];
974             groupingName = splitted[1];
975         } else {
976             groupingPrefix = module.getPrefix();
977             groupingName = groupingString;
978         }
979
980         ModuleBuilder dependentModule = null;
981         if (groupingPrefix.equals(module.getPrefix())) {
982             dependentModule = module;
983         } else {
984             dependentModule = findDependentModuleBuilder(modules, module, groupingPrefix, line);
985         }
986
987         if (dependentModule == null) {
988             return null;
989         }
990
991         GroupingBuilder result = null;
992         Set<GroupingBuilder> groupings = dependentModule.getGroupingBuilders();
993         result = findGroupingBuilder(groupings, groupingName);
994         if (result != null) {
995             return result;
996         }
997
998         Builder parent = usesBuilder.getParent();
999
1000         while (parent != null) {
1001             if (parent instanceof DataNodeContainerBuilder) {
1002                 groupings = ((DataNodeContainerBuilder) parent).getGroupingBuilders();
1003             } else if (parent instanceof RpcDefinitionBuilder) {
1004                 groupings = ((RpcDefinitionBuilder) parent).getGroupings();
1005             }
1006             result = findGroupingBuilder(groupings, groupingName);
1007             if (result == null) {
1008                 parent = parent.getParent();
1009             } else {
1010                 break;
1011             }
1012         }
1013
1014         if (result == null) {
1015             throw new YangParseException(module.getName(), line, "Referenced grouping '" + groupingName
1016                     + "' not found.");
1017         }
1018         return result;
1019     }
1020
1021     /**
1022      * Search context for grouping by name defined in uses node.
1023      *
1024      * @param usesBuilder
1025      *            builder of uses statement
1026      * @param module
1027      *            current module
1028      * @param context
1029      *            SchemaContext containing already resolved modules
1030      * @return grouping with given name if found, null otherwise
1031      */
1032     private GroupingDefinition getTargetGroupingFromContext(final UsesNodeBuilder usesBuilder,
1033             final ModuleBuilder module, final SchemaContext context) {
1034         final int line = usesBuilder.getLine();
1035         String groupingString = usesBuilder.getGroupingName();
1036         String groupingPrefix;
1037         String groupingName;
1038
1039         if (groupingString.contains(":")) {
1040             String[] splitted = groupingString.split(":");
1041             if (splitted.length != 2 || groupingString.contains("/")) {
1042                 throw new YangParseException(module.getName(), line, "Invalid name of target grouping");
1043             }
1044             groupingPrefix = splitted[0];
1045             groupingName = splitted[1];
1046         } else {
1047             groupingPrefix = module.getPrefix();
1048             groupingName = groupingString;
1049         }
1050
1051         Module dependentModule = findModuleFromContext(context, module, groupingPrefix, line);
1052         return findGroupingDefinition(dependentModule.getGroupings(), groupingName);
1053     }
1054
1055     /**
1056      * Add nodes defined in target grouping to current context.
1057      *
1058      * @param usesNode
1059      * @param targetGrouping
1060      */
1061     private void processUsesNode(final UsesNodeBuilder usesNode, final GroupingBuilder targetGrouping) {
1062         List<SchemaNodeBuilder> refineNodes = usesNode.getRefineNodes();
1063         DataNodeContainerBuilder parent = usesNode.getParent();
1064         SchemaPath parentPath = parent.getPath();
1065         for (DataSchemaNodeBuilder child : targetGrouping.getChildNodeBuilders()) {
1066             if (child != null) {
1067                 // if node is refined, take it from refined nodes and continue
1068                 SchemaNodeBuilder refined = getRefined(child.getQName(), refineNodes);
1069                 if (refined != null) {
1070                     refined.setPath(createSchemaPath(parentPath, refined.getQName().getLocalName()));
1071                     parent.addChildNode((DataSchemaNodeBuilder) refined);
1072                     continue;
1073                 }
1074
1075                 DataSchemaNodeBuilder newChild = null;
1076                 if (child instanceof AnyXmlBuilder) {
1077                     newChild = new AnyXmlBuilder((AnyXmlBuilder) child);
1078                 } else if (child instanceof ChoiceBuilder) {
1079                     newChild = new ChoiceBuilder((ChoiceBuilder) child);
1080                 } else if (child instanceof ContainerSchemaNodeBuilder) {
1081                     newChild = new ContainerSchemaNodeBuilder((ContainerSchemaNodeBuilder) child);
1082                 } else if (child instanceof LeafListSchemaNodeBuilder) {
1083                     newChild = new LeafListSchemaNodeBuilder((LeafListSchemaNodeBuilder) child);
1084                 } else if (child instanceof LeafSchemaNodeBuilder) {
1085                     newChild = new LeafSchemaNodeBuilder((LeafSchemaNodeBuilder) child);
1086                 } else if (child instanceof ListSchemaNodeBuilder) {
1087                     newChild = new ListSchemaNodeBuilder((ListSchemaNodeBuilder) child);
1088                 }
1089
1090                 if (newChild == null) {
1091                     throw new YangParseException(usesNode.getLine(),
1092                             "Unknown member of target grouping while resolving uses node.");
1093                 }
1094
1095                 if (newChild instanceof GroupingMember) {
1096                     ((GroupingMember) newChild).setAddedByUses(true);
1097                 }
1098
1099                 newChild.setPath(createSchemaPath(parentPath, newChild.getQName().getLocalName()));
1100                 parent.addChildNode(newChild);
1101             }
1102         }
1103         for (GroupingBuilder g : targetGrouping.getGroupingBuilders()) {
1104             GroupingBuilder newGrouping = new GroupingBuilderImpl(g);
1105             newGrouping.setAddedByUses(true);
1106             newGrouping.setPath(createSchemaPath(parentPath, newGrouping.getQName().getLocalName()));
1107             parent.addGrouping(newGrouping);
1108         }
1109         for (TypeDefinitionBuilder td : targetGrouping.getTypeDefinitionBuilders()) {
1110             TypeDefinitionBuilder newType = new TypeDefinitionBuilderImpl(td);
1111             newType.setAddedByUses(true);
1112             newType.setPath(createSchemaPath(parentPath, newType.getQName().getLocalName()));
1113             parent.addTypedef(newType);
1114         }
1115         for (UsesNodeBuilder un : targetGrouping.getUses()) {
1116             UsesNodeBuilder newUses = new UsesNodeBuilderImpl(un);
1117             newUses.setAddedByUses(true);
1118             // uses has not path
1119             parent.addUsesNode(newUses);
1120         }
1121         for (UnknownSchemaNodeBuilder un : targetGrouping.getUnknownNodeBuilders()) {
1122             UnknownSchemaNodeBuilder newUn = new UnknownSchemaNodeBuilder(un);
1123             newUn.setAddedByUses(true);
1124             newUn.setPath(createSchemaPath(parentPath, un.getQName().getLocalName()));
1125             parent.addUnknownNodeBuilder(newUn);
1126         }
1127     }
1128
1129     private void processUsesNode(final UsesNodeBuilder usesNode, final GroupingDefinition targetGrouping) {
1130         final int line = usesNode.getLine();
1131         List<SchemaNodeBuilder> refineNodes = usesNode.getRefineNodes();
1132         DataNodeContainerBuilder parent = usesNode.getParent();
1133         SchemaPath parentPath = parent.getPath();
1134         for (DataSchemaNode child : targetGrouping.getChildNodes()) {
1135             if (child != null) {
1136                 // if node is refined, take it from refined nodes and continue
1137                 SchemaNodeBuilder refined = getRefined(child.getQName(), refineNodes);
1138                 if (refined != null) {
1139                     refined.setPath(createSchemaPath(parentPath, refined.getQName().getLocalName()));
1140                     parent.addChildNode((DataSchemaNodeBuilder) refined);
1141                     continue;
1142                 }
1143
1144                 DataSchemaNodeBuilder newChild = null;
1145                 if (child instanceof AnyXmlSchemaNode) {
1146                     newChild = createAnyXml((AnyXmlSchemaNode) child, line);
1147                 } else if (child instanceof ChoiceNode) {
1148                     newChild = createChoice((ChoiceNode) child, line);
1149                 } else if (child instanceof ContainerSchemaNode) {
1150                     newChild = createContainer((ContainerSchemaNode) child, line);
1151                 } else if (child instanceof LeafListSchemaNode) {
1152                     newChild = createLeafList((LeafListSchemaNode) child, line);
1153                 } else if (child instanceof LeafSchemaNode) {
1154                     newChild = createLeafBuilder((LeafSchemaNode) child, line);
1155                 } else if (child instanceof ListSchemaNode) {
1156                     newChild = createList((ListSchemaNode) child, line);
1157                 }
1158
1159                 if (newChild == null) {
1160                     throw new YangParseException(usesNode.getLine(),
1161                             "Unknown member of target grouping while resolving uses node.");
1162                 }
1163
1164                 if (newChild instanceof GroupingMember) {
1165                     ((GroupingMember) newChild).setAddedByUses(true);
1166                 }
1167                 newChild.setPath(createSchemaPath(parentPath, newChild.getQName().getLocalName()));
1168                 parent.addChildNode(newChild);
1169             }
1170         }
1171         for (GroupingDefinition g : targetGrouping.getGroupings()) {
1172             GroupingBuilder newGrouping = createGrouping(g, line);
1173             newGrouping.setAddedByUses(true);
1174             newGrouping.setPath(createSchemaPath(parentPath, newGrouping.getQName().getLocalName()));
1175             parent.addGrouping(newGrouping);
1176         }
1177         for (TypeDefinition<?> td : targetGrouping.getTypeDefinitions()) {
1178             TypeDefinitionBuilder newType = createTypedef((ExtendedType) td, line);
1179             newType.setAddedByUses(true);
1180             newType.setPath(createSchemaPath(parentPath, newType.getQName().getLocalName()));
1181             parent.addTypedef(newType);
1182         }
1183         for (UsesNode un : targetGrouping.getUses()) {
1184             if (un instanceof UsesNodeImpl) {
1185                 UsesNodeBuilder newUses = new UsesNodeBuilderImpl(((UsesNodeImpl) un).toBuilder());
1186                 newUses.setAddedByUses(true);
1187                 // uses has not path
1188                 parent.addUsesNode(newUses);
1189             }
1190         }
1191         for (UnknownSchemaNode un : targetGrouping.getUnknownSchemaNodes()) {
1192             UnknownSchemaNodeBuilder newNode = createUnknownSchemaNode(un, line);
1193             newNode.setAddedByUses(true);
1194             newNode.setPath(createSchemaPath(parentPath, un.getQName().getLocalName()));
1195             parent.addUnknownNodeBuilder(newNode);
1196         }
1197     }
1198
1199     private QName findFullQName(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
1200             final IdentityrefTypeBuilder idref) {
1201         QName result = null;
1202         String baseString = idref.getBaseString();
1203         if (baseString.contains(":")) {
1204             String[] splittedBase = baseString.split(":");
1205             if (splittedBase.length > 2) {
1206                 throw new YangParseException(module.getName(), idref.getLine(), "Failed to parse identityref base: "
1207                         + baseString);
1208             }
1209             String prefix = splittedBase[0];
1210             String name = splittedBase[1];
1211             ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, prefix, idref.getLine());
1212             result = new QName(dependentModule.getNamespace(), dependentModule.getRevision(), prefix, name);
1213         } else {
1214             result = new QName(module.getNamespace(), module.getRevision(), module.getPrefix(), baseString);
1215         }
1216         return result;
1217     }
1218
1219     private void resolveUnknownNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
1220         for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) {
1221             QName nodeType = usnb.getNodeType();
1222             if (nodeType.getNamespace() == null || nodeType.getRevision() == null) {
1223                 try {
1224                     ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, nodeType.getPrefix(),
1225                             usnb.getLine());
1226                     QName newNodeType = new QName(dependentModule.getNamespace(), dependentModule.getRevision(),
1227                             nodeType.getPrefix(), nodeType.getLocalName());
1228                     usnb.setNodeType(newNodeType);
1229                 } catch (YangParseException e) {
1230                     LOG.debug(module.getName(), usnb.getLine(), "Failed to find unknown node type: " + nodeType);
1231                 }
1232             }
1233         }
1234     }
1235
1236     private void resolveUnknownNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1237             final ModuleBuilder module, final SchemaContext context) {
1238         for (UnknownSchemaNodeBuilder unknownNodeBuilder : module.getAllUnknownNodes()) {
1239             QName nodeType = unknownNodeBuilder.getNodeType();
1240             if (nodeType.getNamespace() == null || nodeType.getRevision() == null) {
1241                 try {
1242                     ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
1243                             nodeType.getPrefix(), unknownNodeBuilder.getLine());
1244
1245                     QName newNodeType = null;
1246                     if (dependentModuleBuilder == null) {
1247                         Module dependentModule = findModuleFromContext(context, module, nodeType.getPrefix(),
1248                                 unknownNodeBuilder.getLine());
1249                         newNodeType = new QName(dependentModule.getNamespace(), dependentModule.getRevision(),
1250                                 nodeType.getPrefix(), nodeType.getLocalName());
1251                     } else {
1252                         newNodeType = new QName(dependentModuleBuilder.getNamespace(),
1253                                 dependentModuleBuilder.getRevision(), nodeType.getPrefix(), nodeType.getLocalName());
1254                     }
1255
1256                     unknownNodeBuilder.setNodeType(newNodeType);
1257                 } catch (YangParseException e) {
1258                     LOG.debug(module.getName(), unknownNodeBuilder.getLine(), "Failed to find unknown node type: "
1259                             + nodeType);
1260                 }
1261             }
1262         }
1263     }
1264
1265     private void resolveDeviations(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
1266         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
1267             for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
1268                 ModuleBuilder b = inner.getValue();
1269                 resolveDeviation(modules, b);
1270             }
1271         }
1272     }
1273
1274     private void resolveDeviation(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
1275         for (DeviationBuilder dev : module.getDeviations()) {
1276             int line = dev.getLine();
1277             SchemaPath targetPath = dev.getTargetPath();
1278             List<QName> path = targetPath.getPath();
1279             QName q0 = path.get(0);
1280             String prefix = q0.getPrefix();
1281             if (prefix == null) {
1282                 prefix = module.getPrefix();
1283             }
1284
1285             ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, line);
1286             processDeviation(dev, dependentModuleBuilder, path, module);
1287         }
1288     }
1289
1290     private void resolveDeviationsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1291             final SchemaContext context) {
1292         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
1293             for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
1294                 ModuleBuilder b = inner.getValue();
1295                 resolveDeviationWithContext(modules, b, context);
1296             }
1297         }
1298     }
1299
1300     private void resolveDeviationWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1301             final ModuleBuilder module, final SchemaContext context) {
1302         for (DeviationBuilder dev : module.getDeviations()) {
1303             int line = dev.getLine();
1304             SchemaPath targetPath = dev.getTargetPath();
1305             List<QName> path = targetPath.getPath();
1306             QName q0 = path.get(0);
1307             String prefix = q0.getPrefix();
1308             if (prefix == null) {
1309                 prefix = module.getPrefix();
1310             }
1311             String name = null;
1312
1313             ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, line);
1314             if (dependentModuleBuilder == null) {
1315                 Module dependentModule = findModuleFromContext(context, module, prefix, line);
1316                 Object currentParent = dependentModule;
1317
1318                 for (int i = 0; i < path.size(); i++) {
1319                     if (currentParent == null) {
1320                         throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
1321                     }
1322                     QName q = path.get(i);
1323                     name = q.getLocalName();
1324                     if (currentParent instanceof DataNodeContainer) {
1325                         currentParent = ((DataNodeContainer) currentParent).getDataChildByName(name);
1326                     }
1327                 }
1328
1329                 if (currentParent == null) {
1330                     throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
1331                 }
1332                 if (currentParent instanceof SchemaNode) {
1333                     dev.setTargetPath(((SchemaNode) currentParent).getPath());
1334                 }
1335
1336             } else {
1337                 processDeviation(dev, dependentModuleBuilder, path, module);
1338             }
1339         }
1340     }
1341
1342     /**
1343      * Correct deviation target path in deviation builder.
1344      *
1345      * @param dev
1346      *            deviation
1347      * @param dependentModuleBuilder
1348      *            module containing deviation target
1349      * @param path
1350      *            current deviation target path
1351      * @param module
1352      *            current module
1353      */
1354     private void processDeviation(final DeviationBuilder dev, final ModuleBuilder dependentModuleBuilder,
1355             final List<QName> path, final ModuleBuilder module) {
1356         final int line = dev.getLine();
1357         Builder currentParent = dependentModuleBuilder;
1358
1359         for (int i = 0; i < path.size(); i++) {
1360             if (currentParent == null) {
1361                 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
1362             }
1363             QName q = path.get(i);
1364             String name = q.getLocalName();
1365             if (currentParent instanceof DataNodeContainerBuilder) {
1366                 currentParent = ((DataNodeContainerBuilder) currentParent).getDataChildByName(name);
1367             }
1368         }
1369
1370         if (currentParent == null || !(currentParent instanceof SchemaNodeBuilder)) {
1371             throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
1372         }
1373         dev.setTargetPath(((SchemaNodeBuilder) currentParent).getPath());
1374     }
1375
1376 }