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