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