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.util.ArrayList;
24 import java.util.Collection;
25 import java.util.Date;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.Iterator;
29 import java.util.LinkedHashSet;
30 import java.util.List;
33 import java.util.TreeMap;
34 import org.antlr.v4.runtime.tree.ParseTree;
35 import org.apache.commons.io.IOUtils;
36 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Module_header_stmtsContext;
37 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Module_stmtContext;
38 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Namespace_stmtContext;
39 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_stmtsContext;
40 import org.opendaylight.yangtools.yang.common.QName;
41 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
42 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
43 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
44 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
45 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
46 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
47 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
48 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
49 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
50 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
51 import org.opendaylight.yangtools.yang.model.api.Module;
52 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
53 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
54 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
55 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
56 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
57 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
58 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
59 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationTargetBuilder;
60 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
61 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
62 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
63 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
64 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingMember;
65 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
66 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
67 import org.opendaylight.yangtools.yang.parser.builder.api.UnknownSchemaNodeBuilder;
68 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
69 import org.opendaylight.yangtools.yang.parser.impl.ParserListenerUtils;
70 import org.opendaylight.yangtools.yang.parser.impl.util.YangModelDependencyInfo;
71 import org.opendaylight.yangtools.yang.parser.util.NamedByteArrayInputStream;
72 import org.opendaylight.yangtools.yang.parser.util.NamedFileInputStream;
73 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
74 import org.slf4j.Logger;
75 import org.slf4j.LoggerFactory;
77 public final class BuilderUtils {
79 private static final Logger LOG = LoggerFactory.getLogger(BuilderUtils.class);
80 private static final Splitter COLON_SPLITTER = Splitter.on(':');
81 private static final Date NULL_DATE = new Date(0L);
82 private static final String INPUT = "input";
83 private static final String OUTPUT = "output";
85 private BuilderUtils() {
88 public static Collection<ByteSource> streamsToByteSources(final Collection<InputStream> streams) throws IOException {
89 Collection<ByteSource> result = new HashSet<>();
90 for (InputStream stream : streams) {
91 result.add(new ByteSourceImpl(stream));
96 public static ByteSource fileToByteSource(final File file) {
97 return new ByteSource() {
99 public InputStream openStream() throws IOException {
100 return new NamedFileInputStream(file, file.getAbsolutePath());
105 public static Collection<ByteSource> filesToByteSources(final Collection<File> streams)
106 throws FileNotFoundException {
107 return Collections2.transform(streams, new Function<File, ByteSource>() {
109 public ByteSource apply(final File input) {
110 return new ByteSource() {
112 public InputStream openStream() throws IOException {
113 return new NamedFileInputStream(input, input.getAbsolutePath());
121 * Create new SchemaPath from given path and qname.
126 * one or more qnames added to base path
127 * @return new SchemaPath from given path and qname
129 * @deprecated Use {@link SchemaPath#createChild(QName...)} instead.
132 public static SchemaPath createSchemaPath(final SchemaPath schemaPath, final QName... qname) {
133 return schemaPath.createChild(qname);
137 * Find dependent module based on given prefix
140 * all available modules
144 * target module prefix
146 * current line in yang model
147 * @return module builder if found, null otherwise
149 public static ModuleBuilder findModuleFromBuilders(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
150 final ModuleBuilder module, final String prefix, final int line) {
151 ModuleBuilder dependentModule;
152 Date dependentModuleRevision;
154 if (prefix == null) {
155 dependentModule = module;
156 } else if (prefix.equals(module.getPrefix())) {
157 dependentModule = module;
159 ModuleImport dependentModuleImport = module.getImport(prefix);
160 if (dependentModuleImport == null) {
161 throw new YangParseException(module.getName(), line, "No import found with prefix '" + prefix + "'.");
163 String dependentModuleName = dependentModuleImport.getModuleName();
164 dependentModuleRevision = dependentModuleImport.getRevision();
166 TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules.get(dependentModuleName);
167 if (moduleBuildersByRevision == null) {
170 if (dependentModuleRevision == null) {
171 dependentModule = moduleBuildersByRevision.lastEntry().getValue();
173 dependentModule = moduleBuildersByRevision.get(dependentModuleRevision);
176 return dependentModule;
179 public static ModuleBuilder findModuleFromBuilders(ModuleImport imp, Iterable<ModuleBuilder> modules) {
180 String name = imp.getModuleName();
181 Date revision = imp.getRevision();
182 TreeMap<Date, ModuleBuilder> map = new TreeMap<>();
183 for (ModuleBuilder module : modules) {
184 if (module != null) {
185 if (module.getName().equals(name)) {
186 map.put(module.getRevision(), module);
193 if (revision == null) {
194 return map.lastEntry().getValue();
196 return map.get(revision);
200 * Find module from context based on prefix.
204 * @param currentModule
207 * prefix used to reference dependent module
209 * current line in yang model
210 * @return module based on import with given prefix if found in context,
212 * @throws YangParseException
213 * if no import found with given prefix
215 public static Module findModuleFromContext(final SchemaContext context, final ModuleBuilder currentModule,
216 final String prefix, final int line) {
217 TreeMap<Date, Module> modulesByRevision = new TreeMap<>();
219 ModuleImport dependentModuleImport = currentModule.getImport(prefix);
220 if (dependentModuleImport == null) {
221 throw new YangParseException(currentModule.getName(), line, "No import found with prefix '" + prefix + "'.");
223 String dependentModuleName = dependentModuleImport.getModuleName();
224 Date dependentModuleRevision = dependentModuleImport.getRevision();
226 for (Module contextModule : context.getModules()) {
227 if (contextModule.getName().equals(dependentModuleName)) {
228 Date revision = contextModule.getRevision();
229 if (revision == null) {
230 revision = NULL_DATE;
232 modulesByRevision.put(revision, contextModule);
237 if (dependentModuleRevision == null) {
238 result = modulesByRevision.get(modulesByRevision.firstKey());
240 result = modulesByRevision.get(dependentModuleRevision);
242 if (result == null) {
243 throw new YangParseException(currentModule.getName(), line, "Module not found for prefix " + prefix);
250 * Add all augment's child nodes to given target.
253 * builder of augment statement
255 * augmentation target node
257 public static void fillAugmentTarget(final AugmentationSchemaBuilder augment, final Builder target) {
258 if (target instanceof DataNodeContainerBuilder) {
259 fillAugmentTarget(augment, (DataNodeContainerBuilder) target);
260 } else if (target instanceof ChoiceBuilder) {
261 fillAugmentTarget(augment, (ChoiceBuilder) target);
263 throw new YangParseException(
264 augment.getModuleName(),
266 "Error in augment parsing: The target node MUST be either a container, list, choice, case, input, output, or notification node.");
271 * Add all augment's child nodes to given target.
274 * builder of augment statement
276 * augmentation target node
278 private static void fillAugmentTarget(final AugmentationSchemaBuilder augment, final DataNodeContainerBuilder target) {
279 for (DataSchemaNodeBuilder child : augment.getChildNodeBuilders()) {
280 DataSchemaNodeBuilder childCopy = CopyUtils.copy(child, target, false);
281 if (augment.getParent() instanceof UsesNodeBuilder) {
282 setNodeAddedByUses(childCopy);
284 setNodeAugmenting(childCopy);
286 target.addChildNode(childCopy);
287 } catch (YangParseException e) {
289 // more descriptive message
290 throw new YangParseException(augment.getModuleName(), augment.getLine(),
291 "Failed to perform augmentation: " + e.getMessage());
297 * Add all augment's child nodes to given target.
300 * builder of augment statement
302 * augmentation target choice node
304 private static void fillAugmentTarget(final AugmentationSchemaBuilder augment, final ChoiceBuilder target) {
305 for (DataSchemaNodeBuilder builder : augment.getChildNodeBuilders()) {
306 DataSchemaNodeBuilder childCopy = CopyUtils.copy(builder, target, false);
307 if (augment.getParent() instanceof UsesNodeBuilder) {
308 setNodeAddedByUses(childCopy);
310 setNodeAugmenting(childCopy);
311 target.addCase(childCopy);
313 for (UsesNodeBuilder usesNode : augment.getUsesNodeBuilders()) {
314 if (usesNode != null) {
315 throw new YangParseException(augment.getModuleName(), augment.getLine(),
316 "Error in augment parsing: cannot augment choice with nodes from grouping");
322 * Set augmenting flag to true for node and all its child nodes.
326 private static void setNodeAugmenting(final DataSchemaNodeBuilder node) {
327 node.setAugmenting(true);
328 if (node instanceof DataNodeContainerBuilder) {
329 DataNodeContainerBuilder dataNodeChild = (DataNodeContainerBuilder) node;
330 for (DataSchemaNodeBuilder inner : dataNodeChild.getChildNodeBuilders()) {
331 setNodeAugmenting(inner);
333 } else if (node instanceof ChoiceBuilder) {
334 ChoiceBuilder choiceChild = (ChoiceBuilder) node;
335 for (ChoiceCaseBuilder inner : choiceChild.getCases()) {
336 setNodeAugmenting(inner);
342 * Set addedByUses flag to true for node and all its child nodes.
346 public static void setNodeAddedByUses(final GroupingMember node) {
347 node.setAddedByUses(true);
348 if (node instanceof DataNodeContainerBuilder) {
349 DataNodeContainerBuilder dataNodeChild = (DataNodeContainerBuilder) node;
350 for (DataSchemaNodeBuilder inner : dataNodeChild.getChildNodeBuilders()) {
351 setNodeAddedByUses(inner);
353 } else if (node instanceof ChoiceBuilder) {
354 ChoiceBuilder choiceChild = (ChoiceBuilder) node;
355 for (ChoiceCaseBuilder inner : choiceChild.getCases()) {
356 setNodeAddedByUses(inner);
361 public static SchemaNodeBuilder findSchemaNode(final Iterable<QName> path, final SchemaNodeBuilder parentNode) {
362 SchemaNodeBuilder node = null;
363 SchemaNodeBuilder parent = parentNode;
364 int size = Iterables.size(path);
366 for (QName qname : path) {
367 String name = qname.getLocalName();
368 if (parent instanceof DataNodeContainerBuilder) {
369 node = ((DataNodeContainerBuilder) parent).getDataChildByName(name);
371 node = findUnknownNode(name, parent);
373 } else if (parent instanceof ChoiceBuilder) {
374 node = ((ChoiceBuilder) parent).getCaseNodeByName(name);
376 node = findUnknownNode(name, parent);
378 } else if (parent instanceof RpcDefinitionBuilder) {
379 if ("input".equals(name)) {
380 node = ((RpcDefinitionBuilder) parent).getInput();
381 } else if ("output".equals(name)) {
382 node = ((RpcDefinitionBuilder) parent).getOutput();
385 node = findUnknownNode(name, parent);
389 node = findUnknownNode(name, parent);
401 private static UnknownSchemaNodeBuilder findUnknownNode(final String name, final Builder parent) {
402 for (UnknownSchemaNodeBuilder un : parent.getUnknownNodes()) {
403 if (un.getQName().getLocalName().equals(name)) {
412 * Find a builder for node in data namespace of YANG module.
414 * Search is performed on full QName equals, this means builders and schema
415 * path MUST be resolved against imports and their namespaces.
417 * Search is done in data namespace, this means notification, rpc
418 * definitions and top level data definitions are considered as top-level
419 * items, from which it is possible to traverse.
423 * Schema Path to node
425 * ModuleBuilder to start lookup in
426 * @return Node Builder if found, {@link Optional#absent()} otherwise.
428 public static Optional<SchemaNodeBuilder> findSchemaNodeInModule(final SchemaPath schemaPath,
429 final ModuleBuilder module) {
430 Iterator<QName> path = schemaPath.getPathFromRoot().iterator();
431 Preconditions.checkArgument(path.hasNext(), "Schema Path must contain at least one element.");
432 QName first = path.next();
433 Optional<SchemaNodeBuilder> currentNode = getDataNamespaceChild(module, first);
435 while (currentNode.isPresent() && path.hasNext()) {
436 SchemaNodeBuilder currentParent = currentNode.get();
437 QName currentPath = path.next();
438 currentNode = findDataChild(currentParent, currentPath);
439 if (!currentNode.isPresent()) {
440 for (SchemaNodeBuilder un : currentParent.getUnknownNodes()) {
441 if (un.getQName().equals(currentPath)) {
442 currentNode = Optional.of(un);
450 private static Optional<SchemaNodeBuilder> findDataChild(final SchemaNodeBuilder parent, final QName child) {
451 if (parent instanceof DataNodeContainerBuilder) {
452 return castOptional(SchemaNodeBuilder.class,
453 findDataChildInDataNodeContainer((DataNodeContainerBuilder) parent, child));
454 } else if (parent instanceof ChoiceBuilder) {
455 return castOptional(SchemaNodeBuilder.class, findCaseInChoice((ChoiceBuilder) parent, child));
456 } else if (parent instanceof RpcDefinitionBuilder) {
457 return castOptional(SchemaNodeBuilder.class, findContainerInRpc((RpcDefinitionBuilder) parent, child));
460 LOG.trace("Child {} not found in node {}", child, parent);
461 return Optional.absent();
466 * Casts optional from one argument to other.
469 * Class to be checked
472 * @return Optional object with type argument casted as cls
474 private static <T> Optional<T> castOptional(final Class<T> cls, final Optional<?> optional) {
475 if (optional.isPresent()) {
476 Object value = optional.get();
477 if (cls.isInstance(value)) {
478 @SuppressWarnings("unchecked")
479 // Actually checked by outer if
480 T casted = (T) value;
481 return Optional.of(casted);
484 return Optional.absent();
487 // FIXME: if rpc does not define input or output, this method creates it
490 * Gets input / output container from {@link RpcDefinitionBuilder} if QName
495 * RPC Definition builder
498 * @return Optional of input/output if defined and QName is input/output.
499 * Otherwise {@link Optional#absent()}.
501 private static Optional<ContainerSchemaNodeBuilder> findContainerInRpc(final RpcDefinitionBuilder parent,
503 if (INPUT.equals(child.getLocalName())) {
504 if (parent.getInput() == null) {
505 QName qname = QName.create(parent.getQName().getModule(), "input");
506 final ContainerSchemaNodeBuilder inputBuilder = new ContainerSchemaNodeBuilder(parent.getModuleName(),
507 parent.getLine(), qname, parent.getPath().createChild(qname));
508 inputBuilder.setParent(parent);
509 parent.setInput(inputBuilder);
510 return Optional.of(inputBuilder);
512 return Optional.of(parent.getInput());
513 } else if (OUTPUT.equals(child.getLocalName())) {
514 if (parent.getOutput() == null) {
515 QName qname = QName.create(parent.getQName().getModule(), "output");
516 final ContainerSchemaNodeBuilder outputBuilder = new ContainerSchemaNodeBuilder(parent.getModuleName(),
517 parent.getLine(), qname, parent.getPath().createChild(qname));
518 outputBuilder.setParent(parent);
519 parent.setOutput(outputBuilder);
520 return Optional.of(outputBuilder);
522 return Optional.of(parent.getOutput());
524 LOG.trace("Child {} not found in node {}", child, parent);
525 return Optional.absent();
529 * Finds case by QName in {@link ChoiceBuilder}
533 * DataNodeContainer in which lookup should be performed
536 * @return Optional of child if found.
539 private static Optional<ChoiceCaseBuilder> findCaseInChoice(final ChoiceBuilder parent, final QName child) {
540 for (ChoiceCaseBuilder caze : parent.getCases()) {
541 if (caze.getQName().equals(child)) {
542 return Optional.of(caze);
545 LOG.trace("Child {} not found in node {}", child, parent);
546 return Optional.absent();
550 * Finds direct child by QName in {@link DataNodeContainerBuilder}
554 * DataNodeContainer in which lookup should be performed
557 * @return Optional of child if found.
559 private static Optional<DataSchemaNodeBuilder> findDataChildInDataNodeContainer(final DataNodeContainerBuilder parent,
561 for (DataSchemaNodeBuilder childNode : parent.getChildNodeBuilders()) {
562 if (childNode.getQName().equals(child)) {
563 return Optional.of(childNode);
566 LOG.trace("Child {} not found in node {}", child, parent);
567 return Optional.absent();
572 * Find a child builder for node in data namespace of YANG module.
574 * Search is performed on full QName equals, this means builders and schema
575 * path MUST be resolved against imports and their namespaces.
577 * Search is done in data namespace, this means notification, rpc
578 * definitions and top level data definitions are considered as top-level
579 * items, from which it is possible to traverse.
585 * ModuleBuilder to start lookup in
586 * @return Node Builder if found, {@link Optional#absent()} otherwise.
588 private static Optional<SchemaNodeBuilder> getDataNamespaceChild(final ModuleBuilder module, final QName child) {
590 * First we do lookup in data tree, if node is found we return it.
592 final Optional<SchemaNodeBuilder> dataTreeNode = getDataChildByQName(module, child);
593 if (dataTreeNode.isPresent()) {
598 * We lookup in notifications
600 Set<NotificationBuilder> notifications = module.getAddedNotifications();
601 for (NotificationBuilder notification : notifications) {
602 if (notification.getQName().equals(child)) {
603 return Optional.<SchemaNodeBuilder> of(notification);
610 Set<RpcDefinitionBuilder> rpcs = module.getAddedRpcs();
611 for (RpcDefinitionBuilder rpc : rpcs) {
612 if (rpc.getQName().equals(child)) {
613 return Optional.<SchemaNodeBuilder> of(rpc);
616 LOG.trace("Child {} not found in data namespace of module {}", child, module);
617 return Optional.absent();
620 private static Optional<SchemaNodeBuilder> getDataChildByQName(final DataNodeContainerBuilder builder, final QName child) {
621 for (DataSchemaNodeBuilder childNode : builder.getChildNodeBuilders()) {
622 if (childNode.getQName().equals(child)) {
623 return Optional.<SchemaNodeBuilder> of(childNode);
626 LOG.trace("Child {} not found in node {}", child, builder);
627 return Optional.absent();
631 * Find augment target node and perform augmentation.
634 * augment builder to process
635 * @param firstNodeParent
636 * parent of first node in path
637 * @return true if augmentation process succeed, false otherwise
639 public static boolean processAugmentation(final AugmentationSchemaBuilder augment,
640 final ModuleBuilder firstNodeParent) {
641 Optional<SchemaNodeBuilder> potentialTargetNode = findSchemaNodeInModule(augment.getTargetPath(),
643 if (!potentialTargetNode.isPresent()) {
645 } else if (potentialTargetNode.get() instanceof UnknownSchemaNodeBuilder) {
646 LOG.warn("Error in augment parsing: unsupported augment target: {}", potentialTargetNode.get());
649 SchemaNodeBuilder targetNode = potentialTargetNode.get();
650 fillAugmentTarget(augment, targetNode);
651 Preconditions.checkState(targetNode instanceof AugmentationTargetBuilder,
652 "Node refered by augmentation must be valid augmentation target");
653 ((AugmentationTargetBuilder) targetNode).addAugmentation(augment);
654 augment.setResolved(true);
658 public static IdentitySchemaNodeBuilder findBaseIdentity(final ModuleBuilder module, final String baseString,
661 // FIXME: optimize indexOf() away?
662 if (baseString.indexOf(':') != -1) {
663 final Iterator<String> it = COLON_SPLITTER.split(baseString).iterator();
664 final String prefix = it.next();
665 final String name = it.next();
668 throw new YangParseException(module.getName(), line, "Failed to parse identityref base: " + baseString);
671 ModuleBuilder dependentModule = getModuleByPrefix(module, prefix);
672 if (dependentModule == null) {
676 return findIdentity(dependentModule.getAddedIdentities(), name);
678 return findIdentity(module.getAddedIdentities(), baseString);
682 public static IdentitySchemaNodeBuilder findIdentity(final Set<IdentitySchemaNodeBuilder> identities,
684 for (IdentitySchemaNodeBuilder identity : identities) {
685 if (identity.getQName().getLocalName().equals(name)) {
693 * Get module in which this node is defined.
696 * @return builder of module where this node is defined
698 public static ModuleBuilder getParentModule(final Builder node) {
699 if (node instanceof ModuleBuilder) {
700 return (ModuleBuilder) node;
702 Builder parent = node.getParent();
703 while (!(parent instanceof ModuleBuilder)) {
704 parent = parent.getParent();
706 ModuleBuilder parentModule = (ModuleBuilder) parent;
707 if (parentModule.isSubmodule()) {
708 parentModule = parentModule.getParent();
713 public static Set<DataSchemaNodeBuilder> wrapChildNodes(final String moduleName, final int line,
714 final Collection<DataSchemaNode> nodes, final SchemaPath parentPath, final QName parentQName) {
715 Set<DataSchemaNodeBuilder> result = new LinkedHashSet<>(nodes.size());
717 for (DataSchemaNode node : nodes) {
718 QName qname = QName.create(parentQName, node.getQName().getLocalName());
719 DataSchemaNodeBuilder wrapped = wrapChildNode(moduleName, line, node, parentPath, qname);
725 public static DataSchemaNodeBuilder wrapChildNode(final String moduleName, final int line,
726 final DataSchemaNode node, final SchemaPath parentPath, final QName qname) {
728 final SchemaPath schemaPath = parentPath.createChild(qname);
730 if (node instanceof AnyXmlSchemaNode) {
731 return new AnyXmlBuilder(moduleName, line, qname, schemaPath, ((AnyXmlSchemaNode) node));
732 } else if (node instanceof ChoiceNode) {
733 return new ChoiceBuilder(moduleName, line, qname, schemaPath, ((ChoiceNode) node));
734 } else if (node instanceof ContainerSchemaNode) {
735 return new ContainerSchemaNodeBuilder(moduleName, line, qname, schemaPath, ((ContainerSchemaNode) node));
736 } else if (node instanceof LeafSchemaNode) {
737 return new LeafSchemaNodeBuilder(moduleName, line, qname, schemaPath, ((LeafSchemaNode) node));
738 } else if (node instanceof LeafListSchemaNode) {
739 return new LeafListSchemaNodeBuilder(moduleName, line, qname, schemaPath, ((LeafListSchemaNode) node));
740 } else if (node instanceof ListSchemaNode) {
741 return new ListSchemaNodeBuilder(moduleName, line, qname, schemaPath, ((ListSchemaNode) node));
742 } else if (node instanceof ChoiceCaseNode) {
743 return new ChoiceCaseBuilder(moduleName, line, qname, schemaPath, ((ChoiceCaseNode) node));
745 throw new YangParseException(moduleName, line, "Failed to copy node: Unknown type of DataSchemaNode: "
750 public static Set<GroupingBuilder> wrapGroupings(final String moduleName, final int line,
751 final Set<GroupingDefinition> nodes, final SchemaPath parentPath, final QName parentQName) {
752 Set<GroupingBuilder> result = new HashSet<>();
753 for (GroupingDefinition node : nodes) {
754 QName qname = QName.create(parentQName, node.getQName().getLocalName());
755 SchemaPath schemaPath = parentPath.createChild(qname);
756 result.add(new GroupingBuilderImpl(moduleName, line, qname, schemaPath, node));
761 public static Set<TypeDefinitionBuilder> wrapTypedefs(final String moduleName, final int line,
762 final DataNodeContainer dataNode, final SchemaPath parentPath, final QName parentQName) {
763 Set<TypeDefinition<?>> nodes = dataNode.getTypeDefinitions();
764 Set<TypeDefinitionBuilder> result = new HashSet<>();
765 for (TypeDefinition<?> node : nodes) {
766 QName qname = QName.create(parentQName, node.getQName().getLocalName());
767 SchemaPath schemaPath = parentPath.createChild(qname);
768 result.add(new TypeDefinitionBuilderImpl(moduleName, line, qname, schemaPath, ((ExtendedType) node)));
773 public static List<UnknownSchemaNodeBuilderImpl> wrapUnknownNodes(final String moduleName, final int line,
774 final List<UnknownSchemaNode> nodes, final SchemaPath parentPath, final QName parentQName) {
775 List<UnknownSchemaNodeBuilderImpl> result = new ArrayList<>();
776 for (UnknownSchemaNode node : nodes) {
777 QName qname = QName.create(parentQName, node.getQName().getLocalName());
778 SchemaPath schemaPath = parentPath.createChild(qname);
779 result.add(new UnknownSchemaNodeBuilderImpl(moduleName, line, qname, schemaPath, node));
784 private static final class ByteSourceImpl extends ByteSource {
785 private final String toString;
786 private final ByteArrayOutputStream output = new ByteArrayOutputStream();
788 private ByteSourceImpl(final InputStream input) throws IOException {
789 toString = input.toString();
790 IOUtils.copy(input, output);
794 public InputStream openStream() throws IOException {
795 return new NamedByteArrayInputStream(output.toByteArray(), toString);
799 public static ModuleBuilder getModuleByPrefix(final ModuleBuilder module, final String prefix) {
800 if (prefix == null || prefix.isEmpty() || prefix.equals(module.getPrefix())) {
803 return module.getImportedModule(prefix);
807 public static ModuleBuilder findModule(final QName qname, final Map<URI, TreeMap<Date, ModuleBuilder>> modules) {
808 TreeMap<Date, ModuleBuilder> map = modules.get(qname.getNamespace());
812 if (qname.getRevision() == null) {
813 return map.lastEntry().getValue();
815 return map.get(qname.getRevision());
818 public static Map<String, TreeMap<Date, URI>> createYangNamespaceContext(
819 final Collection<? extends ParseTree> modules, final Optional<SchemaContext> context) {
820 Map<String, TreeMap<Date, URI>> map = new HashMap<>();
821 for (ParseTree module : modules) {
822 for (int i = 0; i < module.getChildCount(); i++) {
823 ParseTree moduleTree = module.getChild(i);
824 if (moduleTree instanceof Module_stmtContext) {
825 Module_stmtContext moduleCtx = (Module_stmtContext) moduleTree;
826 final String moduleName = ParserListenerUtils.stringFromNode(moduleCtx);
828 URI namespace = null;
829 for (int j = 0; j < moduleCtx.getChildCount(); j++) {
830 ParseTree moduleCtxChildTree = moduleCtx.getChild(j);
831 if (moduleCtxChildTree instanceof Revision_stmtsContext) {
832 String revisionDateStr = YangModelDependencyInfo
833 .getLatestRevision((Revision_stmtsContext) moduleCtxChildTree);
834 if (revisionDateStr == null) {
837 rev = QName.parseRevision(revisionDateStr);
840 if (moduleCtxChildTree instanceof Module_header_stmtsContext) {
841 Module_header_stmtsContext headerCtx = (Module_header_stmtsContext) moduleCtxChildTree;
842 for (int k = 0; k < headerCtx.getChildCount(); k++) {
843 ParseTree ctx = headerCtx.getChild(k);
844 if (ctx instanceof Namespace_stmtContext) {
845 final String namespaceStr = ParserListenerUtils.stringFromNode(ctx);
846 namespace = URI.create(namespaceStr);
852 TreeMap<Date, URI> revToNs = map.get(moduleName);
853 if (revToNs == null) {
854 revToNs = new TreeMap<>();
855 revToNs.put(rev, namespace);
856 map.put(moduleName, revToNs);
858 revToNs.put(rev, namespace);
862 if (context.isPresent()) {
863 for (Module module : context.get().getModules()) {
864 TreeMap<Date, URI> revToNs = map.get(module.getName());
865 if (revToNs == null) {
866 revToNs = new TreeMap<>();
867 revToNs.put(module.getRevision(), module.getNamespace());
868 map.put(module.getName(), revToNs);
870 revToNs.put(module.getRevision(), module.getNamespace());