6adc29b2271ce956fed15035084b1a3f9f7f77b0
[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, dependentModule,
440                 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,
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, dependentModule, ut
539                         .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, dependentModule,
550                             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, dependentModuleBuilder,
585                             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,
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.getAllAugments().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.getAllAugments().size()) {
674             for (AugmentationSchemaBuilder augmentBuilder : module.getAllAugments()) {
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, 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.getAllAugments().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.getAllAugments().size()) {
749
750             for (AugmentationSchemaBuilder augmentBuilder : module.getAllAugments()) {
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, 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 List<UsesNodeBuilder> allModuleUses = module.getAllUsesNodes();
879         for (UsesNodeBuilder usesNode : allModuleUses) {
880             // refine
881             final int line = usesNode.getLine();
882             final GroupingBuilder targetGrouping = getTargetGroupingFromModules(usesNode, modules, module);
883             usesNode.setGroupingPath(targetGrouping.getPath());
884             for (RefineHolder refine : usesNode.getRefines()) {
885                 final SchemaNodeBuilder nodeToRefine = RefineUtils.getRefineNodeFromGroupingBuilder(targetGrouping,
886                         refine, module.getName());
887                 if (nodeToRefine instanceof GroupingMember) {
888                     ((GroupingMember) nodeToRefine).setAddedByUses(true);
889                 }
890                 RefineUtils.performRefine(nodeToRefine, refine, line);
891                 usesNode.addRefineNode(nodeToRefine);
892             }
893
894             // child nodes
895             processUsesNode(usesNode, targetGrouping);
896         }
897     }
898
899     /**
900      * Tries to search target grouping in given modules and resolve refine
901      * nodes. If grouping is not found in modules, method tries to find it in
902      * modules from context.
903      *
904      * @param modules
905      *            all loaded modules
906      * @param module
907      *            current module
908      * @param context
909      *            SchemaContext containing already resolved modules
910      */
911     private void resolveUsesRefineWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
912             final ModuleBuilder module, final SchemaContext context) {
913         final List<UsesNodeBuilder> moduleUses = module.getAllUsesNodes();
914         for (UsesNodeBuilder usesNode : moduleUses) {
915             final int line = usesNode.getLine();
916
917             final GroupingBuilder targetGroupingBuilder = getTargetGroupingFromModules(usesNode, modules, module);
918             if (targetGroupingBuilder == null) {
919                 final GroupingDefinition targetGrouping = getTargetGroupingFromContext(usesNode, module, context);
920                 usesNode.setGroupingPath(targetGrouping.getPath());
921                 for (RefineHolder refine : usesNode.getRefines()) {
922                     final SchemaNodeBuilder nodeToRefine = RefineUtils.getRefineNodeFromGroupingDefinition(
923                             targetGrouping, refine, module.getName());
924                     if (nodeToRefine instanceof GroupingMember) {
925                         ((GroupingMember) nodeToRefine).setAddedByUses(true);
926                     }
927                     RefineUtils.performRefine(nodeToRefine, refine, line);
928                     usesNode.addRefineNode(nodeToRefine);
929                 }
930
931                 processUsesNode(usesNode, targetGrouping);
932             } else {
933                 usesNode.setGroupingPath(targetGroupingBuilder.getPath());
934                 for (RefineHolder refine : usesNode.getRefines()) {
935                     final SchemaNodeBuilder nodeToRefine = RefineUtils.getRefineNodeFromGroupingBuilder(
936                             targetGroupingBuilder, refine, module.getName());
937                     if (nodeToRefine instanceof GroupingMember) {
938                         ((GroupingMember) nodeToRefine).setAddedByUses(true);
939                     }
940                     RefineUtils.performRefine(nodeToRefine, refine, line);
941                     usesNode.addRefineNode(nodeToRefine);
942                 }
943
944                 processUsesNode(usesNode, targetGroupingBuilder);
945             }
946         }
947     }
948
949     /**
950      * Search given modules for grouping by name defined in uses node.
951      *
952      * @param usesBuilder
953      *            builder of uses statement
954      * @param modules
955      *            all loaded modules
956      * @param module
957      *            current module
958      * @return grouping with given name if found, null otherwise
959      */
960     private GroupingBuilder getTargetGroupingFromModules(final UsesNodeBuilder usesBuilder,
961             final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
962         final int line = usesBuilder.getLine();
963         final String groupingString = usesBuilder.getGroupingName();
964         String groupingPrefix;
965         String groupingName;
966
967         if (groupingString.contains(":")) {
968             String[] splitted = groupingString.split(":");
969             if (splitted.length != 2 || groupingString.contains("/")) {
970                 throw new YangParseException(module.getName(), line, "Invalid name of target grouping");
971             }
972             groupingPrefix = splitted[0];
973             groupingName = splitted[1];
974         } else {
975             groupingPrefix = module.getPrefix();
976             groupingName = groupingString;
977         }
978
979         ModuleBuilder dependentModule = null;
980         if (groupingPrefix.equals(module.getPrefix())) {
981             dependentModule = module;
982         } else {
983             dependentModule = findDependentModuleBuilder(modules, module, groupingPrefix, line);
984         }
985
986         if (dependentModule == null) {
987             return null;
988         }
989
990         GroupingBuilder result = null;
991         Set<GroupingBuilder> groupings = dependentModule.getGroupingBuilders();
992         result = findGroupingBuilder(groupings, groupingName);
993         if (result != null) {
994             return result;
995         }
996
997         Builder parent = usesBuilder.getParent();
998
999         while (parent != null) {
1000             if (parent instanceof DataNodeContainerBuilder) {
1001                 groupings = ((DataNodeContainerBuilder) parent).getGroupingBuilders();
1002             } else if (parent instanceof RpcDefinitionBuilder) {
1003                 groupings = ((RpcDefinitionBuilder) parent).getGroupings();
1004             }
1005             result = findGroupingBuilder(groupings, groupingName);
1006             if (result == null) {
1007                 parent = parent.getParent();
1008             } else {
1009                 break;
1010             }
1011         }
1012
1013         if (result == null) {
1014             throw new YangParseException(module.getName(), line, "Referenced grouping '" + groupingName
1015                     + "' not found.");
1016         }
1017         return result;
1018     }
1019
1020     /**
1021      * Search context for grouping by name defined in uses node.
1022      *
1023      * @param usesBuilder
1024      *            builder of uses statement
1025      * @param module
1026      *            current module
1027      * @param context
1028      *            SchemaContext containing already resolved modules
1029      * @return grouping with given name if found, null otherwise
1030      */
1031     private GroupingDefinition getTargetGroupingFromContext(final UsesNodeBuilder usesBuilder,
1032             final ModuleBuilder module, final SchemaContext context) {
1033         final int line = usesBuilder.getLine();
1034         String groupingString = usesBuilder.getGroupingName();
1035         String groupingPrefix;
1036         String groupingName;
1037
1038         if (groupingString.contains(":")) {
1039             String[] splitted = groupingString.split(":");
1040             if (splitted.length != 2 || groupingString.contains("/")) {
1041                 throw new YangParseException(module.getName(), line, "Invalid name of target grouping");
1042             }
1043             groupingPrefix = splitted[0];
1044             groupingName = splitted[1];
1045         } else {
1046             groupingPrefix = module.getPrefix();
1047             groupingName = groupingString;
1048         }
1049
1050         Module dependentModule = findModuleFromContext(context, module, groupingPrefix, line);
1051         return findGroupingDefinition(dependentModule.getGroupings(), groupingName);
1052     }
1053
1054     /**
1055      * Add nodes defined in target grouping to current context.
1056      *
1057      * @param usesNode
1058      * @param targetGrouping
1059      */
1060     private void processUsesNode(final UsesNodeBuilder usesNode, final GroupingBuilder targetGrouping) {
1061         List<SchemaNodeBuilder> refineNodes = usesNode.getRefineNodes();
1062         DataNodeContainerBuilder parent = usesNode.getParent();
1063         SchemaPath parentPath = parent.getPath();
1064         for (DataSchemaNodeBuilder child : targetGrouping.getChildNodeBuilders()) {
1065             // if node is refined, take it from refined nodes and continue
1066             SchemaNodeBuilder refined = getRefined(child.getQName(), refineNodes);
1067             if (refined != null) {
1068                 refined.setPath(createSchemaPath(parentPath, refined.getQName().getLocalName()));
1069                 parent.addChildNode((DataSchemaNodeBuilder) refined);
1070                 continue;
1071             }
1072
1073             DataSchemaNodeBuilder newChild = null;
1074             if (child instanceof AnyXmlBuilder) {
1075                 newChild = new AnyXmlBuilder((AnyXmlBuilder) child);
1076             } else if (child instanceof ChoiceBuilder) {
1077                 newChild = new ChoiceBuilder((ChoiceBuilder) child);
1078             } else if (child instanceof ContainerSchemaNodeBuilder) {
1079                 newChild = new ContainerSchemaNodeBuilder((ContainerSchemaNodeBuilder) child);
1080             } else if (child instanceof LeafListSchemaNodeBuilder) {
1081                 newChild = new LeafListSchemaNodeBuilder((LeafListSchemaNodeBuilder) child);
1082             } else if (child instanceof LeafSchemaNodeBuilder) {
1083                 newChild = new LeafSchemaNodeBuilder((LeafSchemaNodeBuilder) child);
1084             } else if (child instanceof ListSchemaNodeBuilder) {
1085                 newChild = new ListSchemaNodeBuilder((ListSchemaNodeBuilder) child);
1086             }
1087
1088             if (newChild instanceof GroupingMember) {
1089                 ((GroupingMember) newChild).setAddedByUses(true);
1090             }
1091             newChild.setPath(createSchemaPath(parentPath, newChild.getQName().getLocalName()));
1092             parent.addChildNode(newChild);
1093         }
1094         for (GroupingBuilder g : targetGrouping.getGroupingBuilders()) {
1095             GroupingBuilder newGrouping = new GroupingBuilderImpl(g);
1096             newGrouping.setAddedByUses(true);
1097             newGrouping.setPath(createSchemaPath(parentPath, newGrouping.getQName().getLocalName()));
1098             parent.addGrouping(newGrouping);
1099         }
1100         for (TypeDefinitionBuilder td : targetGrouping.getTypeDefinitionBuilders()) {
1101             TypeDefinitionBuilder newType = new TypeDefinitionBuilderImpl(td);
1102             newType.setAddedByUses(true);
1103             newType.setPath(createSchemaPath(parentPath, newType.getQName().getLocalName()));
1104             parent.addTypedef(newType);
1105         }
1106         for (UsesNodeBuilder un : targetGrouping.getUses()) {
1107             UsesNodeBuilder newUses = new UsesNodeBuilderImpl(un);
1108             newUses.setAddedByUses(true);
1109             // uses has not path
1110             parent.addUsesNode(newUses);
1111         }
1112         for (UnknownSchemaNodeBuilder un : targetGrouping.getUnknownNodes()) {
1113             UnknownSchemaNodeBuilder newUn = new UnknownSchemaNodeBuilder(un);
1114             newUn.setAddedByUses(true);
1115             newUn.setPath(createSchemaPath(parentPath, un.getQName().getLocalName()));
1116             parent.addUnknownSchemaNode(newUn);
1117         }
1118     }
1119
1120     private void processUsesNode(final UsesNodeBuilder usesNode, final GroupingDefinition targetGrouping) {
1121         final int line = usesNode.getLine();
1122         List<SchemaNodeBuilder> refineNodes = usesNode.getRefineNodes();
1123         DataNodeContainerBuilder parent = usesNode.getParent();
1124         SchemaPath parentPath = parent.getPath();
1125         for (DataSchemaNode child : targetGrouping.getChildNodes()) {
1126             // if node is refined, take it from refined nodes and continue
1127             SchemaNodeBuilder refined = getRefined(child.getQName(), refineNodes);
1128             if (refined != null) {
1129                 refined.setPath(createSchemaPath(parentPath, refined.getQName().getLocalName()));
1130                 parent.addChildNode((DataSchemaNodeBuilder) refined);
1131                 continue;
1132             }
1133
1134             DataSchemaNodeBuilder newChild = null;
1135             if (child instanceof AnyXmlSchemaNode) {
1136                 newChild = createAnyXml((AnyXmlSchemaNode) child, line);
1137             } else if (child instanceof ChoiceNode) {
1138                 newChild = createChoice((ChoiceNode) child, line);
1139             } else if (child instanceof ContainerSchemaNode) {
1140                 newChild = createContainer((ContainerSchemaNode) child, line);
1141             } else if (child instanceof LeafListSchemaNode) {
1142                 newChild = createLeafList((LeafListSchemaNode) child, line);
1143             } else if (child instanceof LeafSchemaNode) {
1144                 newChild = createLeafBuilder((LeafSchemaNode) child, line);
1145             } else if (child instanceof ListSchemaNode) {
1146                 newChild = createList((ListSchemaNode) child, line);
1147             }
1148
1149             if (newChild instanceof GroupingMember) {
1150                 ((GroupingMember) newChild).setAddedByUses(true);
1151             }
1152             newChild.setPath(createSchemaPath(parentPath, newChild.getQName().getLocalName()));
1153             parent.addChildNode(newChild);
1154         }
1155         for (GroupingDefinition g : targetGrouping.getGroupings()) {
1156             GroupingBuilder newGrouping = createGrouping(g, line);
1157             newGrouping.setAddedByUses(true);
1158             newGrouping.setPath(createSchemaPath(parentPath, newGrouping.getQName().getLocalName()));
1159             parent.addGrouping(newGrouping);
1160         }
1161         for (TypeDefinition<?> td : targetGrouping.getTypeDefinitions()) {
1162             TypeDefinitionBuilder newType = createTypedef((ExtendedType) td, line);
1163             newType.setAddedByUses(true);
1164             newType.setPath(createSchemaPath(parentPath, newType.getQName().getLocalName()));
1165             parent.addTypedef(newType);
1166         }
1167         for (UsesNode un : targetGrouping.getUses()) {
1168             if (un instanceof UsesNodeImpl) {
1169                 UsesNodeBuilder newUses = new UsesNodeBuilderImpl(((UsesNodeImpl) un).toBuilder());
1170                 newUses.setAddedByUses(true);
1171                 // uses has not path
1172                 parent.addUsesNode(newUses);
1173             }
1174         }
1175         for (UnknownSchemaNode un : targetGrouping.getUnknownSchemaNodes()) {
1176             UnknownSchemaNodeBuilder newNode = createUnknownSchemaNode(un, line);
1177             newNode.setAddedByUses(true);
1178             newNode.setPath(createSchemaPath(parentPath, un.getQName().getLocalName()));
1179             parent.addUnknownSchemaNode(newNode);
1180         }
1181     }
1182
1183     private QName findFullQName(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
1184             final IdentityrefTypeBuilder idref) {
1185         QName result = null;
1186         String baseString = idref.getBaseString();
1187         if (baseString.contains(":")) {
1188             String[] splittedBase = baseString.split(":");
1189             if (splittedBase.length > 2) {
1190                 throw new YangParseException(module.getName(), idref.getLine(), "Failed to parse identityref base: "
1191                         + baseString);
1192             }
1193             String prefix = splittedBase[0];
1194             String name = splittedBase[1];
1195             ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, prefix, idref.getLine());
1196             result = new QName(dependentModule.getNamespace(), dependentModule.getRevision(), prefix, name);
1197         } else {
1198             result = new QName(module.getNamespace(), module.getRevision(), module.getPrefix(), baseString);
1199         }
1200         return result;
1201     }
1202
1203     private void resolveUnknownNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
1204         for (UnknownSchemaNodeBuilder usnb : module.getUnknownNodes()) {
1205             QName nodeType = usnb.getNodeType();
1206             if (nodeType.getNamespace() == null || nodeType.getRevision() == null) {
1207                 try {
1208                     ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, nodeType.getPrefix(),
1209                             usnb.getLine());
1210                     QName newNodeType = new QName(dependentModule.getNamespace(), dependentModule.getRevision(),
1211                             nodeType.getPrefix(), nodeType.getLocalName());
1212                     usnb.setNodeType(newNodeType);
1213                 } catch (YangParseException e) {
1214                     logger.debug(module.getName(), usnb.getLine(), "Failed to find unknown node type: " + nodeType);
1215                 }
1216             }
1217         }
1218     }
1219
1220     private void resolveUnknownNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1221             final ModuleBuilder module, SchemaContext context) {
1222         for (UnknownSchemaNodeBuilder unknownNodeBuilder : module.getUnknownNodes()) {
1223             QName nodeType = unknownNodeBuilder.getNodeType();
1224             if (nodeType.getNamespace() == null || nodeType.getRevision() == null) {
1225                 try {
1226                     ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
1227                             nodeType.getPrefix(), unknownNodeBuilder.getLine());
1228
1229                     QName newNodeType = null;
1230                     if (dependentModuleBuilder == null) {
1231                         Module dependentModule = findModuleFromContext(context, module, nodeType.getPrefix(),
1232                                 unknownNodeBuilder.getLine());
1233                         newNodeType = new QName(dependentModule.getNamespace(), dependentModule.getRevision(),
1234                                 nodeType.getPrefix(), nodeType.getLocalName());
1235                     } else {
1236                         newNodeType = new QName(dependentModuleBuilder.getNamespace(),
1237                                 dependentModuleBuilder.getRevision(), nodeType.getPrefix(), nodeType.getLocalName());
1238                     }
1239
1240                     unknownNodeBuilder.setNodeType(newNodeType);
1241                 } catch (YangParseException e) {
1242                     logger.debug(module.getName(), unknownNodeBuilder.getLine(), "Failed to find unknown node type: "
1243                             + nodeType);
1244                 }
1245             }
1246         }
1247     }
1248
1249 }