Merge "BUG-981: remove deprecated elements"
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / util / ParserUtils.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.yangtools.yang.parser.util;
9
10 import java.io.File;
11 import java.io.FileNotFoundException;
12 import java.io.IOException;
13 import java.io.InputStream;
14 import java.net.URI;
15 import java.util.ArrayList;
16 import java.util.Arrays;
17 import java.util.Collection;
18 import java.util.Date;
19 import java.util.HashSet;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Set;
24 import java.util.TreeMap;
25
26 import org.apache.commons.io.IOUtils;
27 import org.opendaylight.yangtools.yang.common.QName;
28 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
29 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
30 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
31 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
32 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
33 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
34 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
35 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
36 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
37 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
38 import org.opendaylight.yangtools.yang.model.api.Module;
39 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
40 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
41 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
42 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
43 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
44 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
45 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
46 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationTargetBuilder;
47 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
48 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
49 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
50 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
51 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingMember;
52 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
53 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
54 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
55 import org.opendaylight.yangtools.yang.parser.builder.impl.AnyXmlBuilder;
56 import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceBuilder;
57 import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceCaseBuilder;
58 import org.opendaylight.yangtools.yang.parser.builder.impl.ContainerSchemaNodeBuilder;
59 import org.opendaylight.yangtools.yang.parser.builder.impl.GroupingBuilderImpl;
60 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentitySchemaNodeBuilder;
61 import org.opendaylight.yangtools.yang.parser.builder.impl.LeafListSchemaNodeBuilder;
62 import org.opendaylight.yangtools.yang.parser.builder.impl.LeafSchemaNodeBuilder;
63 import org.opendaylight.yangtools.yang.parser.builder.impl.ListSchemaNodeBuilder;
64 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
65 import org.opendaylight.yangtools.yang.parser.builder.impl.NotificationBuilder;
66 import org.opendaylight.yangtools.yang.parser.builder.impl.RpcDefinitionBuilder;
67 import org.opendaylight.yangtools.yang.parser.builder.impl.TypeDefinitionBuilderImpl;
68 import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
69 import org.slf4j.Logger;
70 import org.slf4j.LoggerFactory;
71
72 import com.google.common.base.Function;
73 import com.google.common.base.Preconditions;
74 import com.google.common.base.Splitter;
75 import com.google.common.collect.Collections2;
76 import com.google.common.io.ByteSource;
77
78 public final class ParserUtils {
79
80     private static final Logger LOG = LoggerFactory.getLogger(ParserUtils.class);
81     private static final Splitter SLASH_SPLITTER = Splitter.on('/');
82     private static final Splitter COLON_SPLITTER = Splitter.on(':');
83
84     private ParserUtils() {
85     }
86
87     public static Collection<ByteSource> streamsToByteSources(final Collection<InputStream> streams) {
88         return Collections2.transform(streams, new Function<InputStream, ByteSource>() {
89             @Override
90             public ByteSource apply(final InputStream input) {
91                 return new ByteSource() {
92                     @Override
93                     public InputStream openStream() throws IOException {
94                         return NamedByteArrayInputStream.create(input);
95                     }
96                 };
97             }
98         });
99     }
100
101     public static ByteSource fileToByteSource(final File file) {
102         return new ByteSource() {
103             @Override
104             public InputStream openStream() throws IOException {
105                 return new NamedFileInputStream(file, file.getAbsolutePath());
106             }
107         };
108     }
109
110     public static Collection<ByteSource> filesToByteSources(final Collection<File> streams) throws FileNotFoundException {
111         return Collections2.transform(streams, new Function<File, ByteSource>() {
112             @Override
113             public ByteSource apply(final File input) {
114                 return new ByteSource() {
115                     @Override
116                     public InputStream openStream() throws IOException {
117                         return new NamedFileInputStream(input, input.getAbsolutePath());
118                     }
119                 };
120             }
121         });
122     }
123
124     /**
125      * Set string representation of source to ModuleBuilder.
126      *
127      * @param sourceToBuilder
128      *            source to module mapping
129      */
130     public static void setSourceToBuilder(final Map<ByteSource, ModuleBuilder> sourceToBuilder) throws IOException {
131         for (Map.Entry<ByteSource, ModuleBuilder> entry : sourceToBuilder.entrySet()) {
132             ModuleBuilder builder = entry.getValue();
133             ByteSource source = entry.getKey();
134
135             String content = null;
136             InputStream stream = null;
137             try {
138                 stream = source.openStream();
139                 content = IOUtils.toString(stream);
140             } finally {
141                 if (stream != null) {
142                     try {
143                         stream.close();
144                     } catch (IOException e) {
145                         LOG.warn("Failed to close stream {}", stream);
146                     }
147                 }
148             }
149             builder.setSource(content);
150         }
151     }
152
153     /**
154      * Create new SchemaPath from given path and qname.
155      *
156      * @param schemaPath
157      *            base path
158      * @param qname
159      *            one or more qnames added to base path
160      * @return new SchemaPath from given path and qname
161      *
162      * @deprecated Use {@link SchemaPath#createChild(QName...)} instead.
163      */
164     @Deprecated
165     public static SchemaPath createSchemaPath(final SchemaPath schemaPath, final QName... qname) {
166         List<QName> path = new ArrayList<>(schemaPath.getPath());
167         path.addAll(Arrays.asList(qname));
168         return SchemaPath.create(path, schemaPath.isAbsolute());
169     }
170
171     /**
172      * Get module import referenced by given prefix.
173      *
174      * @param builder
175      *            module to search
176      * @param prefix
177      *            prefix associated with import
178      * @return ModuleImport based on given prefix
179      */
180     public static ModuleImport getModuleImport(final ModuleBuilder builder, final String prefix) {
181         for (ModuleImport mi : builder.getModuleImports()) {
182             if (mi.getPrefix().equals(prefix)) {
183                 return mi;
184
185             }
186         }
187         return null;
188     }
189
190     /**
191      * Find dependent module based on given prefix
192      *
193      * @param modules
194      *            all available modules
195      * @param module
196      *            current module
197      * @param prefix
198      *            target module prefix
199      * @param line
200      *            current line in yang model
201      * @return module builder if found, null otherwise
202      */
203     public static ModuleBuilder findModuleFromBuilders(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
204             final ModuleBuilder module, final String prefix, final int line) {
205         ModuleBuilder dependentModule = null;
206         Date dependentModuleRevision = null;
207
208         if (prefix == null) {
209             dependentModule = module;
210         } else if (prefix.equals(module.getPrefix())) {
211             dependentModule = module;
212         } else {
213             ModuleImport dependentModuleImport = getModuleImport(module, prefix);
214             if (dependentModuleImport == null) {
215                 throw new YangParseException(module.getName(), line, "No import found with prefix '" + prefix + "'.");
216             }
217             String dependentModuleName = dependentModuleImport.getModuleName();
218             dependentModuleRevision = dependentModuleImport.getRevision();
219
220             TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules.get(dependentModuleName);
221             if (moduleBuildersByRevision == null) {
222                 return null;
223             }
224             if (dependentModuleRevision == null) {
225                 dependentModule = moduleBuildersByRevision.lastEntry().getValue();
226             } else {
227                 dependentModule = moduleBuildersByRevision.get(dependentModuleRevision);
228             }
229         }
230         return dependentModule;
231     }
232
233     /**
234      * Find module from context based on prefix.
235      *
236      * @param context
237      *            schema context
238      * @param currentModule
239      *            current module
240      * @param prefix
241      *            current prefix used to reference dependent module
242      * @param line
243      *            current line in yang model
244      * @return module based on given prefix if found in context, null otherwise
245      */
246     public static Module findModuleFromContext(final SchemaContext context, final ModuleBuilder currentModule, final String prefix,
247             final int line) {
248         if (context == null) {
249             throw new YangParseException(currentModule.getName(), line, "Cannot find module with prefix '" + prefix
250                     + "'.");
251         }
252         TreeMap<Date, Module> modulesByRevision = new TreeMap<>();
253
254         ModuleImport dependentModuleImport = ParserUtils.getModuleImport(currentModule, prefix);
255         if (dependentModuleImport == null) {
256             throw new YangParseException(currentModule.getName(), line, "No import found with prefix '" + prefix + "'.");
257         }
258         String dependentModuleName = dependentModuleImport.getModuleName();
259         Date dependentModuleRevision = dependentModuleImport.getRevision();
260
261         for (Module contextModule : context.getModules()) {
262             if (contextModule.getName().equals(dependentModuleName)) {
263                 Date revision = contextModule.getRevision();
264                 if (revision == null) {
265                     revision = new Date(0L);
266                 }
267                 modulesByRevision.put(revision, contextModule);
268             }
269         }
270
271         Module result = null;
272         if (dependentModuleRevision == null) {
273             result = modulesByRevision.get(modulesByRevision.firstKey());
274         } else {
275             result = modulesByRevision.get(dependentModuleRevision);
276         }
277         return result;
278     }
279
280     /**
281      * Parse XPath string.
282      *
283      * @param xpathString
284      *            XPath as String
285      * @return SchemaPath from given String
286      */
287     public static SchemaPath parseXPathString(final String xpathString) {
288         final boolean absolute = xpathString.indexOf('/') == 0;
289
290         final List<QName> path = new ArrayList<QName>();
291         for (String pathElement : SLASH_SPLITTER.split(xpathString)) {
292             if (pathElement.length() > 0) {
293                 final Iterator<String> it = COLON_SPLITTER.split(pathElement).iterator();
294                 final String s = it.next();
295
296                 final QName name;
297                 if (it.hasNext()) {
298                     name = new QName(null, null, s, it.next());
299                 } else {
300                     name = new QName(null, null, null, s);
301                 }
302                 path.add(name);
303             }
304         }
305         return SchemaPath.create(path, absolute);
306     }
307
308     /**
309      * Add all augment's child nodes to given target.
310      *
311      * @param augment
312      *            builder of augment statement
313      * @param target
314      *            augmentation target node
315      */
316     public static void fillAugmentTarget(final AugmentationSchemaBuilder augment, final Builder target) {
317         if (target instanceof DataNodeContainerBuilder) {
318             fillAugmentTarget(augment, (DataNodeContainerBuilder) target);
319         } else if (target instanceof ChoiceBuilder) {
320             fillAugmentTarget(augment, (ChoiceBuilder) target);
321         } else {
322             throw new YangParseException(
323                     augment.getModuleName(),
324                     augment.getLine(),
325                     "Error in augment parsing: The target node MUST be either a container, list, choice, case, input, output, or notification node.");
326         }
327     }
328
329     /**
330      * Add all augment's child nodes to given target.
331      *
332      * @param augment
333      *            builder of augment statement
334      * @param target
335      *            augmentation target node
336      */
337     private static void fillAugmentTarget(final AugmentationSchemaBuilder augment, final DataNodeContainerBuilder target) {
338         for (DataSchemaNodeBuilder child : augment.getChildNodeBuilders()) {
339             DataSchemaNodeBuilder childCopy = CopyUtils.copy(child, target, false);
340             if (augment.getParent() instanceof UsesNodeBuilder) {
341                 setNodeAddedByUses(childCopy);
342             }
343             setNodeAugmenting(childCopy);
344             try {
345                 target.addChildNode(childCopy);
346             } catch (YangParseException e) {
347
348                 // more descriptive message
349                 throw new YangParseException(augment.getModuleName(), augment.getLine(),
350                         "Failed to perform augmentation: " + e.getMessage());
351             }
352         }
353     }
354
355     /**
356      * Add all augment's child nodes to given target.
357      *
358      * @param augment
359      *            builder of augment statement
360      * @param target
361      *            augmentation target choice node
362      */
363     private static void fillAugmentTarget(final AugmentationSchemaBuilder augment, final ChoiceBuilder target) {
364         for (DataSchemaNodeBuilder builder : augment.getChildNodeBuilders()) {
365             DataSchemaNodeBuilder childCopy = CopyUtils.copy(builder, target, false);
366             if (augment.getParent() instanceof UsesNodeBuilder) {
367                 setNodeAddedByUses(childCopy);
368             }
369             setNodeAugmenting(childCopy);
370             target.addCase(childCopy);
371         }
372         for (UsesNodeBuilder usesNode : augment.getUsesNodeBuilders()) {
373             if (usesNode != null) {
374                 throw new YangParseException(augment.getModuleName(), augment.getLine(),
375                         "Error in augment parsing: cannot augment choice with nodes from grouping");
376             }
377         }
378     }
379
380     /**
381      * Set augmenting flag to true for node and all its child nodes.
382      *
383      * @param node
384      */
385     private static void setNodeAugmenting(final DataSchemaNodeBuilder node) {
386         node.setAugmenting(true);
387         if (node instanceof DataNodeContainerBuilder) {
388             DataNodeContainerBuilder dataNodeChild = (DataNodeContainerBuilder) node;
389             for (DataSchemaNodeBuilder inner : dataNodeChild.getChildNodeBuilders()) {
390                 setNodeAugmenting(inner);
391             }
392         } else if (node instanceof ChoiceBuilder) {
393             ChoiceBuilder choiceChild = (ChoiceBuilder) node;
394             for (ChoiceCaseBuilder inner : choiceChild.getCases()) {
395                 setNodeAugmenting(inner);
396             }
397         }
398     }
399
400     /**
401      * Set addedByUses flag to true for node and all its child nodes.
402      *
403      * @param node
404      */
405     public static void setNodeAddedByUses(final GroupingMember node) {
406         node.setAddedByUses(true);
407         if (node instanceof DataNodeContainerBuilder) {
408             DataNodeContainerBuilder dataNodeChild = (DataNodeContainerBuilder) node;
409             for (DataSchemaNodeBuilder inner : dataNodeChild.getChildNodeBuilders()) {
410                 setNodeAddedByUses(inner);
411             }
412         } else if (node instanceof ChoiceBuilder) {
413             ChoiceBuilder choiceChild = (ChoiceBuilder) node;
414             for (ChoiceCaseBuilder inner : choiceChild.getCases()) {
415                 setNodeAddedByUses(inner);
416             }
417         }
418     }
419
420     /**
421      * Set config flag to new value.
422      *
423      * @param node
424      *            node to update
425      * @param config
426      *            new config value
427      */
428     public static void setNodeConfig(final DataSchemaNodeBuilder node, final Boolean config) {
429         if (node instanceof ContainerSchemaNodeBuilder || node instanceof LeafSchemaNodeBuilder
430                 || node instanceof LeafListSchemaNodeBuilder || node instanceof ListSchemaNodeBuilder
431                 || node instanceof ChoiceBuilder || node instanceof AnyXmlBuilder) {
432             node.setConfiguration(config);
433         }
434         if (node instanceof DataNodeContainerBuilder) {
435             DataNodeContainerBuilder dataNodeChild = (DataNodeContainerBuilder) node;
436             for (DataSchemaNodeBuilder inner : dataNodeChild.getChildNodeBuilders()) {
437                 setNodeConfig(inner, config);
438             }
439         } else if (node instanceof ChoiceBuilder) {
440             ChoiceBuilder choiceChild = (ChoiceBuilder) node;
441             for (ChoiceCaseBuilder inner : choiceChild.getCases()) {
442                 setNodeConfig(inner, config);
443             }
444         }
445     }
446
447     public static DataSchemaNodeBuilder findSchemaNode(final List<QName> path, final SchemaNodeBuilder parentNode) {
448         DataSchemaNodeBuilder node = null;
449         SchemaNodeBuilder parent = parentNode;
450         int i = 0;
451         while (i < path.size()) {
452             String name = path.get(i).getLocalName();
453             if (parent instanceof DataNodeContainerBuilder) {
454                 node = ((DataNodeContainerBuilder) parent).getDataChildByName(name);
455             } else if (parent instanceof ChoiceBuilder) {
456                 node = ((ChoiceBuilder) parent).getCaseNodeByName(name);
457             } else if (parent instanceof RpcDefinitionBuilder) {
458                 if ("input".equals(name)) {
459                     node = ((RpcDefinitionBuilder) parent).getInput();
460                 } else if ("output".equals(name)) {
461                     node = ((RpcDefinitionBuilder) parent).getOutput();
462                 } else {
463                     return null;
464                 }
465             } else {
466                 return null;
467             }
468
469             if (i < path.size() - 1) {
470                 parent = node;
471             }
472             i = i + 1;
473         }
474
475         return node;
476     }
477
478     public static SchemaNodeBuilder findSchemaNodeInModule(final List<QName> pathToNode, final ModuleBuilder module) {
479         List<QName> path = new ArrayList<>(pathToNode);
480         QName first = path.remove(0);
481
482         SchemaNodeBuilder node = module.getDataChildByName(first.getLocalName());
483         if (node == null) {
484             Set<NotificationBuilder> notifications = module.getAddedNotifications();
485             for (NotificationBuilder notification : notifications) {
486                 if (notification.getQName().getLocalName().equals(first.getLocalName())) {
487                     node = notification;
488                 }
489             }
490         }
491         if (node == null) {
492             Set<RpcDefinitionBuilder> rpcs = module.getAddedRpcs();
493             for (RpcDefinitionBuilder rpc : rpcs) {
494                 if (rpc.getQName().getLocalName().equals(first.getLocalName())) {
495                     node = rpc;
496                 }
497             }
498         }
499         if (node == null) {
500             return null;
501         }
502
503         if (!path.isEmpty()) {
504             node = findSchemaNode(path, node);
505         }
506
507         return node;
508     }
509
510     /**
511      * Find augment target node and perform augmentation.
512      *
513      * @param augment
514      * @param firstNodeParent
515      *            parent of first node in path
516      * @param path
517      *            path to augment target
518      * @return true if augmentation process succeed, false otherwise
519      */
520     public static boolean processAugmentation(final AugmentationSchemaBuilder augment, final ModuleBuilder firstNodeParent) {
521         List<QName> path = augment.getTargetPath().getPath();
522         Builder targetNode = findSchemaNodeInModule(path, firstNodeParent);
523         if (targetNode == null) {
524             return false;
525         }
526
527         fillAugmentTarget(augment, targetNode);
528         ((AugmentationTargetBuilder) targetNode).addAugmentation(augment);
529         augment.setResolved(true);
530         return true;
531     }
532
533     public static IdentitySchemaNodeBuilder findBaseIdentity(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
534             final ModuleBuilder module, final String baseString, final int line) {
535
536         // FIXME: optimize indexOf() away?
537         if (baseString.indexOf(':') != -1) {
538             final Iterator<String> it = COLON_SPLITTER.split(baseString).iterator();
539             final String prefix = it.next();
540             final String name = it.next();
541
542             if (it.hasNext()) {
543                 throw new YangParseException(module.getName(), line, "Failed to parse identityref base: " + baseString);
544             }
545
546             ModuleBuilder dependentModule = findModuleFromBuilders(modules, module, prefix, line);
547             if (dependentModule == null) {
548                 return null;
549             }
550
551             return findIdentity(dependentModule.getAddedIdentities(), name);
552         } else {
553             return findIdentity(module.getAddedIdentities(), baseString);
554         }
555     }
556
557     public static IdentitySchemaNodeBuilder findIdentity(final Set<IdentitySchemaNodeBuilder> identities, final String name) {
558         for (IdentitySchemaNodeBuilder identity : identities) {
559             if (identity.getQName().getLocalName().equals(name)) {
560                 return identity;
561             }
562         }
563         return null;
564     }
565
566     /**
567      * Get module in which this node is defined.
568      *
569      * @param node
570      * @return builder of module where this node is defined
571      */
572     public static ModuleBuilder getParentModule(final Builder node) {
573         if (node instanceof ModuleBuilder) {
574             return (ModuleBuilder) node;
575         }
576         Builder parent = node.getParent();
577         while (!(parent instanceof ModuleBuilder)) {
578             parent = parent.getParent();
579         }
580         Preconditions.checkState(parent instanceof ModuleBuilder);
581         ModuleBuilder parentModule = (ModuleBuilder) parent;
582         if (parentModule.isSubmodule()) {
583             parentModule = parentModule.getParent();
584         }
585         return parentModule;
586     }
587
588     public static Set<DataSchemaNodeBuilder> wrapChildNodes(final String moduleName, final int line, final Set<DataSchemaNode> nodes,
589             final SchemaPath parentPath, final URI ns, final Date rev, final String pref) {
590         Set<DataSchemaNodeBuilder> result = new HashSet<>();
591
592         for (DataSchemaNode node : nodes) {
593             QName qname = new QName(ns, rev, pref, node.getQName().getLocalName());
594             DataSchemaNodeBuilder wrapped = wrapChildNode(moduleName, line, node, parentPath, qname);
595             result.add(wrapped);
596         }
597         return result;
598     }
599
600     public static DataSchemaNodeBuilder wrapChildNode(final String moduleName, final int line, final DataSchemaNode node,
601             final SchemaPath parentPath, final QName qname) {
602
603         final SchemaPath schemaPath = parentPath.createChild(qname);
604
605         if (node instanceof AnyXmlSchemaNode) {
606             return new AnyXmlBuilder(moduleName, line, qname, schemaPath, ((AnyXmlSchemaNode) node));
607         } else if (node instanceof ChoiceNode) {
608             return new ChoiceBuilder(moduleName, line, qname, schemaPath, ((ChoiceNode) node));
609         } else if (node instanceof ContainerSchemaNode) {
610             return new ContainerSchemaNodeBuilder(moduleName, line, qname, schemaPath, ((ContainerSchemaNode) node));
611         } else if (node instanceof LeafSchemaNode) {
612             return new LeafSchemaNodeBuilder(moduleName, line, qname, schemaPath, ((LeafSchemaNode) node));
613         } else if (node instanceof LeafListSchemaNode) {
614             return new LeafListSchemaNodeBuilder(moduleName, line, qname, schemaPath, ((LeafListSchemaNode) node));
615         } else if (node instanceof ListSchemaNode) {
616             return new ListSchemaNodeBuilder(moduleName, line, qname, schemaPath, ((ListSchemaNode) node));
617         } else if (node instanceof ChoiceCaseNode) {
618             return new ChoiceCaseBuilder(moduleName, line, qname, schemaPath, ((ChoiceCaseNode) node));
619         } else {
620             throw new YangParseException(moduleName, line, "Failed to copy node: Unknown type of DataSchemaNode: "
621                     + node);
622         }
623     }
624
625     public static Set<GroupingBuilder> wrapGroupings(final String moduleName, final int line, final Set<GroupingDefinition> nodes,
626             final SchemaPath parentPath, final URI ns, final Date rev, final String pref) {
627         Set<GroupingBuilder> result = new HashSet<>();
628         for (GroupingDefinition node : nodes) {
629             QName qname = new QName(ns, rev, pref, node.getQName().getLocalName());
630             SchemaPath schemaPath = parentPath.createChild(qname);
631             result.add(new GroupingBuilderImpl(moduleName, line, qname, schemaPath, node));
632         }
633         return result;
634     }
635
636     public static Set<TypeDefinitionBuilder> wrapTypedefs(final String moduleName, final int line, final DataNodeContainer dataNode,
637             final SchemaPath parentPath, final URI ns, final Date rev, final String pref) {
638         Set<TypeDefinition<?>> nodes = dataNode.getTypeDefinitions();
639         Set<TypeDefinitionBuilder> result = new HashSet<>();
640         for (TypeDefinition<?> node : nodes) {
641             QName qname = new QName(ns, rev, pref, node.getQName().getLocalName());
642             List<QName> path = new ArrayList<>(parentPath.getPath());
643             path.add(qname);
644             SchemaPath schemaPath = SchemaPath.create(path, parentPath.isAbsolute());
645             result.add(new TypeDefinitionBuilderImpl(moduleName, line, qname, schemaPath, ((ExtendedType) node)));
646         }
647         return result;
648     }
649
650     public static List<UnknownSchemaNodeBuilder> wrapUnknownNodes(final String moduleName, final int line,
651             final List<UnknownSchemaNode> nodes, final SchemaPath parentPath, final URI ns, final Date rev, final String pref) {
652         List<UnknownSchemaNodeBuilder> result = new ArrayList<>();
653         for (UnknownSchemaNode node : nodes) {
654             QName qname = new QName(ns, rev, pref, node.getQName().getLocalName());
655             List<QName> path = new ArrayList<>(parentPath.getPath());
656             path.add(qname);
657             SchemaPath schemaPath = SchemaPath.create(path, parentPath.isAbsolute());
658             result.add(new UnknownSchemaNodeBuilder(moduleName, line, qname, schemaPath, node));
659         }
660         return result;
661     }
662
663 }