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