2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.controller.yang.parser.impl;
10 import static org.opendaylight.controller.yang.parser.util.ParserUtils.*;
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;
27 import java.util.Map.Entry;
28 import java.util.NoSuchElementException;
30 import java.util.TreeMap;
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.GroupingDefinition;
40 import org.opendaylight.controller.yang.model.api.IdentitySchemaNode;
41 import org.opendaylight.controller.yang.model.api.Module;
42 import org.opendaylight.controller.yang.model.api.SchemaContext;
43 import org.opendaylight.controller.yang.model.api.SchemaPath;
44 import org.opendaylight.controller.yang.model.api.TypeDefinition;
45 import org.opendaylight.controller.yang.model.parser.api.YangModelParser;
46 import org.opendaylight.controller.yang.model.util.ExtendedType;
47 import org.opendaylight.controller.yang.model.util.IdentityrefType;
48 import org.opendaylight.controller.yang.model.util.UnknownType;
49 import org.opendaylight.controller.yang.parser.builder.api.AugmentationSchemaBuilder;
50 import org.opendaylight.controller.yang.parser.builder.api.Builder;
51 import org.opendaylight.controller.yang.parser.builder.api.DataNodeContainerBuilder;
52 import org.opendaylight.controller.yang.parser.builder.api.GroupingBuilder;
53 import org.opendaylight.controller.yang.parser.builder.api.SchemaNodeBuilder;
54 import org.opendaylight.controller.yang.parser.builder.api.TypeAwareBuilder;
55 import org.opendaylight.controller.yang.parser.builder.api.TypeDefinitionBuilder;
56 import org.opendaylight.controller.yang.parser.builder.api.UsesNodeBuilder;
57 import org.opendaylight.controller.yang.parser.builder.impl.IdentitySchemaNodeBuilder;
58 import org.opendaylight.controller.yang.parser.builder.impl.IdentityrefTypeBuilder;
59 import org.opendaylight.controller.yang.parser.builder.impl.ModuleBuilder;
60 import org.opendaylight.controller.yang.parser.builder.impl.RpcDefinitionBuilder;
61 import org.opendaylight.controller.yang.parser.builder.impl.UnionTypeBuilder;
62 import org.opendaylight.controller.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
63 import org.opendaylight.controller.yang.parser.util.ModuleDependencySort;
64 import org.opendaylight.controller.yang.parser.util.RefineHolder;
65 import org.opendaylight.controller.yang.parser.util.RefineUtils;
66 import org.opendaylight.controller.yang.parser.util.TypeConstraints;
67 import org.opendaylight.controller.yang.parser.util.YangParseException;
68 import org.opendaylight.controller.yang.validator.YangModelBasicValidator;
69 import org.slf4j.Logger;
70 import org.slf4j.LoggerFactory;
72 import com.google.common.collect.Lists;
73 import com.google.common.collect.Maps;
74 import com.google.common.collect.Sets;
76 public final class YangParserImpl implements YangModelParser {
78 private static final Logger logger = LoggerFactory.getLogger(YangParserImpl.class);
81 public Set<Module> parseYangModels(final List<File> yangFiles) {
82 return Sets.newLinkedHashSet(parseYangModelsMapped(yangFiles).values());
86 public Set<Module> parseYangModels(final List<File> yangFiles, final SchemaContext context) {
87 if (yangFiles != null) {
88 final Map<InputStream, File> inputStreams = Maps.newHashMap();
90 for (final File yangFile : yangFiles) {
92 inputStreams.put(new FileInputStream(yangFile), yangFile);
93 } catch (FileNotFoundException e) {
94 logger.warn("Exception while reading yang file: " + yangFile.getName(), e);
98 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
100 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
101 Lists.newArrayList(inputStreams.keySet()), builderToStreamMap);
103 for (InputStream is : inputStreams.keySet()) {
106 } catch (IOException e) {
107 logger.debug("Failed to close stream.");
111 return new LinkedHashSet<Module>(buildWithContext(modules, context).values());
113 return Collections.emptySet();
117 public Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams) {
118 return Sets.newHashSet(parseYangModelsFromStreamsMapped(yangModelStreams).values());
122 public Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams, SchemaContext context) {
123 if (yangModelStreams != null) {
124 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
125 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersWithContext(
126 yangModelStreams, builderToStreamMap, context);
127 return new LinkedHashSet<Module>(buildWithContext(modules, context).values());
129 return Collections.emptySet();
133 public Map<File, Module> parseYangModelsMapped(List<File> yangFiles) {
134 if (yangFiles != null) {
135 final Map<InputStream, File> inputStreams = Maps.newHashMap();
137 for (final File yangFile : yangFiles) {
139 inputStreams.put(new FileInputStream(yangFile), yangFile);
140 } catch (FileNotFoundException e) {
141 logger.warn("Exception while reading yang file: " + yangFile.getName(), e);
145 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
146 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
147 Lists.newArrayList(inputStreams.keySet()), builderToStreamMap);
149 for (InputStream is : inputStreams.keySet()) {
152 } catch (IOException e) {
153 logger.debug("Failed to close stream.");
157 Map<File, Module> retVal = Maps.newLinkedHashMap();
158 Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
160 for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap.entrySet()) {
161 retVal.put(inputStreams.get(builderToStreamMap.get(builderToModule.getKey())),
162 builderToModule.getValue());
167 return Collections.emptyMap();
171 public Map<InputStream, Module> parseYangModelsFromStreamsMapped(final List<InputStream> yangModelStreams) {
172 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
174 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangModelStreams,
176 Map<InputStream, Module> retVal = Maps.newLinkedHashMap();
177 Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
179 for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap.entrySet()) {
180 retVal.put(builderToStreamMap.get(builderToModule.getKey()), builderToModule.getValue());
186 public SchemaContext resolveSchemaContext(final Set<Module> modules) {
187 return new SchemaContextImpl(modules);
190 private ModuleBuilder[] parseModuleBuilders(List<InputStream> inputStreams,
191 Map<ModuleBuilder, InputStream> streamToBuilderMap) {
193 final ParseTreeWalker walker = new ParseTreeWalker();
194 final List<ParseTree> trees = parseStreams(inputStreams);
195 final ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
198 new YangModelBasicValidator(walker).validate(trees);
200 YangParserListenerImpl yangModelParser = null;
201 for (int i = 0; i < trees.size(); i++) {
202 yangModelParser = new YangParserListenerImpl();
203 walker.walk(yangModelParser, trees.get(i));
204 ModuleBuilder moduleBuilder = yangModelParser.getModuleBuilder();
206 // We expect the order of trees and streams has to be the same
207 streamToBuilderMap.put(moduleBuilder, inputStreams.get(i));
208 builders[i] = moduleBuilder;
213 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(final List<InputStream> yangFileStreams,
214 Map<ModuleBuilder, InputStream> streamToBuilderMap) {
215 return resolveModuleBuildersWithContext(yangFileStreams, streamToBuilderMap, null);
218 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuildersWithContext(
219 final List<InputStream> yangFileStreams, final Map<ModuleBuilder, InputStream> streamToBuilderMap,
220 final SchemaContext context) {
221 final ModuleBuilder[] builders = parseModuleBuilders(yangFileStreams, streamToBuilderMap);
223 // Linked Hash Map MUST be used because Linked Hash Map preserves ORDER
224 // of items stored in map.
225 final LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> modules = new LinkedHashMap<String, TreeMap<Date, ModuleBuilder>>();
227 // module dependency graph sorted
228 List<ModuleBuilder> sorted = null;
229 if (context == null) {
230 sorted = ModuleDependencySort.sort(builders);
232 sorted = ModuleDependencySort.sortWithContext(context, builders);
235 for (final ModuleBuilder builder : sorted) {
236 if (builder == null) {
239 final String builderName = builder.getName();
240 Date builderRevision = builder.getRevision();
241 if (builderRevision == null) {
242 builderRevision = new Date(0L);
244 TreeMap<Date, ModuleBuilder> builderByRevision = modules.get(builderName);
245 if (builderByRevision == null) {
246 builderByRevision = new TreeMap<Date, ModuleBuilder>();
248 builderByRevision.put(builderRevision, builder);
249 modules.put(builderName, builderByRevision);
254 private List<ParseTree> parseStreams(final List<InputStream> yangStreams) {
255 final List<ParseTree> trees = new ArrayList<ParseTree>();
256 for (InputStream yangStream : yangStreams) {
257 trees.add(parseStream(yangStream));
262 private ParseTree parseStream(final InputStream yangStream) {
263 ParseTree result = null;
265 final ANTLRInputStream input = new ANTLRInputStream(yangStream);
266 final YangLexer lexer = new YangLexer(input);
267 final CommonTokenStream tokens = new CommonTokenStream(lexer);
268 final YangParser parser = new YangParser(tokens);
269 parser.removeErrorListeners();
270 parser.addErrorListener(new YangErrorListener());
272 result = parser.yang();
273 } catch (IOException e) {
274 logger.warn("Exception while reading yang file: " + yangStream, e);
279 private Map<ModuleBuilder, Module> build(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
280 // fix unresolved nodes
281 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
282 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
283 final ModuleBuilder moduleBuilder = childEntry.getValue();
284 fixUnresolvedNodes(modules, moduleBuilder);
287 resolveAugments(modules);
290 // LinkedHashMap MUST be used otherwise the values will not maintain
292 // http://docs.oracle.com/javase/6/docs/api/java/util/LinkedHashMap.html
293 final Map<ModuleBuilder, Module> result = new LinkedHashMap<ModuleBuilder, Module>();
294 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
295 final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
296 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
297 final ModuleBuilder moduleBuilder = childEntry.getValue();
298 final Module module = moduleBuilder.build();
299 modulesByRevision.put(childEntry.getKey(), module);
300 result.put(moduleBuilder, module);
306 private Map<ModuleBuilder, Module> buildWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
307 SchemaContext context) {
308 // fix unresolved nodes
309 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
310 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
311 final ModuleBuilder moduleBuilder = childEntry.getValue();
312 fixUnresolvedNodesWithContext(modules, moduleBuilder, context);
315 resolveAugmentsWithContext(modules, context);
318 // LinkedHashMap MUST be used otherwise the values will not maintain
320 // http://docs.oracle.com/javase/6/docs/api/java/util/LinkedHashMap.html
321 final Map<ModuleBuilder, Module> result = new LinkedHashMap<ModuleBuilder, Module>();
322 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
323 final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
324 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
325 final ModuleBuilder moduleBuilder = childEntry.getValue();
326 final Module module = moduleBuilder.build();
327 modulesByRevision.put(childEntry.getKey(), module);
328 result.put(moduleBuilder, module);
334 private void fixUnresolvedNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder builder) {
335 resolveDirtyNodes(modules, builder);
336 resolveIdentities(modules, builder);
337 resolveUsesRefine(modules, builder);
338 resolveUnknownNodes(modules, builder);
341 private void fixUnresolvedNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
342 final ModuleBuilder builder, final SchemaContext context) {
343 resolveDirtyNodesWithContext(modules, builder, context);
344 resolveIdentitiesWithContext(modules, builder, context);
345 resolveUsesRefineWithContext(modules, builder, context);
346 resolveUnknownNodesWithContext(modules, builder, context);
350 * Search for dirty nodes (node which contains UnknownType) and resolve
354 * all available modules
358 private void resolveDirtyNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
359 final Map<List<String>, TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
360 if (!dirtyNodes.isEmpty()) {
361 for (Map.Entry<List<String>, TypeAwareBuilder> entry : dirtyNodes.entrySet()) {
362 final TypeAwareBuilder nodeToResolve = entry.getValue();
364 if (nodeToResolve instanceof UnionTypeBuilder) {
365 // special handling for union types
366 resolveTypeUnion((UnionTypeBuilder) nodeToResolve, modules, module);
367 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
368 // special handling for identityref types
369 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
370 nodeToResolve.setType(new IdentityrefType(findFullQName(modules, module, idref), idref.getPath()));
372 resolveType(nodeToResolve, modules, module);
378 private void resolveDirtyNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
379 final ModuleBuilder module, SchemaContext context) {
380 final Map<List<String>, TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
381 if (!dirtyNodes.isEmpty()) {
382 for (Map.Entry<List<String>, TypeAwareBuilder> entry : dirtyNodes.entrySet()) {
383 final TypeAwareBuilder nodeToResolve = entry.getValue();
385 if (nodeToResolve instanceof UnionTypeBuilder) {
386 // special handling for union types
387 resolveTypeUnionWithContext((UnionTypeBuilder) nodeToResolve, modules, module, context);
388 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
389 // special handling for identityref types
390 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
391 nodeToResolve.setType(new IdentityrefType(findFullQName(modules, module, idref), idref.getPath()));
393 resolveTypeWithContext(nodeToResolve, modules, module, context);
400 * Resolve unknown type of node. It is assumed that type of node is either
401 * UnknownType or ExtendedType with UnknownType as base type.
403 * @param nodeToResolve
404 * node with type to resolve
410 private void resolveType(final TypeAwareBuilder nodeToResolve,
411 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
412 TypeDefinitionBuilder resolvedType = null;
413 final int line = nodeToResolve.getLine();
414 final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
415 final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
416 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, unknownTypeQName.getPrefix(),
419 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(nodeToResolve.getPath(),
420 dependentModule, unknownTypeQName.getLocalName(), module.getName(), line);
422 if (nodeToResolveType instanceof ExtendedType) {
423 final ExtendedType extType = (ExtendedType) nodeToResolveType;
424 final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder, extType,
425 modules, module, nodeToResolve.getLine());
426 resolvedType = newType;
428 resolvedType = targetTypeBuilder;
431 // validate constraints
432 final TypeConstraints constraints = findConstraintsFromTypeBuilder(nodeToResolve,
433 new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module, null);
434 constraints.validateConstraints();
436 nodeToResolve.setTypedef(resolvedType);
440 * Resolve unknown type of node. It is assumed that type of node is either
441 * UnknownType or ExtendedType with UnknownType as base type.
443 * @param nodeToResolve
444 * node with type to resolve
450 * SchemaContext containing already resolved modules
452 private void resolveTypeWithContext(final TypeAwareBuilder nodeToResolve,
453 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
454 final SchemaContext context) {
455 TypeDefinitionBuilder resolvedType = null;
456 final int line = nodeToResolve.getLine();
457 final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
458 final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
459 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
460 unknownTypeQName.getPrefix(), line);
462 if (dependentModuleBuilder == null) {
463 final Module dependentModule = findModuleFromContext(context, module, unknownTypeQName.getPrefix(), line);
464 final Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
465 final TypeDefinition<?> type = findTypeByName(types, unknownTypeQName.getLocalName());
467 if (nodeToResolveType instanceof ExtendedType) {
468 final ExtendedType extType = (ExtendedType) nodeToResolveType;
469 final TypeDefinitionBuilder newType = extendedTypeWithNewBaseType(type, extType, module,
470 nodeToResolve.getLine());
472 nodeToResolve.setTypedef(newType);
474 if(nodeToResolve instanceof TypeDefinitionBuilder) {
475 TypeDefinitionBuilder tdb = (TypeDefinitionBuilder)nodeToResolve;
476 TypeConstraints tc = findConstraintsFromTypeBuilder(nodeToResolve, new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module, context);
477 tdb.setLengths(tc.getLength());
478 tdb.setPatterns(tc.getPatterns());
479 tdb.setRanges(tc.getRange());
480 tdb.setFractionDigits(tc.getFractionDigits());
482 nodeToResolve.setType(type);
486 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(nodeToResolve.getPath(),
487 dependentModuleBuilder, unknownTypeQName.getLocalName(), module.getName(), line);
489 if (nodeToResolveType instanceof ExtendedType) {
490 final ExtendedType extType = (ExtendedType) nodeToResolveType;
491 final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder, extType,
492 modules, module, nodeToResolve.getLine());
493 resolvedType = newType;
495 resolvedType = targetTypeBuilder;
498 // validate constraints
499 final TypeConstraints constraints = findConstraintsFromTypeBuilder(nodeToResolve, new TypeConstraints(
500 module.getName(), nodeToResolve.getLine()), modules, module, context);
501 constraints.validateConstraints();
503 nodeToResolve.setTypedef(resolvedType);
507 private void resolveTypeUnion(final UnionTypeBuilder union,
508 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder builder) {
510 final List<TypeDefinition<?>> unionTypes = union.getTypes();
511 final List<TypeDefinition<?>> toRemove = new ArrayList<TypeDefinition<?>>();
512 for (TypeDefinition<?> unionType : unionTypes) {
513 if (unionType instanceof UnknownType) {
514 final UnknownType ut = (UnknownType) unionType;
515 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, builder, ut.getQName()
516 .getPrefix(), union.getLine());
517 final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union.getPath(), dependentModule,
518 ut.getQName().getLocalName(), builder.getName(), union.getLine());
519 union.setTypedef(resolvedType);
521 } else if (unionType instanceof ExtendedType) {
522 final ExtendedType extType = (ExtendedType) unionType;
523 final TypeDefinition<?> extTypeBase = extType.getBaseType();
524 if (extTypeBase instanceof UnknownType) {
525 final UnknownType ut = (UnknownType) extTypeBase;
526 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, builder, ut.getQName()
527 .getPrefix(), union.getLine());
528 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union.getPath(),
529 dependentModule, ut.getQName().getLocalName(), builder.getName(), union.getLine());
531 final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder,
532 extType, modules, builder, union.getLine());
534 union.setTypedef(newType);
535 toRemove.add(extType);
539 unionTypes.removeAll(toRemove);
542 private void resolveTypeUnionWithContext(final UnionTypeBuilder union,
543 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder builder,
544 final SchemaContext context) {
546 final List<TypeDefinition<?>> unionTypes = union.getTypes();
547 final List<TypeDefinition<?>> toRemove = new ArrayList<TypeDefinition<?>>();
548 for (TypeDefinition<?> unionType : unionTypes) {
549 if (unionType instanceof UnknownType) {
550 final UnknownType ut = (UnknownType) unionType;
551 final QName utQName = ut.getQName();
552 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, builder,
553 utQName.getPrefix(), union.getLine());
555 if (dependentModuleBuilder == null) {
556 Module dependentModule = findModuleFromContext(context, builder, utQName.getPrefix(),
558 Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
559 TypeDefinition<?> type = findTypeByName(types, utQName.getLocalName());
563 final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union.getPath(),
564 dependentModuleBuilder, utQName.getLocalName(), builder.getName(), union.getLine());
565 union.setTypedef(resolvedType);
569 } else if (unionType instanceof ExtendedType) {
570 final ExtendedType extType = (ExtendedType) unionType;
571 TypeDefinition<?> extTypeBase = extType.getBaseType();
572 if (extTypeBase instanceof UnknownType) {
573 final UnknownType ut = (UnknownType) extTypeBase;
574 final QName utQName = ut.getQName();
575 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, builder,
576 utQName.getPrefix(), union.getLine());
578 if (dependentModuleBuilder == null) {
579 final Module dependentModule = findModuleFromContext(context, builder, utQName.getPrefix(),
581 Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
582 TypeDefinition<?> type = findTypeByName(types, utQName.getLocalName());
583 final TypeDefinitionBuilder newType = extendedTypeWithNewBaseType(type, extType, builder, 0);
585 union.setTypedef(newType);
586 toRemove.add(extType);
588 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union.getPath(),
589 dependentModuleBuilder, utQName.getLocalName(), builder.getName(), union.getLine());
591 final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder,
592 extType, modules, builder, union.getLine());
594 union.setTypedef(newType);
595 toRemove.add(extType);
600 unionTypes.removeAll(toRemove);
604 * Go through all augment definitions and resolve them. It is expected that
605 * modules are already sorted by their dependencies. This method also finds
606 * augment target node and add child nodes to it.
609 * all available modules
611 private void resolveAugments(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
612 final List<ModuleBuilder> allModulesList = new ArrayList<ModuleBuilder>();
613 final Set<ModuleBuilder> allModulesSet = new HashSet<ModuleBuilder>();
614 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
615 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
616 allModulesList.add(inner.getValue());
617 allModulesSet.add(inner.getValue());
621 for (int i = 0; i < allModulesList.size(); i++) {
622 final ModuleBuilder module = allModulesList.get(i);
623 // try to resolve augments in module
624 resolveAugment(modules, module);
625 // while all augments are not resolved
626 final Iterator<ModuleBuilder> allModulesIterator = allModulesSet.iterator();
627 while (!(module.getAugmentsResolved() == module.getAugments().size())) {
628 ModuleBuilder nextModule = null;
629 // try resolve other module augments
631 nextModule = allModulesIterator.next();
632 resolveAugment(modules, nextModule);
633 } catch (NoSuchElementException e) {
634 throw new YangParseException("Failed to resolve augments in module '" + module.getName() + "'.", e);
636 // then try to resolve first module again
637 resolveAugment(modules, module);
643 * Tries to resolve augments in given module. If augment target node is not
647 * all available modules
651 private void resolveAugment(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
652 if (module.getAugmentsResolved() < module.getAugments().size()) {
653 for (AugmentationSchemaBuilder augmentBuilder : module.getAugments()) {
655 if (!augmentBuilder.isResolved()) {
656 final SchemaPath augmentTargetSchemaPath = augmentBuilder.getTargetPath();
657 final List<QName> path = augmentTargetSchemaPath.getPath();
659 final QName qname = path.get(0);
660 String prefix = qname.getPrefix();
661 if (prefix == null) {
662 prefix = module.getPrefix();
665 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, prefix,
666 augmentBuilder.getLine());
667 processAugmentation(augmentBuilder, path, module, qname, dependentModule);
675 * Go through all augment definitions and resolve them. This method works in
676 * same way as {@link #resolveAugments(Map)} except that if target node is not
677 * found in loaded modules, it search for target node in given context.
682 * SchemaContext containing already resolved modules
684 private void resolveAugmentsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
685 final SchemaContext context) {
686 final List<ModuleBuilder> allModulesList = new ArrayList<ModuleBuilder>();
687 final Set<ModuleBuilder> allModulesSet = new HashSet<ModuleBuilder>();
688 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
689 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
690 allModulesList.add(inner.getValue());
691 allModulesSet.add(inner.getValue());
695 for (int i = 0; i < allModulesList.size(); i++) {
696 final ModuleBuilder module = allModulesList.get(i);
697 // try to resolve augments in module
698 resolveAugmentWithContext(modules, module, context);
699 // while all augments are not resolved
700 final Iterator<ModuleBuilder> allModulesIterator = allModulesSet.iterator();
701 while (!(module.getAugmentsResolved() == module.getAugments().size())) {
702 ModuleBuilder nextModule = null;
703 // try resolve other module augments
705 nextModule = allModulesIterator.next();
706 resolveAugmentWithContext(modules, nextModule, context);
707 } catch (NoSuchElementException e) {
708 throw new YangParseException("Failed to resolve augments in module '" + module.getName() + "'.", e);
710 // then try to resolve first module again
711 resolveAugmentWithContext(modules, module, context);
717 * Tries to resolve augments in given module. If augment target node is not
721 * all available modules
725 private void resolveAugmentWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
726 final ModuleBuilder module, final SchemaContext context) {
727 if (module.getAugmentsResolved() < module.getAugments().size()) {
729 for (AugmentationSchemaBuilder augmentBuilder : module.getAugments()) {
730 final int line = augmentBuilder.getLine();
732 if (!augmentBuilder.isResolved()) {
733 final List<QName> path = augmentBuilder.getTargetPath().getPath();
734 final QName qname = path.get(0);
735 String prefix = qname.getPrefix();
736 if (prefix == null) {
737 prefix = module.getPrefix();
740 // try to find augment target module in loaded modules...
741 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix,
743 if (dependentModuleBuilder == null) {
744 // perform augmentation on module from context and
745 // continue to next augment
746 processAugmentationOnContext(augmentBuilder, path, module, prefix, line, context);
749 processAugmentation(augmentBuilder, path, module, qname, dependentModuleBuilder);
758 * Go through identity statements defined in current module and resolve
759 * their 'base' statement if present.
764 * module being resolved
766 private void resolveIdentities(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
767 final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
768 for (IdentitySchemaNodeBuilder identity : identities) {
769 final String baseIdentityName = identity.getBaseIdentityName();
770 if (baseIdentityName != null) {
771 String baseIdentityPrefix = null;
772 String baseIdentityLocalName = null;
773 if (baseIdentityName.contains(":")) {
774 final String[] splitted = baseIdentityName.split(":");
775 baseIdentityPrefix = splitted[0];
776 baseIdentityLocalName = splitted[1];
778 baseIdentityPrefix = module.getPrefix();
779 baseIdentityLocalName = baseIdentityName;
781 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, baseIdentityPrefix,
784 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule.getIdentities();
785 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
786 if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
787 identity.setBaseIdentity(idBuilder);
795 * Go through identity statements defined in current module and resolve
796 * their 'base' statement. Method tries to find base identity in given
797 * modules. If base identity is not found, method will search it in context.
804 * SchemaContext containing already resolved modules
806 private void resolveIdentitiesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
807 final ModuleBuilder module, SchemaContext context) {
808 final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
809 for (IdentitySchemaNodeBuilder identity : identities) {
810 final String baseIdentityName = identity.getBaseIdentityName();
811 if (baseIdentityName != null) {
812 String baseIdentityPrefix = null;
813 String baseIdentityLocalName = null;
814 if (baseIdentityName.contains(":")) {
815 final String[] splitted = baseIdentityName.split(":");
816 baseIdentityPrefix = splitted[0];
817 baseIdentityLocalName = splitted[1];
819 baseIdentityPrefix = module.getPrefix();
820 baseIdentityLocalName = baseIdentityName;
822 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
823 baseIdentityPrefix, identity.getLine());
825 if (dependentModuleBuilder == null) {
826 final Module dependentModule = findModuleFromContext(context, module, baseIdentityPrefix,
828 final Set<IdentitySchemaNode> dependentModuleIdentities = dependentModule.getIdentities();
829 for (IdentitySchemaNode idNode : dependentModuleIdentities) {
830 if (idNode.getQName().getLocalName().equals(baseIdentityLocalName)) {
831 identity.setBaseIdentity(idNode);
835 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModuleBuilder
837 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
838 if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
839 identity.setBaseIdentity(idBuilder);
848 * Go through uses statements defined in current module and resolve their
854 * module being resolved
856 private void resolveUsesRefine(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
857 final Map<List<String>, UsesNodeBuilder> moduleUses = module.getUsesNodes();
858 for (Map.Entry<List<String>, UsesNodeBuilder> entry : moduleUses.entrySet()) {
859 final UsesNodeBuilder usesNode = entry.getValue();
860 final int line = usesNode.getLine();
861 final GroupingBuilder targetGrouping = getTargetGroupingFromModules(usesNode, modules, module);
862 usesNode.setGroupingPath(targetGrouping.getPath());
863 for (RefineHolder refine : usesNode.getRefines()) {
864 final SchemaNodeBuilder nodeToRefine = RefineUtils.getRefineNodeFromGroupingBuilder(targetGrouping,
865 refine, module.getName());
866 RefineUtils.performRefine(nodeToRefine, refine, line);
867 usesNode.addRefineNode(nodeToRefine);
873 * Tries to search target grouping in given modules and resolve refine
874 * nodes. If grouping is not found in modules, method tries to find it in
875 * modules from context.
882 * SchemaContext containing already resolved modules
884 private void resolveUsesRefineWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
885 final ModuleBuilder module, SchemaContext context) {
886 final Map<List<String>, UsesNodeBuilder> moduleUses = module.getUsesNodes();
887 for (Map.Entry<List<String>, UsesNodeBuilder> entry : moduleUses.entrySet()) {
888 final UsesNodeBuilder usesNode = entry.getValue();
889 final int line = usesNode.getLine();
891 final GroupingBuilder targetGroupingBuilder = getTargetGroupingFromModules(usesNode, modules, module);
892 if (targetGroupingBuilder == null) {
893 final GroupingDefinition targetGrouping = getTargetGroupingFromContext(usesNode, module, context);
894 usesNode.setGroupingPath(targetGrouping.getPath());
895 for (RefineHolder refine : usesNode.getRefines()) {
896 final SchemaNodeBuilder nodeToRefine = RefineUtils.getRefineNodeFromGroupingDefinition(
897 targetGrouping, refine, module.getName());
898 RefineUtils.performRefine(nodeToRefine, refine, line);
899 usesNode.addRefineNode(nodeToRefine);
902 usesNode.setGroupingPath(targetGroupingBuilder.getPath());
903 for (RefineHolder refine : usesNode.getRefines()) {
904 final SchemaNodeBuilder nodeToRefine = RefineUtils.getRefineNodeFromGroupingBuilder(
905 targetGroupingBuilder, refine, module.getName());
906 RefineUtils.performRefine(nodeToRefine, refine, line);
907 usesNode.addRefineNode(nodeToRefine);
914 * Search given modules for grouping by name defined in uses node.
917 * builder of uses statement
922 * @return grouping with given name if found, null otherwise
924 private GroupingBuilder getTargetGroupingFromModules(final UsesNodeBuilder usesBuilder,
925 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
926 final int line = usesBuilder.getLine();
927 final String groupingString = usesBuilder.getGroupingName();
928 String groupingPrefix;
931 if (groupingString.contains(":")) {
932 String[] splitted = groupingString.split(":");
933 if (splitted.length != 2 || groupingString.contains("/")) {
934 throw new YangParseException(module.getName(), line, "Invalid name of target grouping");
936 groupingPrefix = splitted[0];
937 groupingName = splitted[1];
939 groupingPrefix = module.getPrefix();
940 groupingName = groupingString;
943 ModuleBuilder dependentModule = null;
944 if (groupingPrefix.equals(module.getPrefix())) {
945 dependentModule = module;
947 dependentModule = findDependentModuleBuilder(modules, module, groupingPrefix, line);
950 if (dependentModule == null) {
954 List<QName> path = usesBuilder.getPath().getPath();
955 GroupingBuilder result = null;
956 Set<GroupingBuilder> groupings = dependentModule.getModuleGroupings();
957 result = findGroupingBuilder(groupings, groupingName);
959 if (result == null) {
960 Builder currentNode = null;
961 final List<String> currentPath = new ArrayList<String>();
962 currentPath.add(dependentModule.getName());
964 for (int i = 0; i < path.size(); i++) {
965 QName qname = path.get(i);
966 currentPath.add(qname.getLocalName());
967 currentNode = dependentModule.getModuleNode(currentPath);
969 if (currentNode instanceof RpcDefinitionBuilder) {
970 groupings = ((RpcDefinitionBuilder) currentNode).getGroupings();
971 } else if (currentNode instanceof DataNodeContainerBuilder) {
972 groupings = ((DataNodeContainerBuilder) currentNode).getGroupings();
974 groupings = Collections.emptySet();
977 result = findGroupingBuilder(groupings, groupingName);
978 if (result != null) {
988 * Search context for grouping by name defined in uses node.
991 * builder of uses statement
995 * SchemaContext containing already resolved modules
996 * @return grouping with given name if found, null otherwise
998 private GroupingDefinition getTargetGroupingFromContext(final UsesNodeBuilder usesBuilder,
999 final ModuleBuilder module, SchemaContext context) {
1000 final int line = usesBuilder.getLine();
1001 String groupingString = usesBuilder.getGroupingName();
1002 String groupingPrefix;
1003 String groupingName;
1005 if (groupingString.contains(":")) {
1006 String[] splitted = groupingString.split(":");
1007 if (splitted.length != 2 || groupingString.contains("/")) {
1008 throw new YangParseException(module.getName(), line, "Invalid name of target grouping");
1010 groupingPrefix = splitted[0];
1011 groupingName = splitted[1];
1013 groupingPrefix = module.getPrefix();
1014 groupingName = groupingString;
1017 Module dependentModule = findModuleFromContext(context, module, groupingPrefix, line);
1018 return findGroupingDefinition(dependentModule.getGroupings(), groupingName);
1021 private QName findFullQName(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
1022 final IdentityrefTypeBuilder idref) {
1023 QName result = null;
1024 String baseString = idref.getBaseString();
1025 if (baseString.contains(":")) {
1026 String[] splittedBase = baseString.split(":");
1027 if (splittedBase.length > 2) {
1028 throw new YangParseException(module.getName(), idref.getLine(), "Failed to parse identityref base: "
1031 String prefix = splittedBase[0];
1032 String name = splittedBase[1];
1033 ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, prefix, idref.getLine());
1034 result = new QName(dependentModule.getNamespace(), dependentModule.getRevision(), prefix, name);
1036 result = new QName(module.getNamespace(), module.getRevision(), module.getPrefix(), baseString);
1041 private void resolveUnknownNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
1042 for (UnknownSchemaNodeBuilder usnb : module.getUnknownNodes()) {
1043 QName nodeType = usnb.getNodeType();
1044 if (nodeType.getNamespace() == null || nodeType.getRevision() == null) {
1046 ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, nodeType.getPrefix(),
1048 QName newNodeType = new QName(dependentModule.getNamespace(), dependentModule.getRevision(),
1049 nodeType.getPrefix(), nodeType.getLocalName());
1050 usnb.setNodeType(newNodeType);
1051 } catch (YangParseException e) {
1052 logger.debug(module.getName(), usnb.getLine(), "Failed to find unknown node type: " + nodeType);
1058 private void resolveUnknownNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1059 final ModuleBuilder module, SchemaContext context) {
1060 for (UnknownSchemaNodeBuilder unknownNodeBuilder : module.getUnknownNodes()) {
1061 QName nodeType = unknownNodeBuilder.getNodeType();
1062 if (nodeType.getNamespace() == null || nodeType.getRevision() == null) {
1064 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
1065 nodeType.getPrefix(), unknownNodeBuilder.getLine());
1067 QName newNodeType = null;
1068 if (dependentModuleBuilder == null) {
1069 Module dependentModule = findModuleFromContext(context, module, nodeType.getPrefix(),
1070 unknownNodeBuilder.getLine());
1071 newNodeType = new QName(dependentModule.getNamespace(), dependentModule.getRevision(),
1072 nodeType.getPrefix(), nodeType.getLocalName());
1074 newNodeType = new QName(dependentModuleBuilder.getNamespace(),
1075 dependentModuleBuilder.getRevision(), nodeType.getPrefix(), nodeType.getLocalName());
1078 unknownNodeBuilder.setNodeType(newNodeType);
1079 } catch (YangParseException e) {
1080 logger.debug(module.getName(), unknownNodeBuilder.getLine(), "Failed to find unknown node type: "