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.yangtools.yang.parser.impl;
10 import static org.opendaylight.yangtools.yang.parser.util.ParserUtils.*;
13 import java.io.FileInputStream;
14 import java.io.FileNotFoundException;
15 import java.io.IOException;
16 import java.io.InputStream;
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;
28 import java.util.Map.Entry;
29 import java.util.NoSuchElementException;
31 import java.util.TreeMap;
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.yangtools.antlrv4.code.gen.YangLexer;
38 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser;
39 import org.opendaylight.yangtools.yang.common.QName;
40 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
41 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
42 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
43 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
44 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
45 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
46 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
47 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
48 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
49 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
50 import org.opendaylight.yangtools.yang.model.api.Module;
51 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
52 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
53 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
54 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
55 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
56 import org.opendaylight.yangtools.yang.model.parser.api.YangModelParser;
57 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
58 import org.opendaylight.yangtools.yang.model.util.IdentityrefType;
59 import org.opendaylight.yangtools.yang.model.util.UnknownType;
60 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
61 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
62 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
63 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
64 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
65 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingMember;
66 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
67 import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder;
68 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
69 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
70 import org.opendaylight.yangtools.yang.parser.builder.impl.AnyXmlBuilder;
71 import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceBuilder;
72 import org.opendaylight.yangtools.yang.parser.builder.impl.ContainerSchemaNodeBuilder;
73 import org.opendaylight.yangtools.yang.parser.builder.impl.DeviationBuilder;
74 import org.opendaylight.yangtools.yang.parser.builder.impl.GroupingBuilderImpl;
75 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentitySchemaNodeBuilder;
76 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentityrefTypeBuilder;
77 import org.opendaylight.yangtools.yang.parser.builder.impl.LeafListSchemaNodeBuilder;
78 import org.opendaylight.yangtools.yang.parser.builder.impl.LeafSchemaNodeBuilder;
79 import org.opendaylight.yangtools.yang.parser.builder.impl.ListSchemaNodeBuilder;
80 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
81 import org.opendaylight.yangtools.yang.parser.builder.impl.RpcDefinitionBuilder;
82 import org.opendaylight.yangtools.yang.parser.builder.impl.TypeDefinitionBuilderImpl;
83 import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder;
84 import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
85 import org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort;
86 import org.opendaylight.yangtools.yang.parser.util.RefineHolder;
87 import org.opendaylight.yangtools.yang.parser.util.RefineUtils;
88 import org.opendaylight.yangtools.yang.parser.util.TypeConstraints;
89 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
90 import org.opendaylight.yangtools.yang.validator.YangModelBasicValidator;
91 import org.slf4j.Logger;
92 import org.slf4j.LoggerFactory;
94 import com.google.common.collect.Lists;
95 import com.google.common.collect.Maps;
96 import com.google.common.collect.Sets;
98 public final class YangParserImpl implements YangModelParser {
99 private static final Logger LOG = LoggerFactory.getLogger(YangParserImpl.class);
102 public Set<Module> parseYangModels(final List<File> yangFiles) {
103 return Sets.newLinkedHashSet(parseYangModelsMapped(yangFiles).values());
107 public Set<Module> parseYangModels(final List<File> yangFiles, final SchemaContext context) {
108 if (yangFiles != null) {
109 final Map<InputStream, File> inputStreams = Maps.newHashMap();
111 for (final File yangFile : yangFiles) {
113 inputStreams.put(new FileInputStream(yangFile), yangFile);
114 } catch (FileNotFoundException e) {
115 LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
119 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
121 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
122 Lists.newArrayList(inputStreams.keySet()), builderToStreamMap);
124 for (InputStream is : inputStreams.keySet()) {
127 } catch (IOException e) {
128 LOG.debug("Failed to close stream.");
132 return new LinkedHashSet<Module>(buildWithContext(modules, context).values());
134 return Collections.emptySet();
138 public Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams) {
139 return Sets.newHashSet(parseYangModelsFromStreamsMapped(yangModelStreams).values());
143 public Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams, SchemaContext context) {
144 if (yangModelStreams != null) {
145 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
146 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersWithContext(
147 yangModelStreams, builderToStreamMap, context);
148 return new LinkedHashSet<Module>(buildWithContext(modules, context).values());
150 return Collections.emptySet();
154 public Map<File, Module> parseYangModelsMapped(List<File> yangFiles) {
155 if (yangFiles != null) {
156 final Map<InputStream, File> inputStreams = Maps.newHashMap();
158 for (final File yangFile : yangFiles) {
160 inputStreams.put(new FileInputStream(yangFile), yangFile);
161 } catch (FileNotFoundException e) {
162 LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
166 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
167 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
168 Lists.newArrayList(inputStreams.keySet()), builderToStreamMap);
170 for (InputStream is : inputStreams.keySet()) {
173 } catch (IOException e) {
174 LOG.debug("Failed to close stream.");
178 Map<File, Module> retVal = Maps.newLinkedHashMap();
179 Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
181 for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap.entrySet()) {
182 retVal.put(inputStreams.get(builderToStreamMap.get(builderToModule.getKey())),
183 builderToModule.getValue());
188 return Collections.emptyMap();
192 public Map<InputStream, Module> parseYangModelsFromStreamsMapped(final List<InputStream> yangModelStreams) {
193 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
195 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangModelStreams,
197 Map<InputStream, Module> retVal = Maps.newLinkedHashMap();
198 Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
200 for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap.entrySet()) {
201 retVal.put(builderToStreamMap.get(builderToModule.getKey()), builderToModule.getValue());
207 public SchemaContext resolveSchemaContext(final Set<Module> modules) {
208 return new SchemaContextImpl(modules);
211 private ModuleBuilder[] parseModuleBuilders(List<InputStream> inputStreams,
212 Map<ModuleBuilder, InputStream> streamToBuilderMap) {
214 final ParseTreeWalker walker = new ParseTreeWalker();
215 final List<ParseTree> trees = parseStreams(inputStreams);
216 final ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
219 new YangModelBasicValidator(walker).validate(trees);
221 YangParserListenerImpl yangModelParser = null;
222 for (int i = 0; i < trees.size(); i++) {
223 yangModelParser = new YangParserListenerImpl();
224 walker.walk(yangModelParser, trees.get(i));
225 ModuleBuilder moduleBuilder = yangModelParser.getModuleBuilder();
227 // We expect the order of trees and streams has to be the same
228 streamToBuilderMap.put(moduleBuilder, inputStreams.get(i));
229 builders[i] = moduleBuilder;
234 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(final List<InputStream> yangFileStreams,
235 Map<ModuleBuilder, InputStream> streamToBuilderMap) {
236 return resolveModuleBuildersWithContext(yangFileStreams, streamToBuilderMap, null);
239 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuildersWithContext(
240 final List<InputStream> yangFileStreams, final Map<ModuleBuilder, InputStream> streamToBuilderMap,
241 final SchemaContext context) {
242 final ModuleBuilder[] builders = parseModuleBuilders(yangFileStreams, streamToBuilderMap);
244 // Linked Hash Map MUST be used because Linked Hash Map preserves ORDER
245 // of items stored in map.
246 final LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> modules = new LinkedHashMap<String, TreeMap<Date, ModuleBuilder>>();
248 // module dependency graph sorted
249 List<ModuleBuilder> sorted = null;
250 if (context == null) {
251 sorted = ModuleDependencySort.sort(builders);
253 sorted = ModuleDependencySort.sortWithContext(context, builders);
256 for (final ModuleBuilder builder : sorted) {
257 if (builder == null) {
260 final String builderName = builder.getName();
261 Date builderRevision = builder.getRevision();
262 if (builderRevision == null) {
263 builderRevision = new Date(0L);
265 TreeMap<Date, ModuleBuilder> builderByRevision = modules.get(builderName);
266 if (builderByRevision == null) {
267 builderByRevision = new TreeMap<Date, ModuleBuilder>();
269 builderByRevision.put(builderRevision, builder);
270 modules.put(builderName, builderByRevision);
275 private List<ParseTree> parseStreams(final List<InputStream> yangStreams) {
276 final List<ParseTree> trees = new ArrayList<ParseTree>();
277 for (InputStream yangStream : yangStreams) {
278 trees.add(parseStream(yangStream));
283 private ParseTree parseStream(final InputStream yangStream) {
284 ParseTree result = null;
286 final ANTLRInputStream input = new ANTLRInputStream(yangStream);
287 final YangLexer lexer = new YangLexer(input);
288 final CommonTokenStream tokens = new CommonTokenStream(lexer);
289 final YangParser parser = new YangParser(tokens);
290 parser.removeErrorListeners();
291 parser.addErrorListener(new YangErrorListener());
293 result = parser.yang();
294 } catch (IOException e) {
295 LOG.warn("Exception while reading yang file: " + yangStream, e);
300 private Map<ModuleBuilder, Module> build(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
301 // fix unresolved nodes
302 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
303 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
304 final ModuleBuilder moduleBuilder = childEntry.getValue();
305 fixUnresolvedNodes(modules, moduleBuilder);
308 resolveAugments(modules);
309 resolveDeviations(modules);
312 // LinkedHashMap MUST be used otherwise the values will not maintain
314 // http://docs.oracle.com/javase/6/docs/api/java/util/LinkedHashMap.html
315 final Map<ModuleBuilder, Module> result = new LinkedHashMap<ModuleBuilder, Module>();
316 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
317 final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
318 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
319 final ModuleBuilder moduleBuilder = childEntry.getValue();
320 final Module module = moduleBuilder.build();
321 modulesByRevision.put(childEntry.getKey(), module);
322 result.put(moduleBuilder, module);
328 private Map<ModuleBuilder, Module> buildWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
329 SchemaContext context) {
330 // fix unresolved nodes
331 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
332 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
333 final ModuleBuilder moduleBuilder = childEntry.getValue();
334 fixUnresolvedNodesWithContext(modules, moduleBuilder, context);
337 resolveAugmentsWithContext(modules, context);
338 resolveDeviationsWithContext(modules, context);
341 // LinkedHashMap MUST be used otherwise the values will not maintain
343 // http://docs.oracle.com/javase/6/docs/api/java/util/LinkedHashMap.html
344 final Map<ModuleBuilder, Module> result = new LinkedHashMap<ModuleBuilder, Module>();
345 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
346 final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
347 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
348 final ModuleBuilder moduleBuilder = childEntry.getValue();
349 final Module module = moduleBuilder.build();
350 modulesByRevision.put(childEntry.getKey(), module);
351 result.put(moduleBuilder, module);
357 private void fixUnresolvedNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder builder) {
358 resolveDirtyNodes(modules, builder);
359 resolveIdentities(modules, builder);
360 resolveUsesNodes(modules, builder);
361 resolveUnknownNodes(modules, builder);
364 private void fixUnresolvedNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
365 final ModuleBuilder builder, final SchemaContext context) {
366 resolveDirtyNodesWithContext(modules, builder, context);
367 resolveIdentitiesWithContext(modules, builder, context);
368 resolveUsesNodesWithContext(modules, builder, context);
369 resolveUnknownNodesWithContext(modules, builder, context);
373 * Search for dirty nodes (node which contains UnknownType) and resolve
377 * all available modules
381 private void resolveDirtyNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
382 final Set<TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
383 if (!dirtyNodes.isEmpty()) {
384 for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
385 if (nodeToResolve instanceof UnionTypeBuilder) {
386 // special handling for union types
387 resolveTypeUnion((UnionTypeBuilder) nodeToResolve, modules, module);
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 resolveType(nodeToResolve, modules, module);
399 private void resolveDirtyNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
400 final ModuleBuilder module, SchemaContext context) {
401 final Set<TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
402 if (!dirtyNodes.isEmpty()) {
403 for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
404 if (nodeToResolve instanceof UnionTypeBuilder) {
405 // special handling for union types
406 resolveTypeUnionWithContext((UnionTypeBuilder) nodeToResolve, modules, module, context);
407 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
408 // special handling for identityref types
409 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
410 nodeToResolve.setType(new IdentityrefType(findFullQName(modules, module, idref), idref.getPath()));
412 resolveTypeWithContext(nodeToResolve, modules, module, context);
419 * Resolve unknown type of node. It is assumed that type of node is either
420 * UnknownType or ExtendedType with UnknownType as base type.
422 * @param nodeToResolve
423 * node with type to resolve
429 private void resolveType(final TypeAwareBuilder nodeToResolve,
430 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
431 TypeDefinitionBuilder resolvedType = null;
432 final int line = nodeToResolve.getLine();
433 final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
434 final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
435 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, unknownTypeQName.getPrefix(),
438 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(nodeToResolve, dependentModule,
439 unknownTypeQName.getLocalName(), module.getName(), line);
441 if (nodeToResolveType instanceof ExtendedType) {
442 final ExtendedType extType = (ExtendedType) nodeToResolveType;
443 final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder, extType,
444 modules, module, nodeToResolve.getLine());
445 resolvedType = newType;
447 resolvedType = targetTypeBuilder;
450 // validate constraints
451 final TypeConstraints constraints = findConstraintsFromTypeBuilder(nodeToResolve,
452 new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module, null);
453 constraints.validateConstraints();
455 nodeToResolve.setTypedef(resolvedType);
459 * Resolve unknown type of node. It is assumed that type of node is either
460 * UnknownType or ExtendedType with UnknownType as base type.
462 * @param nodeToResolve
463 * node with type to resolve
469 * SchemaContext containing already resolved modules
471 private void resolveTypeWithContext(final TypeAwareBuilder nodeToResolve,
472 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
473 final SchemaContext context) {
474 TypeDefinitionBuilder resolvedType = null;
475 final int line = nodeToResolve.getLine();
476 final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
477 final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
478 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
479 unknownTypeQName.getPrefix(), line);
481 if (dependentModuleBuilder == null) {
482 final Module dependentModule = findModuleFromContext(context, module, unknownTypeQName.getPrefix(), line);
483 final Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
484 final TypeDefinition<?> type = findTypeByName(types, unknownTypeQName.getLocalName());
486 if (nodeToResolveType instanceof ExtendedType) {
487 final ExtendedType extType = (ExtendedType) nodeToResolveType;
488 final TypeDefinitionBuilder newType = extendedTypeWithNewBaseType(type, extType, module,
489 nodeToResolve.getLine());
491 nodeToResolve.setTypedef(newType);
493 if (nodeToResolve instanceof TypeDefinitionBuilder) {
494 TypeDefinitionBuilder tdb = (TypeDefinitionBuilder) nodeToResolve;
495 TypeConstraints tc = findConstraintsFromTypeBuilder(nodeToResolve,
496 new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module, context);
497 tdb.setLengths(tc.getLength());
498 tdb.setPatterns(tc.getPatterns());
499 tdb.setRanges(tc.getRange());
500 tdb.setFractionDigits(tc.getFractionDigits());
502 nodeToResolve.setType(type);
506 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(nodeToResolve,
507 dependentModuleBuilder, unknownTypeQName.getLocalName(), module.getName(), line);
509 if (nodeToResolveType instanceof ExtendedType) {
510 final ExtendedType extType = (ExtendedType) nodeToResolveType;
511 final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder, extType,
512 modules, module, nodeToResolve.getLine());
513 resolvedType = newType;
515 resolvedType = targetTypeBuilder;
518 // validate constraints
519 final TypeConstraints constraints = findConstraintsFromTypeBuilder(nodeToResolve, new TypeConstraints(
520 module.getName(), nodeToResolve.getLine()), modules, module, context);
521 constraints.validateConstraints();
523 nodeToResolve.setTypedef(resolvedType);
527 private void resolveTypeUnion(final UnionTypeBuilder union,
528 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder builder) {
530 final List<TypeDefinition<?>> unionTypes = union.getTypes();
531 final List<TypeDefinition<?>> toRemove = new ArrayList<TypeDefinition<?>>();
532 for (TypeDefinition<?> unionType : unionTypes) {
533 if (unionType instanceof UnknownType) {
534 final UnknownType ut = (UnknownType) unionType;
535 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, builder, ut.getQName()
536 .getPrefix(), union.getLine());
537 final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union, dependentModule, ut
538 .getQName().getLocalName(), builder.getName(), union.getLine());
539 union.setTypedef(resolvedType);
541 } else if (unionType instanceof ExtendedType) {
542 final ExtendedType extType = (ExtendedType) unionType;
543 final TypeDefinition<?> extTypeBase = extType.getBaseType();
544 if (extTypeBase instanceof UnknownType) {
545 final UnknownType ut = (UnknownType) extTypeBase;
546 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, builder, ut.getQName()
547 .getPrefix(), union.getLine());
548 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union, dependentModule,
549 ut.getQName().getLocalName(), builder.getName(), union.getLine());
551 final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder,
552 extType, modules, builder, union.getLine());
554 union.setTypedef(newType);
555 toRemove.add(extType);
559 unionTypes.removeAll(toRemove);
562 private void resolveTypeUnionWithContext(final UnionTypeBuilder union,
563 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder builder,
564 final SchemaContext context) {
566 final List<TypeDefinition<?>> unionTypes = union.getTypes();
567 final List<TypeDefinition<?>> toRemove = new ArrayList<TypeDefinition<?>>();
568 for (TypeDefinition<?> unionType : unionTypes) {
569 if (unionType instanceof UnknownType) {
570 final UnknownType ut = (UnknownType) unionType;
571 final QName utQName = ut.getQName();
572 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, builder,
573 utQName.getPrefix(), union.getLine());
575 if (dependentModuleBuilder == null) {
576 Module dependentModule = findModuleFromContext(context, builder, utQName.getPrefix(),
578 Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
579 TypeDefinition<?> type = findTypeByName(types, utQName.getLocalName());
583 final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union, dependentModuleBuilder,
584 utQName.getLocalName(), builder.getName(), union.getLine());
585 union.setTypedef(resolvedType);
589 } else if (unionType instanceof ExtendedType) {
590 final ExtendedType extType = (ExtendedType) unionType;
591 TypeDefinition<?> extTypeBase = extType.getBaseType();
592 if (extTypeBase instanceof UnknownType) {
593 final UnknownType ut = (UnknownType) extTypeBase;
594 final QName utQName = ut.getQName();
595 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, builder,
596 utQName.getPrefix(), union.getLine());
598 if (dependentModuleBuilder == null) {
599 final Module dependentModule = findModuleFromContext(context, builder, utQName.getPrefix(),
601 Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
602 TypeDefinition<?> type = findTypeByName(types, utQName.getLocalName());
603 final TypeDefinitionBuilder newType = extendedTypeWithNewBaseType(type, extType, builder, 0);
605 union.setTypedef(newType);
606 toRemove.add(extType);
608 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union,
609 dependentModuleBuilder, utQName.getLocalName(), builder.getName(), union.getLine());
611 final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder,
612 extType, modules, builder, union.getLine());
614 union.setTypedef(newType);
615 toRemove.add(extType);
620 unionTypes.removeAll(toRemove);
624 * Go through all augment definitions and resolve them. It is expected that
625 * modules are already sorted by their dependencies. This method also finds
626 * augment target node and add child nodes to it.
629 * all available modules
631 private void resolveAugments(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
632 final List<ModuleBuilder> allModulesList = new ArrayList<ModuleBuilder>();
633 final Set<ModuleBuilder> allModulesSet = new HashSet<ModuleBuilder>();
634 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
635 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
636 allModulesList.add(inner.getValue());
637 allModulesSet.add(inner.getValue());
641 for (int i = 0; i < allModulesList.size(); i++) {
642 final ModuleBuilder module = allModulesList.get(i);
643 // try to resolve augments in module
644 resolveAugment(modules, module);
645 // while all augments are not resolved
646 final Iterator<ModuleBuilder> allModulesIterator = allModulesSet.iterator();
647 while (!(module.getAugmentsResolved() == module.getAllAugments().size())) {
648 ModuleBuilder nextModule = null;
649 // try resolve other module augments
651 nextModule = allModulesIterator.next();
652 resolveAugment(modules, nextModule);
653 } catch (NoSuchElementException e) {
654 throw new YangParseException("Failed to resolve augments in module '" + module.getName() + "'.", e);
656 // then try to resolve first module again
657 resolveAugment(modules, module);
663 * Tries to resolve augments in given module. If augment target node is not
667 * all available modules
671 private void resolveAugment(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
672 if (module.getAugmentsResolved() < module.getAllAugments().size()) {
673 for (AugmentationSchemaBuilder augmentBuilder : module.getAllAugments()) {
675 if (!augmentBuilder.isResolved()) {
676 final SchemaPath augmentTargetSchemaPath = augmentBuilder.getTargetPath();
677 final List<QName> path = augmentTargetSchemaPath.getPath();
679 final QName qname = path.get(0);
680 String prefix = qname.getPrefix();
681 if (prefix == null) {
682 prefix = module.getPrefix();
685 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, prefix,
686 augmentBuilder.getLine());
687 processAugmentation(augmentBuilder, path, module, dependentModule);
695 * Go through all augment definitions and resolve them. This method works in
696 * same way as {@link #resolveAugments(Map)} except that if target node is
697 * not found in loaded modules, it search for target node in given context.
702 * SchemaContext containing already resolved modules
704 private void resolveAugmentsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
705 final SchemaContext context) {
706 final List<ModuleBuilder> allModulesList = new ArrayList<ModuleBuilder>();
707 final Set<ModuleBuilder> allModulesSet = new HashSet<ModuleBuilder>();
708 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
709 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
710 allModulesList.add(inner.getValue());
711 allModulesSet.add(inner.getValue());
715 for (int i = 0; i < allModulesList.size(); i++) {
716 final ModuleBuilder module = allModulesList.get(i);
717 // try to resolve augments in module
718 resolveAugmentWithContext(modules, module, context);
719 // while all augments are not resolved
720 final Iterator<ModuleBuilder> allModulesIterator = allModulesSet.iterator();
721 while (!(module.getAugmentsResolved() == module.getAllAugments().size())) {
722 ModuleBuilder nextModule = null;
723 // try resolve other module augments
725 nextModule = allModulesIterator.next();
726 resolveAugmentWithContext(modules, nextModule, context);
727 } catch (NoSuchElementException e) {
728 throw new YangParseException("Failed to resolve augments in module '" + module.getName() + "'.", e);
730 // then try to resolve first module again
731 resolveAugmentWithContext(modules, module, context);
737 * Tries to resolve augments in given module. If augment target node is not
741 * all available modules
745 private void resolveAugmentWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
746 final ModuleBuilder module, final SchemaContext context) {
747 if (module.getAugmentsResolved() < module.getAllAugments().size()) {
749 for (AugmentationSchemaBuilder augmentBuilder : module.getAllAugments()) {
750 final int line = augmentBuilder.getLine();
752 if (!augmentBuilder.isResolved()) {
753 final List<QName> path = augmentBuilder.getTargetPath().getPath();
754 final QName qname = path.get(0);
755 String prefix = qname.getPrefix();
756 if (prefix == null) {
757 prefix = module.getPrefix();
760 // try to find augment target module in loaded modules...
761 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix,
763 if (dependentModuleBuilder == null) {
764 // perform augmentation on module from context and
765 // continue to next augment
766 processAugmentationOnContext(augmentBuilder, path, module, prefix, line, context);
769 processAugmentation(augmentBuilder, path, module, dependentModuleBuilder);
778 * Go through identity statements defined in current module and resolve
779 * their 'base' statement if present.
784 * module being resolved
786 private void resolveIdentities(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
787 final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
788 for (IdentitySchemaNodeBuilder identity : identities) {
789 final String baseIdentityName = identity.getBaseIdentityName();
790 if (baseIdentityName != null) {
791 String baseIdentityPrefix = null;
792 String baseIdentityLocalName = null;
793 if (baseIdentityName.contains(":")) {
794 final String[] splitted = baseIdentityName.split(":");
795 baseIdentityPrefix = splitted[0];
796 baseIdentityLocalName = splitted[1];
798 baseIdentityPrefix = module.getPrefix();
799 baseIdentityLocalName = baseIdentityName;
801 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, baseIdentityPrefix,
804 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule.getIdentities();
805 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
806 if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
807 identity.setBaseIdentity(idBuilder);
815 * Go through identity statements defined in current module and resolve
816 * their 'base' statement. Method tries to find base identity in given
817 * modules. If base identity is not found, method will search it in context.
824 * SchemaContext containing already resolved modules
826 private void resolveIdentitiesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
827 final ModuleBuilder module, final SchemaContext context) {
828 final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
829 for (IdentitySchemaNodeBuilder identity : identities) {
830 final String baseIdentityName = identity.getBaseIdentityName();
831 if (baseIdentityName != null) {
832 String baseIdentityPrefix = null;
833 String baseIdentityLocalName = null;
834 if (baseIdentityName.contains(":")) {
835 final String[] splitted = baseIdentityName.split(":");
836 baseIdentityPrefix = splitted[0];
837 baseIdentityLocalName = splitted[1];
839 baseIdentityPrefix = module.getPrefix();
840 baseIdentityLocalName = baseIdentityName;
842 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
843 baseIdentityPrefix, identity.getLine());
845 if (dependentModuleBuilder == null) {
846 final Module dependentModule = findModuleFromContext(context, module, baseIdentityPrefix,
848 final Set<IdentitySchemaNode> dependentModuleIdentities = dependentModule.getIdentities();
849 for (IdentitySchemaNode idNode : dependentModuleIdentities) {
850 if (idNode.getQName().getLocalName().equals(baseIdentityLocalName)) {
851 identity.setBaseIdentity(idNode);
855 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModuleBuilder
857 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
858 if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
859 identity.setBaseIdentity(idBuilder);
868 * Go through uses statements defined in current module and resolve their
874 * module being resolved
876 private void resolveUsesNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
877 final List<UsesNodeBuilder> allModuleUses = module.getAllUsesNodes();
878 for (UsesNodeBuilder usesNode : allModuleUses) {
880 final int line = usesNode.getLine();
881 final GroupingBuilder targetGrouping = getTargetGroupingFromModules(usesNode, modules, module);
882 usesNode.setGroupingPath(targetGrouping.getPath());
883 processUsesNode(module, usesNode, targetGrouping);
885 for (RefineHolder refine : usesNode.getRefines()) {
886 DataSchemaNodeBuilder nodeToRefine = null;
887 for (DataSchemaNodeBuilder dsnb : usesNode.getTargetChildren()) {
888 if (refine.getName().equals(dsnb.getQName().getLocalName())) {
893 if (nodeToRefine == null) {
894 throw new YangParseException(refine.getModuleName(), refine.getLine(), "Refine target node '"
895 + refine.getName() + "' not found");
897 if (nodeToRefine instanceof GroupingMember) {
898 ((GroupingMember) nodeToRefine).setAddedByUses(true);
900 RefineUtils.performRefine(nodeToRefine, refine, line);
901 usesNode.addRefineNode(nodeToRefine);
904 for (UsesNodeBuilder usesNode : allModuleUses) {
905 final GroupingBuilder targetGrouping = getTargetGroupingFromModules(usesNode, modules, module);
906 processUsesTarget(module, usesNode, targetGrouping);
911 * Tries to search target grouping in given modules and resolve refine
912 * nodes. If grouping is not found in modules, method tries to find it in
913 * modules from context.
920 * SchemaContext containing already resolved modules
922 private void resolveUsesNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
923 final ModuleBuilder module, final SchemaContext context) {
924 final List<UsesNodeBuilder> moduleUses = module.getAllUsesNodes();
925 for (UsesNodeBuilder usesNode : moduleUses) {
926 final int line = usesNode.getLine();
928 final GroupingBuilder targetGroupingBuilder = getTargetGroupingFromModules(usesNode, modules, module);
929 if (targetGroupingBuilder == null) {
930 final GroupingDefinition targetGrouping = getTargetGroupingFromContext(usesNode, module, context);
931 usesNode.setGroupingPath(targetGrouping.getPath());
932 processUsesNode(usesNode, targetGrouping);
933 for (RefineHolder refine : usesNode.getRefines()) {
934 DataSchemaNodeBuilder nodeToRefine = null;
935 for (DataSchemaNodeBuilder dsnb : usesNode.getTargetChildren()) {
936 if (refine.getName().equals(dsnb.getQName().getLocalName())) {
941 if (nodeToRefine == null) {
942 throw new YangParseException(refine.getModuleName(), refine.getLine(), "Refine target node '"
943 + refine.getName() + "' not found");
945 if (nodeToRefine instanceof GroupingMember) {
946 ((GroupingMember) nodeToRefine).setAddedByUses(true);
948 RefineUtils.performRefine(nodeToRefine, refine, line);
949 usesNode.addRefineNode(nodeToRefine);
952 usesNode.setGroupingPath(targetGroupingBuilder.getPath());
953 processUsesNode(module, usesNode, targetGroupingBuilder);
954 for (RefineHolder refine : usesNode.getRefines()) {
955 DataSchemaNodeBuilder nodeToRefine = null;
956 for (DataSchemaNodeBuilder dsnb : usesNode.getTargetChildren()) {
957 if (refine.getName().equals(dsnb.getQName().getLocalName())) {
962 if (nodeToRefine == null) {
963 throw new YangParseException(refine.getModuleName(), refine.getLine(), "Refine target node '"
964 + refine.getName() + "' not found");
966 if (nodeToRefine instanceof GroupingMember) {
967 ((GroupingMember) nodeToRefine).setAddedByUses(true);
969 RefineUtils.performRefine(nodeToRefine, refine, line);
970 usesNode.addRefineNode(nodeToRefine);
977 * Search given modules for grouping by name defined in uses node.
980 * builder of uses statement
985 * @return grouping with given name if found, null otherwise
987 private GroupingBuilder getTargetGroupingFromModules(final UsesNodeBuilder usesBuilder,
988 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
989 final int line = usesBuilder.getLine();
990 final String groupingString = usesBuilder.getGroupingName();
991 String groupingPrefix;
994 if (groupingString.contains(":")) {
995 String[] splitted = groupingString.split(":");
996 if (splitted.length != 2 || groupingString.contains("/")) {
997 throw new YangParseException(module.getName(), line, "Invalid name of target grouping");
999 groupingPrefix = splitted[0];
1000 groupingName = splitted[1];
1002 groupingPrefix = module.getPrefix();
1003 groupingName = groupingString;
1006 ModuleBuilder dependentModule = null;
1007 if (groupingPrefix.equals(module.getPrefix())) {
1008 dependentModule = module;
1010 dependentModule = findDependentModuleBuilder(modules, module, groupingPrefix, line);
1013 if (dependentModule == null) {
1017 GroupingBuilder result = null;
1018 Set<GroupingBuilder> groupings = dependentModule.getGroupingBuilders();
1019 result = findGroupingBuilder(groupings, groupingName);
1020 if (result != null) {
1024 Builder parent = usesBuilder.getParent();
1026 while (parent != null) {
1027 if (parent instanceof DataNodeContainerBuilder) {
1028 groupings = ((DataNodeContainerBuilder) parent).getGroupingBuilders();
1029 } else if (parent instanceof RpcDefinitionBuilder) {
1030 groupings = ((RpcDefinitionBuilder) parent).getGroupings();
1032 result = findGroupingBuilder(groupings, groupingName);
1033 if (result == null) {
1034 parent = parent.getParent();
1040 if (result == null) {
1041 throw new YangParseException(module.getName(), line, "Referenced grouping '" + groupingName
1048 * Search context for grouping by name defined in uses node.
1050 * @param usesBuilder
1051 * builder of uses statement
1055 * SchemaContext containing already resolved modules
1056 * @return grouping with given name if found, null otherwise
1058 private GroupingDefinition getTargetGroupingFromContext(final UsesNodeBuilder usesBuilder,
1059 final ModuleBuilder module, final SchemaContext context) {
1060 final int line = usesBuilder.getLine();
1061 String groupingString = usesBuilder.getGroupingName();
1062 String groupingPrefix;
1063 String groupingName;
1065 if (groupingString.contains(":")) {
1066 String[] splitted = groupingString.split(":");
1067 if (splitted.length != 2 || groupingString.contains("/")) {
1068 throw new YangParseException(module.getName(), line, "Invalid name of target grouping");
1070 groupingPrefix = splitted[0];
1071 groupingName = splitted[1];
1073 groupingPrefix = module.getPrefix();
1074 groupingName = groupingString;
1077 Module dependentModule = findModuleFromContext(context, module, groupingPrefix, line);
1078 return findGroupingDefinition(dependentModule.getGroupings(), groupingName);
1082 * Add nodes defined in target grouping to current context.
1087 * @param targetGrouping
1089 private void processUsesNode(final ModuleBuilder module, final UsesNodeBuilder usesNode,
1090 final GroupingBuilder targetGrouping) {
1091 DataNodeContainerBuilder parent = usesNode.getParent();
1092 URI namespace = null;
1093 Date revision = null;
1094 String prefix = null;
1095 if (parent instanceof ModuleBuilder || parent instanceof AugmentationSchemaBuilder) {
1096 namespace = module.getNamespace();
1097 revision = module.getRevision();
1098 prefix = module.getPrefix();
1100 QName parentQName = parent.getQName();
1101 namespace = parentQName.getNamespace();
1102 revision = parentQName.getRevision();
1103 prefix = parentQName.getPrefix();
1105 SchemaPath parentPath = parent.getPath();
1107 Set<DataSchemaNodeBuilder> newChildren = new HashSet<>();
1108 for (DataSchemaNodeBuilder child : targetGrouping.getChildNodeBuilders()) {
1109 if (child != null) {
1110 DataSchemaNodeBuilder newChild = null;
1111 if (child instanceof AnyXmlBuilder) {
1112 newChild = new AnyXmlBuilder((AnyXmlBuilder) child);
1113 } else if (child instanceof ChoiceBuilder) {
1114 newChild = new ChoiceBuilder((ChoiceBuilder) child);
1115 } else if (child instanceof ContainerSchemaNodeBuilder) {
1116 newChild = new ContainerSchemaNodeBuilder((ContainerSchemaNodeBuilder) child);
1117 } else if (child instanceof LeafListSchemaNodeBuilder) {
1118 newChild = new LeafListSchemaNodeBuilder((LeafListSchemaNodeBuilder) child);
1119 } else if (child instanceof LeafSchemaNodeBuilder) {
1120 newChild = new LeafSchemaNodeBuilder((LeafSchemaNodeBuilder) child);
1121 } else if (child instanceof ListSchemaNodeBuilder) {
1122 newChild = new ListSchemaNodeBuilder((ListSchemaNodeBuilder) child);
1125 if (newChild == null) {
1126 throw new YangParseException(usesNode.getModuleName(), usesNode.getLine(),
1127 "Unknown member of target grouping while resolving uses node.");
1130 if (newChild instanceof GroupingMember) {
1131 ((GroupingMember) newChild).setAddedByUses(true);
1134 newChild.setPath(createSchemaPath(parentPath, newChild.getQName().getLocalName(), namespace, revision,
1136 newChildren.add(newChild);
1139 usesNode.getTargetChildren().addAll(newChildren);
1141 Set<GroupingBuilder> newGroupings = new HashSet<>();
1142 for (GroupingBuilder g : targetGrouping.getGroupingBuilders()) {
1143 GroupingBuilder newGrouping = new GroupingBuilderImpl(g);
1144 newGrouping.setAddedByUses(true);
1145 newGrouping.setPath(createSchemaPath(parentPath, newGrouping.getQName().getLocalName(), namespace,
1147 newGroupings.add(newGrouping);
1149 usesNode.getTargetGroupings().addAll(newGroupings);
1151 Set<TypeDefinitionBuilder> newTypedefs = new HashSet<>();
1152 for (TypeDefinitionBuilder td : targetGrouping.getTypeDefinitionBuilders()) {
1153 TypeDefinitionBuilder newType = new TypeDefinitionBuilderImpl(td);
1154 newType.setAddedByUses(true);
1155 newType.setPath(createSchemaPath(parentPath, newType.getQName().getLocalName(), namespace, revision, prefix));
1156 newTypedefs.add(newType);
1158 usesNode.getTargetTypedefs().addAll(newTypedefs);
1160 List<UnknownSchemaNodeBuilder> newUnknownNodes = new ArrayList<>();
1161 for (UnknownSchemaNodeBuilder un : targetGrouping.getUnknownNodeBuilders()) {
1162 UnknownSchemaNodeBuilder newUn = new UnknownSchemaNodeBuilder(un);
1163 newUn.setAddedByUses(true);
1164 newUn.setPath(createSchemaPath(parentPath, un.getQName().getLocalName(), namespace, revision, prefix));
1165 newUnknownNodes.add(newUn);
1167 usesNode.getTargetUnknownNodes().addAll(newUnknownNodes);
1171 * Check if target grouping contains uses nodes and if it does, merge
1172 * current uses with them.
1176 * @param targetGrouping
1178 private void processUsesTarget(final ModuleBuilder module, final UsesNodeBuilder usesNode,
1179 final GroupingBuilder targetGrouping) {
1180 for (UsesNodeBuilder unb : targetGrouping.getUses()) {
1181 usesNode.getTargetChildren().addAll(unb.getTargetChildren());
1182 usesNode.getTargetGroupings().addAll(unb.getTargetGroupings());
1183 usesNode.getTargetTypedefs().addAll(unb.getTargetTypedefs());
1184 usesNode.getTargetUnknownNodes().addAll(unb.getTargetUnknownNodes());
1188 private void processUsesNode(final UsesNodeBuilder usesNode, final GroupingDefinition targetGrouping) {
1189 final String moduleName = usesNode.getModuleName();
1190 final int line = usesNode.getLine();
1191 DataNodeContainerBuilder parent = usesNode.getParent();
1192 URI namespace = null;
1193 Date revision = null;
1194 String prefix = null;
1195 if (parent instanceof ModuleBuilder) {
1196 ModuleBuilder module = (ModuleBuilder) parent;
1197 namespace = module.getNamespace();
1198 revision = module.getRevision();
1199 prefix = module.getPrefix();
1201 QName parentQName = parent.getQName();
1202 namespace = parentQName.getNamespace();
1203 revision = parentQName.getRevision();
1204 prefix = parentQName.getPrefix();
1206 SchemaPath parentPath = parent.getPath();
1208 final Set<DataSchemaNodeBuilder> newChildren = new HashSet<>();
1209 for (DataSchemaNode child : targetGrouping.getChildNodes()) {
1210 if (child != null) {
1211 DataSchemaNodeBuilder newChild = null;
1212 if (child instanceof AnyXmlSchemaNode) {
1213 newChild = createAnyXml((AnyXmlSchemaNode) child, moduleName, line);
1214 } else if (child instanceof ChoiceNode) {
1215 newChild = createChoice((ChoiceNode) child, moduleName, line);
1216 } else if (child instanceof ContainerSchemaNode) {
1217 newChild = createContainer((ContainerSchemaNode) child, moduleName, line);
1218 } else if (child instanceof LeafListSchemaNode) {
1219 newChild = createLeafList((LeafListSchemaNode) child, moduleName, line);
1220 } else if (child instanceof LeafSchemaNode) {
1221 newChild = createLeafBuilder((LeafSchemaNode) child, moduleName, line);
1222 } else if (child instanceof ListSchemaNode) {
1223 newChild = createList((ListSchemaNode) child, moduleName, line);
1226 if (newChild == null) {
1227 throw new YangParseException(moduleName, line,
1228 "Unknown member of target grouping while resolving uses node.");
1231 if (newChild instanceof GroupingMember) {
1232 ((GroupingMember) newChild).setAddedByUses(true);
1234 newChild.setPath(createSchemaPath(parentPath, newChild.getQName().getLocalName(), namespace, revision,
1236 newChildren.add(newChild);
1239 usesNode.getTargetChildren().addAll(newChildren);
1241 final Set<GroupingBuilder> newGroupings = new HashSet<>();
1242 for (GroupingDefinition g : targetGrouping.getGroupings()) {
1243 GroupingBuilder newGrouping = createGrouping(g, moduleName, line);
1244 newGrouping.setAddedByUses(true);
1245 newGrouping.setPath(createSchemaPath(parentPath, newGrouping.getQName().getLocalName(), namespace,
1247 newGroupings.add(newGrouping);
1249 usesNode.getTargetGroupings().addAll(newGroupings);
1251 final Set<TypeDefinitionBuilder> newTypedefs = new HashSet<>();
1252 for (TypeDefinition<?> td : targetGrouping.getTypeDefinitions()) {
1253 TypeDefinitionBuilder newType = createTypedef((ExtendedType) td, moduleName, line);
1254 newType.setAddedByUses(true);
1255 newType.setPath(createSchemaPath(parentPath, newType.getQName().getLocalName(), namespace, revision, prefix));
1256 newTypedefs.add(newType);
1258 usesNode.getTargetTypedefs().addAll(newTypedefs);
1260 final List<UnknownSchemaNodeBuilder> newUnknownNodes = new ArrayList<>();
1261 for (UnknownSchemaNode un : targetGrouping.getUnknownSchemaNodes()) {
1262 UnknownSchemaNodeBuilder newNode = createUnknownSchemaNode(un, moduleName, line);
1263 newNode.setAddedByUses(true);
1264 newNode.setPath(createSchemaPath(parentPath, un.getQName().getLocalName(), namespace, revision, prefix));
1265 newUnknownNodes.add(newNode);
1267 usesNode.getTargetUnknownNodes().addAll(newUnknownNodes);
1270 private QName findFullQName(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
1271 final IdentityrefTypeBuilder idref) {
1272 QName result = null;
1273 String baseString = idref.getBaseString();
1274 if (baseString.contains(":")) {
1275 String[] splittedBase = baseString.split(":");
1276 if (splittedBase.length > 2) {
1277 throw new YangParseException(module.getName(), idref.getLine(), "Failed to parse identityref base: "
1280 String prefix = splittedBase[0];
1281 String name = splittedBase[1];
1282 ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, prefix, idref.getLine());
1283 result = new QName(dependentModule.getNamespace(), dependentModule.getRevision(), prefix, name);
1285 result = new QName(module.getNamespace(), module.getRevision(), module.getPrefix(), baseString);
1290 private void resolveUnknownNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
1291 for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) {
1292 QName nodeType = usnb.getNodeType();
1293 if (nodeType.getNamespace() == null || nodeType.getRevision() == null) {
1295 ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, nodeType.getPrefix(),
1297 QName newNodeType = new QName(dependentModule.getNamespace(), dependentModule.getRevision(),
1298 nodeType.getPrefix(), nodeType.getLocalName());
1299 usnb.setNodeType(newNodeType);
1300 } catch (YangParseException e) {
1301 LOG.debug(module.getName(), usnb.getLine(), "Failed to find unknown node type: " + nodeType);
1307 private void resolveUnknownNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1308 final ModuleBuilder module, final SchemaContext context) {
1309 for (UnknownSchemaNodeBuilder unknownNodeBuilder : module.getAllUnknownNodes()) {
1310 QName nodeType = unknownNodeBuilder.getNodeType();
1311 if (nodeType.getNamespace() == null || nodeType.getRevision() == null) {
1313 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
1314 nodeType.getPrefix(), unknownNodeBuilder.getLine());
1316 QName newNodeType = null;
1317 if (dependentModuleBuilder == null) {
1318 Module dependentModule = findModuleFromContext(context, module, nodeType.getPrefix(),
1319 unknownNodeBuilder.getLine());
1320 newNodeType = new QName(dependentModule.getNamespace(), dependentModule.getRevision(),
1321 nodeType.getPrefix(), nodeType.getLocalName());
1323 newNodeType = new QName(dependentModuleBuilder.getNamespace(),
1324 dependentModuleBuilder.getRevision(), nodeType.getPrefix(), nodeType.getLocalName());
1327 unknownNodeBuilder.setNodeType(newNodeType);
1328 } catch (YangParseException e) {
1329 LOG.debug(module.getName(), unknownNodeBuilder.getLine(), "Failed to find unknown node type: "
1336 private void resolveDeviations(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
1337 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
1338 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
1339 ModuleBuilder b = inner.getValue();
1340 resolveDeviation(modules, b);
1345 private void resolveDeviation(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
1346 for (DeviationBuilder dev : module.getDeviations()) {
1347 int line = dev.getLine();
1348 SchemaPath targetPath = dev.getTargetPath();
1349 List<QName> path = targetPath.getPath();
1350 QName q0 = path.get(0);
1351 String prefix = q0.getPrefix();
1352 if (prefix == null) {
1353 prefix = module.getPrefix();
1356 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, line);
1357 processDeviation(dev, dependentModuleBuilder, path, module);
1361 private void resolveDeviationsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1362 final SchemaContext context) {
1363 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
1364 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
1365 ModuleBuilder b = inner.getValue();
1366 resolveDeviationWithContext(modules, b, context);
1371 private void resolveDeviationWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1372 final ModuleBuilder module, final SchemaContext context) {
1373 for (DeviationBuilder dev : module.getDeviations()) {
1374 int line = dev.getLine();
1375 SchemaPath targetPath = dev.getTargetPath();
1376 List<QName> path = targetPath.getPath();
1377 QName q0 = path.get(0);
1378 String prefix = q0.getPrefix();
1379 if (prefix == null) {
1380 prefix = module.getPrefix();
1384 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, line);
1385 if (dependentModuleBuilder == null) {
1386 Module dependentModule = findModuleFromContext(context, module, prefix, line);
1387 Object currentParent = dependentModule;
1389 for (int i = 0; i < path.size(); i++) {
1390 if (currentParent == null) {
1391 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
1393 QName q = path.get(i);
1394 name = q.getLocalName();
1395 if (currentParent instanceof DataNodeContainer) {
1396 currentParent = ((DataNodeContainer) currentParent).getDataChildByName(name);
1400 if (currentParent == null) {
1401 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
1403 if (currentParent instanceof SchemaNode) {
1404 dev.setTargetPath(((SchemaNode) currentParent).getPath());
1408 processDeviation(dev, dependentModuleBuilder, path, module);
1414 * Correct deviation target path in deviation builder.
1418 * @param dependentModuleBuilder
1419 * module containing deviation target
1421 * current deviation target path
1425 private void processDeviation(final DeviationBuilder dev, final ModuleBuilder dependentModuleBuilder,
1426 final List<QName> path, final ModuleBuilder module) {
1427 final int line = dev.getLine();
1428 Builder currentParent = dependentModuleBuilder;
1430 for (int i = 0; i < path.size(); i++) {
1431 if (currentParent == null) {
1432 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
1434 QName q = path.get(i);
1435 String name = q.getLocalName();
1436 if (currentParent instanceof DataNodeContainerBuilder) {
1437 currentParent = ((DataNodeContainerBuilder) currentParent).getDataChildByName(name);
1441 if (currentParent == null || !(currentParent instanceof SchemaNodeBuilder)) {
1442 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
1444 dev.setTargetPath(((SchemaNodeBuilder) currentParent).getPath());