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.io.ByteSource;
17 import java.io.ByteArrayOutputStream;
19 import java.io.FileNotFoundException;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.Date;
25 import java.util.HashSet;
26 import java.util.Iterator;
27 import java.util.LinkedHashSet;
28 import java.util.List;
31 import java.util.TreeMap;
33 import org.apache.commons.io.IOUtils;
34 import org.opendaylight.yangtools.yang.common.QName;
35 import org.opendaylight.yangtools.yang.common.QNameModule;
36 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
37 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
38 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
39 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
40 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
41 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
42 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
43 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
44 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
45 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
46 import org.opendaylight.yangtools.yang.model.api.Module;
47 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
48 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
49 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
50 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
51 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
52 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
53 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
54 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationTargetBuilder;
55 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
56 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
57 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
58 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
59 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingMember;
60 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
61 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
62 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
63 import org.opendaylight.yangtools.yang.parser.util.NamedByteArrayInputStream;
64 import org.opendaylight.yangtools.yang.parser.util.NamedFileInputStream;
65 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
66 import org.slf4j.Logger;
67 import org.slf4j.LoggerFactory;
69 public final class BuilderUtils {
71 private static final Logger LOG = LoggerFactory.getLogger(BuilderUtils.class);
72 private static final Splitter SLASH_SPLITTER = Splitter.on('/').omitEmptyStrings();
73 private static final Splitter COLON_SPLITTER = Splitter.on(':');
74 private static final Date NULL_DATE = new Date(0L);
75 private static final String INPUT = "input";
76 private static final String OUTPUT = "output";
78 private BuilderUtils() {
81 public static Collection<ByteSource> streamsToByteSources(final Collection<InputStream> streams) throws IOException {
82 Collection<ByteSource> result = new HashSet<>();
83 for (InputStream stream : streams) {
84 result.add(new ByteSourceImpl(stream));
89 public static ByteSource fileToByteSource(final File file) {
90 return new ByteSource() {
92 public InputStream openStream() throws IOException {
93 return new NamedFileInputStream(file, file.getAbsolutePath());
98 public static Collection<ByteSource> filesToByteSources(final Collection<File> streams)
99 throws FileNotFoundException {
100 return Collections2.transform(streams, new Function<File, ByteSource>() {
102 public ByteSource apply(final File input) {
103 return new ByteSource() {
105 public InputStream openStream() throws IOException {
106 return new NamedFileInputStream(input, input.getAbsolutePath());
114 * Create new SchemaPath from given path and qname.
119 * one or more qnames added to base path
120 * @return new SchemaPath from given path and qname
122 * @deprecated Use {@link SchemaPath#createChild(QName...)} instead.
125 public static SchemaPath createSchemaPath(final SchemaPath schemaPath, final QName... qname) {
126 return schemaPath.createChild(qname);
130 * Find dependent module based on given prefix
133 * all available modules
137 * target module prefix
139 * current line in yang model
140 * @return module builder if found, null otherwise
142 public static ModuleBuilder findModuleFromBuilders(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
143 final ModuleBuilder module, final String prefix, final int line) {
144 ModuleBuilder dependentModule;
145 Date dependentModuleRevision;
147 if (prefix == null) {
148 dependentModule = module;
149 } else if (prefix.equals(module.getPrefix())) {
150 dependentModule = module;
152 ModuleImport dependentModuleImport = module.getImport(prefix);
153 if (dependentModuleImport == null) {
154 throw new YangParseException(module.getName(), line, "No import found with prefix '" + prefix + "'.");
156 String dependentModuleName = dependentModuleImport.getModuleName();
157 dependentModuleRevision = dependentModuleImport.getRevision();
159 TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules.get(dependentModuleName);
160 if (moduleBuildersByRevision == null) {
163 if (dependentModuleRevision == null) {
164 dependentModule = moduleBuildersByRevision.lastEntry().getValue();
166 dependentModule = moduleBuildersByRevision.get(dependentModuleRevision);
169 return dependentModule;
173 * Find module from context based on prefix.
177 * @param currentModule
180 * prefix used to reference dependent module
182 * current line in yang model
183 * @return module based on import with given prefix if found in context,
185 * @throws YangParseException
186 * if no import found with given prefix
188 public static Module findModuleFromContext(final SchemaContext context, final ModuleBuilder currentModule,
189 final String prefix, final int line) {
190 TreeMap<Date, Module> modulesByRevision = new TreeMap<>();
192 ModuleImport dependentModuleImport = currentModule.getImport(prefix);
193 if (dependentModuleImport == null) {
194 throw new YangParseException(currentModule.getName(), line, "No import found with prefix '" + prefix + "'.");
196 String dependentModuleName = dependentModuleImport.getModuleName();
197 Date dependentModuleRevision = dependentModuleImport.getRevision();
199 for (Module contextModule : context.getModules()) {
200 if (contextModule.getName().equals(dependentModuleName)) {
201 Date revision = contextModule.getRevision();
202 if (revision == null) {
203 revision = NULL_DATE;
205 modulesByRevision.put(revision, contextModule);
210 if (dependentModuleRevision == null) {
211 result = modulesByRevision.get(modulesByRevision.firstKey());
213 result = modulesByRevision.get(dependentModuleRevision);
215 if (result == null) {
216 throw new YangParseException(currentModule.getName(), line, "Module not found for prefix " + prefix);
223 * Parse XPath string.
227 * @return SchemaPath from given String
229 public static SchemaPath parseXPathString(final String xpathString) {
230 final boolean absolute = !xpathString.isEmpty() && xpathString.charAt(0) == '/';
232 final List<QName> path = new ArrayList<>();
233 for (String pathElement : SLASH_SPLITTER.split(xpathString)) {
234 final Iterator<String> it = COLON_SPLITTER.split(pathElement).iterator();
235 final String s = it.next();
239 name = QName.create(QNameModule.create(null, null), s, it.next());
241 name = QName.create(QNameModule.create(null, null), s);
245 return SchemaPath.create(path, absolute);
249 * Add all augment's child nodes to given target.
252 * builder of augment statement
254 * augmentation target node
256 public static void fillAugmentTarget(final AugmentationSchemaBuilder augment, final Builder target) {
257 if (target instanceof DataNodeContainerBuilder) {
258 fillAugmentTarget(augment, (DataNodeContainerBuilder) target);
259 } else if (target instanceof ChoiceBuilder) {
260 fillAugmentTarget(augment, (ChoiceBuilder) target);
262 throw new YangParseException(
263 augment.getModuleName(),
265 "Error in augment parsing: The target node MUST be either a container, list, choice, case, input, output, or notification node.");
270 * Add all augment's child nodes to given target.
273 * builder of augment statement
275 * augmentation target node
277 private static void fillAugmentTarget(final AugmentationSchemaBuilder augment, final DataNodeContainerBuilder target) {
278 for (DataSchemaNodeBuilder child : augment.getChildNodeBuilders()) {
279 DataSchemaNodeBuilder childCopy = CopyUtils.copy(child, target, false);
280 if (augment.getParent() instanceof UsesNodeBuilder) {
281 setNodeAddedByUses(childCopy);
283 setNodeAugmenting(childCopy);
285 target.addChildNode(childCopy);
286 } catch (YangParseException e) {
288 // more descriptive message
289 throw new YangParseException(augment.getModuleName(), augment.getLine(),
290 "Failed to perform augmentation: " + e.getMessage());
296 * Add all augment's child nodes to given target.
299 * builder of augment statement
301 * augmentation target choice node
303 private static void fillAugmentTarget(final AugmentationSchemaBuilder augment, final ChoiceBuilder target) {
304 for (DataSchemaNodeBuilder builder : augment.getChildNodeBuilders()) {
305 DataSchemaNodeBuilder childCopy = CopyUtils.copy(builder, target, false);
306 if (augment.getParent() instanceof UsesNodeBuilder) {
307 setNodeAddedByUses(childCopy);
309 setNodeAugmenting(childCopy);
310 target.addCase(childCopy);
312 for (UsesNodeBuilder usesNode : augment.getUsesNodeBuilders()) {
313 if (usesNode != null) {
314 throw new YangParseException(augment.getModuleName(), augment.getLine(),
315 "Error in augment parsing: cannot augment choice with nodes from grouping");
321 * Set augmenting flag to true for node and all its child nodes.
325 private static void setNodeAugmenting(final DataSchemaNodeBuilder node) {
326 node.setAugmenting(true);
327 if (node instanceof DataNodeContainerBuilder) {
328 DataNodeContainerBuilder dataNodeChild = (DataNodeContainerBuilder) node;
329 for (DataSchemaNodeBuilder inner : dataNodeChild.getChildNodeBuilders()) {
330 setNodeAugmenting(inner);
332 } else if (node instanceof ChoiceBuilder) {
333 ChoiceBuilder choiceChild = (ChoiceBuilder) node;
334 for (ChoiceCaseBuilder inner : choiceChild.getCases()) {
335 setNodeAugmenting(inner);
341 * Set addedByUses flag to true for node and all its child nodes.
345 public static void setNodeAddedByUses(final GroupingMember node) {
346 node.setAddedByUses(true);
347 if (node instanceof DataNodeContainerBuilder) {
348 DataNodeContainerBuilder dataNodeChild = (DataNodeContainerBuilder) node;
349 for (DataSchemaNodeBuilder inner : dataNodeChild.getChildNodeBuilders()) {
350 setNodeAddedByUses(inner);
352 } else if (node instanceof ChoiceBuilder) {
353 ChoiceBuilder choiceChild = (ChoiceBuilder) node;
354 for (ChoiceCaseBuilder inner : choiceChild.getCases()) {
355 setNodeAddedByUses(inner);
360 public static DataSchemaNodeBuilder findSchemaNode(final List<QName> path, final SchemaNodeBuilder parentNode) {
361 DataSchemaNodeBuilder node = null;
362 SchemaNodeBuilder parent = parentNode;
364 while (i < path.size()) {
365 String name = path.get(i).getLocalName();
366 if (parent instanceof DataNodeContainerBuilder) {
367 node = ((DataNodeContainerBuilder) parent).getDataChildByName(name);
368 } else if (parent instanceof ChoiceBuilder) {
369 node = ((ChoiceBuilder) parent).getCaseNodeByName(name);
370 } else if (parent instanceof RpcDefinitionBuilder) {
371 if ("input".equals(name)) {
372 node = ((RpcDefinitionBuilder) parent).getInput();
373 } else if ("output".equals(name)) {
374 node = ((RpcDefinitionBuilder) parent).getOutput();
382 if (i < path.size() - 1) {
393 * Find a builder for node in data namespace of YANG module.
395 * Search is performed on full QName equals, this means builders and schema
396 * path MUST be resolved against imports and their namespaces.
398 * Search is done in data namespace, this means notification, rpc
399 * definitions and top level data definitions are considered as top-level
400 * items, from which it is possible to traverse.
404 * Schema Path to node
406 * ModuleBuilder to start lookup in
407 * @return Node Builder if found, {@link Optional#absent()} otherwise.
409 public static Optional<SchemaNodeBuilder> findSchemaNodeInModule(final SchemaPath schemaPath,
410 final ModuleBuilder module) {
411 Iterator<QName> path = schemaPath.getPathFromRoot().iterator();
412 Preconditions.checkArgument(path.hasNext(), "Schema Path must contain at least one element.");
413 QName first = path.next();
414 Optional<SchemaNodeBuilder> currentNode = getDataNamespaceChild(module, first);
416 while (currentNode.isPresent() && path.hasNext()) {
417 currentNode = findDataChild(currentNode.get(), path.next());
422 private static Optional<SchemaNodeBuilder> findDataChild(final SchemaNodeBuilder parent, final QName child) {
423 if (parent instanceof DataNodeContainerBuilder) {
424 return castOptional(SchemaNodeBuilder.class,
425 findDataChildInDataNodeContainer((DataNodeContainerBuilder) parent, child));
426 } else if (parent instanceof ChoiceBuilder) {
427 return castOptional(SchemaNodeBuilder.class, findCaseInChoice((ChoiceBuilder) parent, child));
428 } else if (parent instanceof RpcDefinitionBuilder) {
429 return castOptional(SchemaNodeBuilder.class, findContainerInRpc((RpcDefinitionBuilder) parent, child));
432 LOG.trace("Child {} not found in node {}", child, parent);
433 return Optional.absent();
438 * Casts optional from one argument to other.
441 * Class to be checked
446 private static <T> Optional<T> castOptional(final Class<T> cls, final Optional<?> optional) {
447 if (optional.isPresent()) {
448 Object value = optional.get();
449 if (cls.isInstance(value)) {
450 @SuppressWarnings("unchecked")
451 // Actually checked by outer if
452 T casted = (T) value;
453 return Optional.of(casted);
456 return Optional.absent();
461 * Gets input / output container from {@link RpcDefinitionBuilder} if QName
466 * RPC Definition builder
469 * @return Optional of input/output if defined and QName is input/output.
470 * Otherwise {@link Optional#absent()}.
472 private static Optional<ContainerSchemaNodeBuilder> findContainerInRpc(final RpcDefinitionBuilder parent, final QName child) {
473 if (INPUT.equals(child.getLocalName())) {
474 return Optional.of(parent.getInput());
475 } else if (OUTPUT.equals(child.getLocalName())) {
476 return Optional.of(parent.getOutput());
478 LOG.trace("Child {} not found in node {}", child, parent);
479 return Optional.absent();
483 * Finds case by QName in {@link ChoiceBuilder}
487 * DataNodeContainer in which lookup should be performed
490 * @return Optional of child if found.
493 private static Optional<ChoiceCaseBuilder> findCaseInChoice(final ChoiceBuilder parent, final QName child) {
494 for (ChoiceCaseBuilder caze : parent.getCases()) {
495 if (caze.getQName().equals(child)) {
496 return Optional.of(caze);
499 LOG.trace("Child {} not found in node {}", child, parent);
500 return Optional.absent();
504 * Finds direct child by QName in {@link DataNodeContainerBuilder}
508 * DataNodeContainer in which lookup should be performed
511 * @return Optional of child if found.
513 private static Optional<DataSchemaNodeBuilder> findDataChildInDataNodeContainer(final DataNodeContainerBuilder parent,
515 for (DataSchemaNodeBuilder childNode : parent.getChildNodeBuilders()) {
516 if (childNode.getQName().equals(child)) {
517 return Optional.of(childNode);
520 LOG.trace("Child {} not found in node {}", child, parent);
521 return Optional.absent();
526 * Find a child builder for node in data namespace of YANG module.
528 * Search is performed on full QName equals, this means builders and schema
529 * path MUST be resolved against imports and their namespaces.
531 * Search is done in data namespace, this means notification, rpc
532 * definitions and top level data definitions are considered as top-level
533 * items, from which it is possible to traverse.
539 * ModuleBuilder to start lookup in
540 * @return Node Builder if found, {@link Optional#absent()} otherwise.
542 private static Optional<SchemaNodeBuilder> getDataNamespaceChild(final ModuleBuilder module, final QName child) {
544 * First we do lookup in data tree, if node is found we return it.
546 final Optional<SchemaNodeBuilder> dataTreeNode = getDataChildByQName(module, child);
547 if (dataTreeNode.isPresent()) {
552 * We lookup in notifications
554 Set<NotificationBuilder> notifications = module.getAddedNotifications();
555 for (NotificationBuilder notification : notifications) {
556 if (notification.getQName().equals(child)) {
557 return Optional.<SchemaNodeBuilder> of(notification);
564 Set<RpcDefinitionBuilder> rpcs = module.getAddedRpcs();
565 for (RpcDefinitionBuilder rpc : rpcs) {
566 if (rpc.getQName().equals(child)) {
567 return Optional.<SchemaNodeBuilder> of(rpc);
570 LOG.trace("Child {} not found in data namespace of module {}", child, module);
571 return Optional.absent();
574 private static Optional<SchemaNodeBuilder> getDataChildByQName(final DataNodeContainerBuilder builder, final QName child) {
575 for (DataSchemaNodeBuilder childNode : builder.getChildNodeBuilders()) {
576 if (childNode.getQName().equals(child)) {
577 return Optional.<SchemaNodeBuilder> of(childNode);
580 LOG.trace("Child {} not found in node {}", child, builder);
581 return Optional.absent();
585 * Find augment target node and perform augmentation.
588 * @param firstNodeParent
589 * parent of first node in path
591 * path to augment target
592 * @return true if augmentation process succeed, false otherwise
594 public static boolean processAugmentation(final AugmentationSchemaBuilder augment,
595 final ModuleBuilder firstNodeParent) {
596 Optional<SchemaNodeBuilder> potentialTargetNode = findSchemaNodeInModule(augment.getTargetNodeSchemaPath(),
598 if (!potentialTargetNode.isPresent()) {
601 SchemaNodeBuilder targetNode = potentialTargetNode.get();
602 fillAugmentTarget(augment, targetNode);
603 Preconditions.checkState(targetNode instanceof AugmentationTargetBuilder,
604 "Node refered by augmentation must be valid augmentation target");
605 ((AugmentationTargetBuilder) targetNode).addAugmentation(augment);
606 augment.setResolved(true);
610 public static IdentitySchemaNodeBuilder findBaseIdentity(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
611 final ModuleBuilder module, final String baseString, final int line) {
613 // FIXME: optimize indexOf() away?
614 if (baseString.indexOf(':') != -1) {
615 final Iterator<String> it = COLON_SPLITTER.split(baseString).iterator();
616 final String prefix = it.next();
617 final String name = it.next();
620 throw new YangParseException(module.getName(), line, "Failed to parse identityref base: " + baseString);
623 ModuleBuilder dependentModule = getModuleByPrefix(module, prefix);
624 if (dependentModule == null) {
628 return findIdentity(dependentModule.getAddedIdentities(), name);
630 return findIdentity(module.getAddedIdentities(), baseString);
634 public static IdentitySchemaNodeBuilder findIdentity(final Set<IdentitySchemaNodeBuilder> identities,
636 for (IdentitySchemaNodeBuilder identity : identities) {
637 if (identity.getQName().getLocalName().equals(name)) {
645 * Get module in which this node is defined.
648 * @return builder of module where this node is defined
650 public static ModuleBuilder getParentModule(final Builder node) {
651 if (node instanceof ModuleBuilder) {
652 return (ModuleBuilder) node;
654 Builder parent = node.getParent();
655 while (!(parent instanceof ModuleBuilder)) {
656 parent = parent.getParent();
658 ModuleBuilder parentModule = (ModuleBuilder) parent;
659 if (parentModule.isSubmodule()) {
660 parentModule = parentModule.getParent();
665 public static Set<DataSchemaNodeBuilder> wrapChildNodes(final String moduleName, final int line,
666 final Collection<DataSchemaNode> nodes, final SchemaPath parentPath, final QName parentQName) {
667 Set<DataSchemaNodeBuilder> result = new LinkedHashSet<>(nodes.size());
669 for (DataSchemaNode node : nodes) {
670 QName qname = QName.create(parentQName, node.getQName().getLocalName());
671 DataSchemaNodeBuilder wrapped = wrapChildNode(moduleName, line, node, parentPath, qname);
677 public static DataSchemaNodeBuilder wrapChildNode(final String moduleName, final int line,
678 final DataSchemaNode node, final SchemaPath parentPath, final QName qname) {
680 final SchemaPath schemaPath = parentPath.createChild(qname);
682 if (node instanceof AnyXmlSchemaNode) {
683 return new AnyXmlBuilder(moduleName, line, qname, schemaPath, ((AnyXmlSchemaNode) node));
684 } else if (node instanceof ChoiceNode) {
685 return new ChoiceBuilder(moduleName, line, qname, schemaPath, ((ChoiceNode) node));
686 } else if (node instanceof ContainerSchemaNode) {
687 return new ContainerSchemaNodeBuilder(moduleName, line, qname, schemaPath, ((ContainerSchemaNode) node));
688 } else if (node instanceof LeafSchemaNode) {
689 return new LeafSchemaNodeBuilder(moduleName, line, qname, schemaPath, ((LeafSchemaNode) node));
690 } else if (node instanceof LeafListSchemaNode) {
691 return new LeafListSchemaNodeBuilder(moduleName, line, qname, schemaPath, ((LeafListSchemaNode) node));
692 } else if (node instanceof ListSchemaNode) {
693 return new ListSchemaNodeBuilder(moduleName, line, qname, schemaPath, ((ListSchemaNode) node));
694 } else if (node instanceof ChoiceCaseNode) {
695 return new ChoiceCaseBuilder(moduleName, line, qname, schemaPath, ((ChoiceCaseNode) node));
697 throw new YangParseException(moduleName, line, "Failed to copy node: Unknown type of DataSchemaNode: "
702 public static Set<GroupingBuilder> wrapGroupings(final String moduleName, final int line,
703 final Set<GroupingDefinition> nodes, final SchemaPath parentPath, final QName parentQName) {
704 Set<GroupingBuilder> result = new HashSet<>();
705 for (GroupingDefinition node : nodes) {
706 QName qname = QName.create(parentQName, node.getQName().getLocalName());
707 SchemaPath schemaPath = parentPath.createChild(qname);
708 result.add(new GroupingBuilderImpl(moduleName, line, qname, schemaPath, node));
713 public static Set<TypeDefinitionBuilder> wrapTypedefs(final String moduleName, final int line,
714 final DataNodeContainer dataNode, final SchemaPath parentPath, final QName parentQName) {
715 Set<TypeDefinition<?>> nodes = dataNode.getTypeDefinitions();
716 Set<TypeDefinitionBuilder> result = new HashSet<>();
717 for (TypeDefinition<?> node : nodes) {
718 QName qname = QName.create(parentQName, node.getQName().getLocalName());
719 SchemaPath schemaPath = parentPath.createChild(qname);
720 result.add(new TypeDefinitionBuilderImpl(moduleName, line, qname, schemaPath, ((ExtendedType) node)));
725 public static List<UnknownSchemaNodeBuilderImpl> wrapUnknownNodes(final String moduleName, final int line,
726 final List<UnknownSchemaNode> nodes, final SchemaPath parentPath, final QName parentQName) {
727 List<UnknownSchemaNodeBuilderImpl> result = new ArrayList<>();
728 for (UnknownSchemaNode node : nodes) {
729 QName qname = QName.create(parentQName, node.getQName().getLocalName());
730 SchemaPath schemaPath = parentPath.createChild(qname);
731 result.add(new UnknownSchemaNodeBuilderImpl(moduleName, line, qname, schemaPath, node));
736 private static final class ByteSourceImpl extends ByteSource {
737 private final String toString;
738 private final ByteArrayOutputStream output = new ByteArrayOutputStream();
740 private ByteSourceImpl(final InputStream input) throws IOException {
741 toString = input.toString();
742 IOUtils.copy(input, output);
746 public InputStream openStream() throws IOException {
747 return new NamedByteArrayInputStream(output.toByteArray(), toString);
751 public static ModuleBuilder getModuleByPrefix(final ModuleBuilder module, final String prefix) {
752 if (prefix == null || prefix.isEmpty() || prefix.equals(module.getPrefix())) {
755 return module.getImportedModule(prefix);