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.builder.impl;
10 import com.google.common.base.Function;
11 import com.google.common.base.Optional;
12 import com.google.common.base.Preconditions;
13 import com.google.common.base.Splitter;
14 import com.google.common.collect.Collections2;
15 import com.google.common.collect.Iterables;
16 import com.google.common.io.ByteSource;
17 import java.io.ByteArrayOutputStream;
19 import java.io.FileNotFoundException;
20 import java.io.IOException;
21 import java.io.InputStream;
23 import java.text.DateFormat;
24 import java.text.SimpleDateFormat;
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.Date;
28 import java.util.HashMap;
29 import java.util.HashSet;
30 import java.util.Iterator;
31 import java.util.LinkedHashSet;
32 import java.util.List;
35 import java.util.TreeMap;
36 import org.antlr.v4.runtime.tree.ParseTree;
37 import org.apache.commons.io.IOUtils;
38 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Module_header_stmtsContext;
39 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Module_stmtContext;
40 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Namespace_stmtContext;
41 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_stmtsContext;
42 import org.opendaylight.yangtools.yang.common.QName;
43 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
44 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
45 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
46 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
47 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
48 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
49 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
50 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
51 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
52 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
53 import org.opendaylight.yangtools.yang.model.api.Module;
54 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
55 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
56 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
57 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
58 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
59 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
60 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
61 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationTargetBuilder;
62 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
63 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
64 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
65 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
66 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingMember;
67 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
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.impl.ParserListenerUtils;
71 import org.opendaylight.yangtools.yang.parser.impl.util.YangModelDependencyInfo;
72 import org.opendaylight.yangtools.yang.parser.util.NamedByteArrayInputStream;
73 import org.opendaylight.yangtools.yang.parser.util.NamedFileInputStream;
74 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
75 import org.slf4j.Logger;
76 import org.slf4j.LoggerFactory;
78 public final class BuilderUtils {
80 private static final DateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
81 private static final Logger LOG = LoggerFactory.getLogger(BuilderUtils.class);
82 private static final Splitter SLASH_SPLITTER = Splitter.on('/').omitEmptyStrings();
83 private static final Splitter COLON_SPLITTER = Splitter.on(':');
84 private static final Date NULL_DATE = new Date(0L);
85 private static final String INPUT = "input";
86 private static final String OUTPUT = "output";
88 private BuilderUtils() {
91 public static Collection<ByteSource> streamsToByteSources(final Collection<InputStream> streams) throws IOException {
92 Collection<ByteSource> result = new HashSet<>();
93 for (InputStream stream : streams) {
94 result.add(new ByteSourceImpl(stream));
99 public static ByteSource fileToByteSource(final File file) {
100 return new ByteSource() {
102 public InputStream openStream() throws IOException {
103 return new NamedFileInputStream(file, file.getAbsolutePath());
108 public static Collection<ByteSource> filesToByteSources(final Collection<File> streams)
109 throws FileNotFoundException {
110 return Collections2.transform(streams, new Function<File, ByteSource>() {
112 public ByteSource apply(final File input) {
113 return new ByteSource() {
115 public InputStream openStream() throws IOException {
116 return new NamedFileInputStream(input, input.getAbsolutePath());
124 * Create new SchemaPath from given path and qname.
129 * one or more qnames added to base path
130 * @return new SchemaPath from given path and qname
132 * @deprecated Use {@link SchemaPath#createChild(QName...)} instead.
135 public static SchemaPath createSchemaPath(final SchemaPath schemaPath, final QName... qname) {
136 return schemaPath.createChild(qname);
140 * Find dependent module based on given prefix
143 * all available modules
147 * target module prefix
149 * current line in yang model
150 * @return module builder if found, null otherwise
152 public static ModuleBuilder findModuleFromBuilders(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
153 final ModuleBuilder module, final String prefix, final int line) {
154 ModuleBuilder dependentModule;
155 Date dependentModuleRevision;
157 if (prefix == null) {
158 dependentModule = module;
159 } else if (prefix.equals(module.getPrefix())) {
160 dependentModule = module;
162 ModuleImport dependentModuleImport = module.getImport(prefix);
163 if (dependentModuleImport == null) {
164 throw new YangParseException(module.getName(), line, "No import found with prefix '" + prefix + "'.");
166 String dependentModuleName = dependentModuleImport.getModuleName();
167 dependentModuleRevision = dependentModuleImport.getRevision();
169 TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules.get(dependentModuleName);
170 if (moduleBuildersByRevision == null) {
173 if (dependentModuleRevision == null) {
174 dependentModule = moduleBuildersByRevision.lastEntry().getValue();
176 dependentModule = moduleBuildersByRevision.get(dependentModuleRevision);
179 return dependentModule;
182 public static ModuleBuilder findModuleFromBuilders(ModuleImport imp, Iterable<ModuleBuilder> modules) {
183 String name = imp.getModuleName();
184 Date revision = imp.getRevision();
185 TreeMap<Date, ModuleBuilder> map = new TreeMap<>();
186 for (ModuleBuilder module : modules) {
187 if (module != null) {
188 if (module.getName().equals(name)) {
189 map.put(module.getRevision(), module);
196 if (revision == null) {
197 return map.lastEntry().getValue();
199 return map.get(revision);
203 * Find module from context based on prefix.
207 * @param currentModule
210 * prefix used to reference dependent module
212 * current line in yang model
213 * @return module based on import with given prefix if found in context,
215 * @throws YangParseException
216 * if no import found with given prefix
218 public static Module findModuleFromContext(final SchemaContext context, final ModuleBuilder currentModule,
219 final String prefix, final int line) {
220 TreeMap<Date, Module> modulesByRevision = new TreeMap<>();
222 ModuleImport dependentModuleImport = currentModule.getImport(prefix);
223 if (dependentModuleImport == null) {
224 throw new YangParseException(currentModule.getName(), line, "No import found with prefix '" + prefix + "'.");
226 String dependentModuleName = dependentModuleImport.getModuleName();
227 Date dependentModuleRevision = dependentModuleImport.getRevision();
229 for (Module contextModule : context.getModules()) {
230 if (contextModule.getName().equals(dependentModuleName)) {
231 Date revision = contextModule.getRevision();
232 if (revision == null) {
233 revision = NULL_DATE;
235 modulesByRevision.put(revision, contextModule);
240 if (dependentModuleRevision == null) {
241 result = modulesByRevision.get(modulesByRevision.firstKey());
243 result = modulesByRevision.get(dependentModuleRevision);
245 if (result == null) {
246 throw new YangParseException(currentModule.getName(), line, "Module not found for prefix " + prefix);
253 * Add all augment's child nodes to given target.
256 * builder of augment statement
258 * augmentation target node
260 public static void fillAugmentTarget(final AugmentationSchemaBuilder augment, final Builder target) {
261 if (target instanceof DataNodeContainerBuilder) {
262 fillAugmentTarget(augment, (DataNodeContainerBuilder) target);
263 } else if (target instanceof ChoiceBuilder) {
264 fillAugmentTarget(augment, (ChoiceBuilder) target);
266 throw new YangParseException(
267 augment.getModuleName(),
269 "Error in augment parsing: The target node MUST be either a container, list, choice, case, input, output, or notification node.");
274 * Add all augment's child nodes to given target.
277 * builder of augment statement
279 * augmentation target node
281 private static void fillAugmentTarget(final AugmentationSchemaBuilder augment, final DataNodeContainerBuilder target) {
282 for (DataSchemaNodeBuilder child : augment.getChildNodeBuilders()) {
283 DataSchemaNodeBuilder childCopy = CopyUtils.copy(child, target, false);
284 if (augment.getParent() instanceof UsesNodeBuilder) {
285 setNodeAddedByUses(childCopy);
287 setNodeAugmenting(childCopy);
289 target.addChildNode(childCopy);
290 } catch (YangParseException e) {
292 // more descriptive message
293 throw new YangParseException(augment.getModuleName(), augment.getLine(),
294 "Failed to perform augmentation: " + e.getMessage());
300 * Add all augment's child nodes to given target.
303 * builder of augment statement
305 * augmentation target choice node
307 private static void fillAugmentTarget(final AugmentationSchemaBuilder augment, final ChoiceBuilder target) {
308 for (DataSchemaNodeBuilder builder : augment.getChildNodeBuilders()) {
309 DataSchemaNodeBuilder childCopy = CopyUtils.copy(builder, target, false);
310 if (augment.getParent() instanceof UsesNodeBuilder) {
311 setNodeAddedByUses(childCopy);
313 setNodeAugmenting(childCopy);
314 target.addCase(childCopy);
316 for (UsesNodeBuilder usesNode : augment.getUsesNodeBuilders()) {
317 if (usesNode != null) {
318 throw new YangParseException(augment.getModuleName(), augment.getLine(),
319 "Error in augment parsing: cannot augment choice with nodes from grouping");
325 * Set augmenting flag to true for node and all its child nodes.
329 private static void setNodeAugmenting(final DataSchemaNodeBuilder node) {
330 node.setAugmenting(true);
331 if (node instanceof DataNodeContainerBuilder) {
332 DataNodeContainerBuilder dataNodeChild = (DataNodeContainerBuilder) node;
333 for (DataSchemaNodeBuilder inner : dataNodeChild.getChildNodeBuilders()) {
334 setNodeAugmenting(inner);
336 } else if (node instanceof ChoiceBuilder) {
337 ChoiceBuilder choiceChild = (ChoiceBuilder) node;
338 for (ChoiceCaseBuilder inner : choiceChild.getCases()) {
339 setNodeAugmenting(inner);
345 * Set addedByUses flag to true for node and all its child nodes.
349 public static void setNodeAddedByUses(final GroupingMember node) {
350 node.setAddedByUses(true);
351 if (node instanceof DataNodeContainerBuilder) {
352 DataNodeContainerBuilder dataNodeChild = (DataNodeContainerBuilder) node;
353 for (DataSchemaNodeBuilder inner : dataNodeChild.getChildNodeBuilders()) {
354 setNodeAddedByUses(inner);
356 } else if (node instanceof ChoiceBuilder) {
357 ChoiceBuilder choiceChild = (ChoiceBuilder) node;
358 for (ChoiceCaseBuilder inner : choiceChild.getCases()) {
359 setNodeAddedByUses(inner);
364 public static DataSchemaNodeBuilder findSchemaNode(final Iterable<QName> path, final SchemaNodeBuilder parentNode) {
365 DataSchemaNodeBuilder node = null;
366 SchemaNodeBuilder parent = parentNode;
367 int size = Iterables.size(path);
369 for (QName qname : path) {
370 String name = qname.getLocalName();
371 if (parent instanceof DataNodeContainerBuilder) {
372 node = ((DataNodeContainerBuilder) parent).getDataChildByName(name);
373 } else if (parent instanceof ChoiceBuilder) {
374 node = ((ChoiceBuilder) parent).getCaseNodeByName(name);
375 } else if (parent instanceof RpcDefinitionBuilder) {
376 if ("input".equals(name)) {
377 node = ((RpcDefinitionBuilder) parent).getInput();
378 } else if ("output".equals(name)) {
379 node = ((RpcDefinitionBuilder) parent).getOutput();
398 * Find a builder for node in data namespace of YANG module.
400 * Search is performed on full QName equals, this means builders and schema
401 * path MUST be resolved against imports and their namespaces.
403 * Search is done in data namespace, this means notification, rpc
404 * definitions and top level data definitions are considered as top-level
405 * items, from which it is possible to traverse.
409 * Schema Path to node
411 * ModuleBuilder to start lookup in
412 * @return Node Builder if found, {@link Optional#absent()} otherwise.
414 public static Optional<SchemaNodeBuilder> findSchemaNodeInModule(final SchemaPath schemaPath,
415 final ModuleBuilder module) {
416 Iterator<QName> path = schemaPath.getPathFromRoot().iterator();
417 Preconditions.checkArgument(path.hasNext(), "Schema Path must contain at least one element.");
418 QName first = path.next();
419 Optional<SchemaNodeBuilder> currentNode = getDataNamespaceChild(module, first);
421 while (currentNode.isPresent() && path.hasNext()) {
422 currentNode = findDataChild(currentNode.get(), path.next());
427 private static Optional<SchemaNodeBuilder> findDataChild(final SchemaNodeBuilder parent, final QName child) {
428 if (parent instanceof DataNodeContainerBuilder) {
429 return castOptional(SchemaNodeBuilder.class,
430 findDataChildInDataNodeContainer((DataNodeContainerBuilder) parent, child));
431 } else if (parent instanceof ChoiceBuilder) {
432 return castOptional(SchemaNodeBuilder.class, findCaseInChoice((ChoiceBuilder) parent, child));
433 } else if (parent instanceof RpcDefinitionBuilder) {
434 return castOptional(SchemaNodeBuilder.class, findContainerInRpc((RpcDefinitionBuilder) parent, child));
437 LOG.trace("Child {} not found in node {}", child, parent);
438 return Optional.absent();
443 * Casts optional from one argument to other.
446 * Class to be checked
451 private static <T> Optional<T> castOptional(final Class<T> cls, final Optional<?> optional) {
452 if (optional.isPresent()) {
453 Object value = optional.get();
454 if (cls.isInstance(value)) {
455 @SuppressWarnings("unchecked")
456 // Actually checked by outer if
457 T casted = (T) value;
458 return Optional.of(casted);
461 return Optional.absent();
466 * Gets input / output container from {@link RpcDefinitionBuilder} if QName
471 * RPC Definition builder
474 * @return Optional of input/output if defined and QName is input/output.
475 * Otherwise {@link Optional#absent()}.
477 private static Optional<ContainerSchemaNodeBuilder> findContainerInRpc(final RpcDefinitionBuilder parent, final QName child) {
478 if (INPUT.equals(child.getLocalName())) {
479 return Optional.of(parent.getInput());
480 } else if (OUTPUT.equals(child.getLocalName())) {
481 return Optional.of(parent.getOutput());
483 LOG.trace("Child {} not found in node {}", child, parent);
484 return Optional.absent();
488 * Finds case by QName in {@link ChoiceBuilder}
492 * DataNodeContainer in which lookup should be performed
495 * @return Optional of child if found.
498 private static Optional<ChoiceCaseBuilder> findCaseInChoice(final ChoiceBuilder parent, final QName child) {
499 for (ChoiceCaseBuilder caze : parent.getCases()) {
500 if (caze.getQName().equals(child)) {
501 return Optional.of(caze);
504 LOG.trace("Child {} not found in node {}", child, parent);
505 return Optional.absent();
509 * Finds direct child by QName in {@link DataNodeContainerBuilder}
513 * DataNodeContainer in which lookup should be performed
516 * @return Optional of child if found.
518 private static Optional<DataSchemaNodeBuilder> findDataChildInDataNodeContainer(final DataNodeContainerBuilder parent,
520 for (DataSchemaNodeBuilder childNode : parent.getChildNodeBuilders()) {
521 if (childNode.getQName().equals(child)) {
522 return Optional.of(childNode);
525 LOG.trace("Child {} not found in node {}", child, parent);
526 return Optional.absent();
531 * Find a child builder for node in data namespace of YANG module.
533 * Search is performed on full QName equals, this means builders and schema
534 * path MUST be resolved against imports and their namespaces.
536 * Search is done in data namespace, this means notification, rpc
537 * definitions and top level data definitions are considered as top-level
538 * items, from which it is possible to traverse.
544 * ModuleBuilder to start lookup in
545 * @return Node Builder if found, {@link Optional#absent()} otherwise.
547 private static Optional<SchemaNodeBuilder> getDataNamespaceChild(final ModuleBuilder module, final QName child) {
549 * First we do lookup in data tree, if node is found we return it.
551 final Optional<SchemaNodeBuilder> dataTreeNode = getDataChildByQName(module, child);
552 if (dataTreeNode.isPresent()) {
557 * We lookup in notifications
559 Set<NotificationBuilder> notifications = module.getAddedNotifications();
560 for (NotificationBuilder notification : notifications) {
561 if (notification.getQName().equals(child)) {
562 return Optional.<SchemaNodeBuilder> of(notification);
569 Set<RpcDefinitionBuilder> rpcs = module.getAddedRpcs();
570 for (RpcDefinitionBuilder rpc : rpcs) {
571 if (rpc.getQName().equals(child)) {
572 return Optional.<SchemaNodeBuilder> of(rpc);
575 LOG.trace("Child {} not found in data namespace of module {}", child, module);
576 return Optional.absent();
579 private static Optional<SchemaNodeBuilder> getDataChildByQName(final DataNodeContainerBuilder builder, final QName child) {
580 for (DataSchemaNodeBuilder childNode : builder.getChildNodeBuilders()) {
581 if (childNode.getQName().equals(child)) {
582 return Optional.<SchemaNodeBuilder> of(childNode);
585 LOG.trace("Child {} not found in node {}", child, builder);
586 return Optional.absent();
590 * Find augment target node and perform augmentation.
593 * @param firstNodeParent
594 * parent of first node in path
596 * path to augment target
597 * @return true if augmentation process succeed, false otherwise
599 public static boolean processAugmentation(final AugmentationSchemaBuilder augment,
600 final ModuleBuilder firstNodeParent) {
601 Optional<SchemaNodeBuilder> potentialTargetNode = findSchemaNodeInModule(augment.getTargetPath(),
603 if (!potentialTargetNode.isPresent()) {
606 SchemaNodeBuilder targetNode = potentialTargetNode.get();
607 fillAugmentTarget(augment, targetNode);
608 Preconditions.checkState(targetNode instanceof AugmentationTargetBuilder,
609 "Node refered by augmentation must be valid augmentation target");
610 ((AugmentationTargetBuilder) targetNode).addAugmentation(augment);
611 augment.setResolved(true);
615 public static IdentitySchemaNodeBuilder findBaseIdentity(final ModuleBuilder module, final String baseString,
618 // FIXME: optimize indexOf() away?
619 if (baseString.indexOf(':') != -1) {
620 final Iterator<String> it = COLON_SPLITTER.split(baseString).iterator();
621 final String prefix = it.next();
622 final String name = it.next();
625 throw new YangParseException(module.getName(), line, "Failed to parse identityref base: " + baseString);
628 ModuleBuilder dependentModule = getModuleByPrefix(module, prefix);
629 if (dependentModule == null) {
633 return findIdentity(dependentModule.getAddedIdentities(), name);
635 return findIdentity(module.getAddedIdentities(), baseString);
639 public static IdentitySchemaNodeBuilder findIdentity(final Set<IdentitySchemaNodeBuilder> identities,
641 for (IdentitySchemaNodeBuilder identity : identities) {
642 if (identity.getQName().getLocalName().equals(name)) {
650 * Get module in which this node is defined.
653 * @return builder of module where this node is defined
655 public static ModuleBuilder getParentModule(final Builder node) {
656 if (node instanceof ModuleBuilder) {
657 return (ModuleBuilder) node;
659 Builder parent = node.getParent();
660 while (!(parent instanceof ModuleBuilder)) {
661 parent = parent.getParent();
663 ModuleBuilder parentModule = (ModuleBuilder) parent;
664 if (parentModule.isSubmodule()) {
665 parentModule = parentModule.getParent();
670 public static Set<DataSchemaNodeBuilder> wrapChildNodes(final String moduleName, final int line,
671 final Collection<DataSchemaNode> nodes, final SchemaPath parentPath, final QName parentQName) {
672 Set<DataSchemaNodeBuilder> result = new LinkedHashSet<>(nodes.size());
674 for (DataSchemaNode node : nodes) {
675 QName qname = QName.create(parentQName, node.getQName().getLocalName());
676 DataSchemaNodeBuilder wrapped = wrapChildNode(moduleName, line, node, parentPath, qname);
682 public static DataSchemaNodeBuilder wrapChildNode(final String moduleName, final int line,
683 final DataSchemaNode node, final SchemaPath parentPath, final QName qname) {
685 final SchemaPath schemaPath = parentPath.createChild(qname);
687 if (node instanceof AnyXmlSchemaNode) {
688 return new AnyXmlBuilder(moduleName, line, qname, schemaPath, ((AnyXmlSchemaNode) node));
689 } else if (node instanceof ChoiceNode) {
690 return new ChoiceBuilder(moduleName, line, qname, schemaPath, ((ChoiceNode) node));
691 } else if (node instanceof ContainerSchemaNode) {
692 return new ContainerSchemaNodeBuilder(moduleName, line, qname, schemaPath, ((ContainerSchemaNode) node));
693 } else if (node instanceof LeafSchemaNode) {
694 return new LeafSchemaNodeBuilder(moduleName, line, qname, schemaPath, ((LeafSchemaNode) node));
695 } else if (node instanceof LeafListSchemaNode) {
696 return new LeafListSchemaNodeBuilder(moduleName, line, qname, schemaPath, ((LeafListSchemaNode) node));
697 } else if (node instanceof ListSchemaNode) {
698 return new ListSchemaNodeBuilder(moduleName, line, qname, schemaPath, ((ListSchemaNode) node));
699 } else if (node instanceof ChoiceCaseNode) {
700 return new ChoiceCaseBuilder(moduleName, line, qname, schemaPath, ((ChoiceCaseNode) node));
702 throw new YangParseException(moduleName, line, "Failed to copy node: Unknown type of DataSchemaNode: "
707 public static Set<GroupingBuilder> wrapGroupings(final String moduleName, final int line,
708 final Set<GroupingDefinition> nodes, final SchemaPath parentPath, final QName parentQName) {
709 Set<GroupingBuilder> result = new HashSet<>();
710 for (GroupingDefinition node : nodes) {
711 QName qname = QName.create(parentQName, node.getQName().getLocalName());
712 SchemaPath schemaPath = parentPath.createChild(qname);
713 result.add(new GroupingBuilderImpl(moduleName, line, qname, schemaPath, node));
718 public static Set<TypeDefinitionBuilder> wrapTypedefs(final String moduleName, final int line,
719 final DataNodeContainer dataNode, final SchemaPath parentPath, final QName parentQName) {
720 Set<TypeDefinition<?>> nodes = dataNode.getTypeDefinitions();
721 Set<TypeDefinitionBuilder> result = new HashSet<>();
722 for (TypeDefinition<?> node : nodes) {
723 QName qname = QName.create(parentQName, node.getQName().getLocalName());
724 SchemaPath schemaPath = parentPath.createChild(qname);
725 result.add(new TypeDefinitionBuilderImpl(moduleName, line, qname, schemaPath, ((ExtendedType) node)));
730 public static List<UnknownSchemaNodeBuilderImpl> wrapUnknownNodes(final String moduleName, final int line,
731 final List<UnknownSchemaNode> nodes, final SchemaPath parentPath, final QName parentQName) {
732 List<UnknownSchemaNodeBuilderImpl> result = new ArrayList<>();
733 for (UnknownSchemaNode node : nodes) {
734 QName qname = QName.create(parentQName, node.getQName().getLocalName());
735 SchemaPath schemaPath = parentPath.createChild(qname);
736 result.add(new UnknownSchemaNodeBuilderImpl(moduleName, line, qname, schemaPath, node));
741 private static final class ByteSourceImpl extends ByteSource {
742 private final String toString;
743 private final ByteArrayOutputStream output = new ByteArrayOutputStream();
745 private ByteSourceImpl(final InputStream input) throws IOException {
746 toString = input.toString();
747 IOUtils.copy(input, output);
751 public InputStream openStream() throws IOException {
752 return new NamedByteArrayInputStream(output.toByteArray(), toString);
756 public static ModuleBuilder getModuleByPrefix(final ModuleBuilder module, final String prefix) {
757 if (prefix == null || prefix.isEmpty() || prefix.equals(module.getPrefix())) {
760 return module.getImportedModule(prefix);
764 public static ModuleBuilder findModule(final QName qname, final Map<URI, TreeMap<Date, ModuleBuilder>> modules) {
765 TreeMap<Date, ModuleBuilder> map = modules.get(qname.getNamespace());
769 if (qname.getRevision() == null) {
770 return map.lastEntry().getValue();
772 return map.get(qname.getRevision());
775 public static Map<String, TreeMap<Date, URI>> createYangNamespaceContext(
776 final Collection<? extends ParseTree> modules, final Optional<SchemaContext> context) {
777 Map<String, TreeMap<Date, URI>> map = new HashMap<>();
778 for (ParseTree module : modules) {
779 for (int i = 0; i < module.getChildCount(); i++) {
780 ParseTree moduleTree = module.getChild(i);
781 if (moduleTree instanceof Module_stmtContext) {
782 Module_stmtContext moduleCtx = (Module_stmtContext) moduleTree;
783 final String moduleName = ParserListenerUtils.stringFromNode(moduleCtx);
785 URI namespace = null;
786 for (int j = 0; j < moduleCtx.getChildCount(); j++) {
787 ParseTree moduleCtxChildTree = moduleCtx.getChild(j);
788 if (moduleCtxChildTree instanceof Revision_stmtsContext) {
789 String revisionDateStr = YangModelDependencyInfo
790 .getLatestRevision((Revision_stmtsContext) moduleCtxChildTree);
791 if (revisionDateStr == null) {
794 rev = QName.parseRevision(revisionDateStr);
797 if (moduleCtxChildTree instanceof Module_header_stmtsContext) {
798 Module_header_stmtsContext headerCtx = (Module_header_stmtsContext) moduleCtxChildTree;
799 for (int k = 0; k < headerCtx.getChildCount(); k++) {
800 ParseTree ctx = headerCtx.getChild(k);
801 if (ctx instanceof Namespace_stmtContext) {
802 final String namespaceStr = ParserListenerUtils.stringFromNode(ctx);
803 namespace = URI.create(namespaceStr);
809 TreeMap<Date, URI> revToNs = map.get(moduleName);
810 if (revToNs == null) {
811 revToNs = new TreeMap<>();
812 revToNs.put(rev, namespace);
813 map.put(moduleName, revToNs);
815 revToNs.put(rev, namespace);
819 if (context.isPresent()) {
820 for (Module module : context.get().getModules()) {
821 TreeMap<Date, URI> revToNs = map.get(module.getName());
822 if (revToNs == null) {
823 revToNs = new TreeMap<>();
824 revToNs.put(module.getRevision(), module.getNamespace());
825 map.put(module.getName(), revToNs);
827 revToNs.put(module.getRevision(), module.getNamespace());