Reduce the use of AttrBuilders
[netconf.git] / restconf / restconf-nb-rfc8040 / src / main / java / org / opendaylight / restconf / nb / rfc8040 / utils / mapping / RestconfMappingNodeUtil.java
1 /*
2  * Copyright (c) 2016 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.restconf.nb.rfc8040.utils.mapping;
9
10 import java.net.URI;
11 import java.time.Instant;
12 import java.time.OffsetDateTime;
13 import java.time.ZoneId;
14 import java.time.format.DateTimeFormatter;
15 import java.util.Collection;
16 import java.util.Optional;
17 import java.util.Set;
18 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
19 import org.opendaylight.restconf.nb.rfc8040.Rfc8040.IetfYangLibrary;
20 import org.opendaylight.restconf.nb.rfc8040.Rfc8040.MonitoringModule;
21 import org.opendaylight.restconf.nb.rfc8040.Rfc8040.MonitoringModule.QueryParams;
22 import org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserIdentifier;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev160621.module.list.Module.ConformanceType;
24 import org.opendaylight.yangtools.yang.common.QName;
25 import org.opendaylight.yangtools.yang.common.Revision;
26 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
27 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
28 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
29 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
30 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
32 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
33 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
34 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
35 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
36 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
37 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
38 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
39 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
40 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
41 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
42 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
43 import org.opendaylight.yangtools.yang.model.api.Deviation;
44 import org.opendaylight.yangtools.yang.model.api.FeatureDefinition;
45 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
46 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
47 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
48 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
49 import org.opendaylight.yangtools.yang.model.api.Module;
50 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
51 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
52 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
53
54 /**
55  * Util class for mapping nodes.
56  *
57  */
58 public final class RestconfMappingNodeUtil {
59
60     private RestconfMappingNodeUtil() {
61         throw new UnsupportedOperationException("Util class");
62     }
63
64     /**
65      * Map data from modules to {@link NormalizedNode}.
66      *
67      * @param modules
68      *             modules for mapping
69      * @param ietfYangLibraryModule
70      *             ietf-yang-library module
71      * @param context
72      *             schema context
73      * @param moduleSetId
74      *             module-set-id of actual set
75      * @return mapped data as {@link NormalizedNode}
76      */
77     public static NormalizedNode<NodeIdentifier, Collection<DataContainerChild<? extends PathArgument, ?>>>
78             mapModulesByIetfYangLibraryYang(final Set<Module> modules, final Module ietfYangLibraryModule,
79                     final SchemaContext context, final String moduleSetId) {
80         final DataSchemaNode modulesStateSch =
81                 ietfYangLibraryModule.getDataChildByName(IetfYangLibrary.MODUELS_STATE_CONT_QNAME);
82         final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> modulesStateBuilder =
83                 Builders.containerBuilder((ContainerSchemaNode) modulesStateSch);
84
85         final DataSchemaNode moduleSetIdSch =
86                 ((ContainerSchemaNode) modulesStateSch).getDataChildByName(IetfYangLibrary.MODULE_SET_ID_LEAF_QNAME);
87         modulesStateBuilder
88                 .withChild(Builders.leafBuilder((LeafSchemaNode) moduleSetIdSch).withValue(moduleSetId).build());
89
90         final DataSchemaNode moduleSch = findNodeInGroupings(IetfYangLibrary.MODULE_QNAME_LIST, ietfYangLibraryModule);
91         final CollectionNodeBuilder<MapEntryNode, OrderedMapNode> mapBuilder =
92                 Builders.orderedMapBuilder((ListSchemaNode) moduleSch);
93         for (final Module module : context.getModules()) {
94             fillMapByModules(mapBuilder, moduleSch, false, module, ietfYangLibraryModule, context);
95         }
96         return modulesStateBuilder.withChild(mapBuilder.build()).build();
97     }
98
99     /**
100      * Map data by the specific module or submodule.
101      *
102      * @param mapBuilder
103      *             ordered list builder for children
104      * @param moduleSch
105      *             schema of list for entryMapBuilder
106      * @param isSubmodule
107      *             true if module is specified as submodule, false otherwise
108      * @param module
109      *             specific module or submodule
110      * @param ietfYangLibraryModule
111      *             ietf-yang-library module
112      * @param context
113      *             schema context
114      */
115     private static void fillMapByModules(final CollectionNodeBuilder<MapEntryNode, OrderedMapNode> mapBuilder,
116             final DataSchemaNode moduleSch, final boolean isSubmodule, final Module module,
117             final Module ietfYangLibraryModule, final SchemaContext context) {
118         final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder =
119                 Builders.mapEntryBuilder((ListSchemaNode) moduleSch);
120         addCommonLeafs(module, mapEntryBuilder, ietfYangLibraryModule);
121         addChildOfModuleBySpecificModuleInternal(
122                 IetfYangLibrary.SPECIFIC_MODULE_SCHEMA_LEAF_QNAME, mapEntryBuilder, IetfYangLibrary.BASE_URI_OF_SCHEMA
123                         + module.getName() + "/"
124                         + module.getQNameModule().getRevision().map(Revision::toString).orElse(null),
125                 ietfYangLibraryModule);
126         if (!isSubmodule) {
127             addChildOfModuleBySpecificModuleOfListChild(IetfYangLibrary.SPECIFIC_MODULE_NAMESPACE_LEAF_QNAME,
128                     mapEntryBuilder, module.getNamespace().toString(), ietfYangLibraryModule);
129
130             // features - not mandatory
131             if (module.getFeatures() != null && !module.getFeatures().isEmpty()) {
132                 addFeatureLeafList(IetfYangLibrary.SPECIFIC_MODULE_FEATURE_LEAF_LIST_QNAME, mapEntryBuilder,
133                         module.getFeatures(), ietfYangLibraryModule);
134             }
135             // deviations - not mandatory
136             if (module.getDeviations() != null && !module.getDeviations().isEmpty()) {
137                 addDeviationList(module, mapEntryBuilder, ietfYangLibraryModule, context);
138                 addChildOfModuleBySpecificModuleOfListChild(IetfYangLibrary.SPECIFIC_MODULE_CONFORMANCE_LEAF_QNAME,
139                         mapEntryBuilder, ConformanceType.Implement.getName(), ietfYangLibraryModule);
140             } else {
141                 addChildOfModuleBySpecificModuleOfListChild(IetfYangLibrary.SPECIFIC_MODULE_CONFORMANCE_LEAF_QNAME,
142                         mapEntryBuilder, ConformanceType.Import.getName(), ietfYangLibraryModule);
143             }
144             // submodules - not mandatory
145             if (module.getSubmodules() != null && !module.getSubmodules().isEmpty()) {
146                 addSubmodules(module, mapEntryBuilder, ietfYangLibraryModule, context);
147             }
148         }
149         mapBuilder.withChild(mapEntryBuilder.build());
150     }
151
152     /**
153      * Mapping submodules of specific module.
154      *
155      * @param module
156      *             module with submodules
157      * @param mapEntryBuilder
158      *             mapEntryBuilder of parent for mapping children
159      * @param ietfYangLibraryModule
160      *             ietf-yang-library module
161      * @param context
162      *             schema context
163      */
164     private static void addSubmodules(final Module module,
165             final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder,
166             final Module ietfYangLibraryModule, final SchemaContext context) {
167         final DataSchemaNode listSubm = findSchemaInListOfModulesSchema(
168                 IetfYangLibrary.SPECIFIC_MODULE_SUBMODULE_LIST_QNAME, ietfYangLibraryModule);
169         final CollectionNodeBuilder<MapEntryNode, OrderedMapNode> mapBuilder =
170                 Builders.orderedMapBuilder((ListSchemaNode) listSubm);
171         for (final Module submodule : module.getSubmodules()) {
172             fillMapByModules(mapBuilder, listSubm, true, submodule, ietfYangLibraryModule, context);
173         }
174         mapEntryBuilder.withChild(mapBuilder.build());
175     }
176
177     /**
178      * Mapping deviations of specific module.
179      *
180      * @param module
181      *             module with deviations
182      * @param mapEntryBuilder
183      *             mapEntryBuilder of parent for mapping children
184      * @param ietfYangLibraryModule
185      *             ietf-yang-library module
186      * @param context
187      *             schema context
188      */
189     private static void addDeviationList(final Module module,
190             final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder,
191             final Module ietfYangLibraryModule, final SchemaContext context) {
192         final DataSchemaNode deviationsSchema = findSchemaInListOfModulesSchema(
193                 IetfYangLibrary.SPECIFIC_MODULE_DEVIATION_LIST_QNAME, ietfYangLibraryModule);
194         final CollectionNodeBuilder<MapEntryNode, MapNode> deviations =
195                 Builders.mapBuilder((ListSchemaNode) deviationsSchema);
196         for (final Deviation deviation : module.getDeviations()) {
197             final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> deviationEntryNode =
198                     Builders.mapEntryBuilder((ListSchemaNode) deviationsSchema);
199             final QName lastComponent = deviation.getTargetPath().getLastComponent();
200             addChildOfModuleBySpecificModule(IetfYangLibrary.SPECIFIC_MODULE_NAME_LEAF_QNAME, deviationEntryNode,
201                     context.findModule(lastComponent.getModule()).get().getName(),
202                     ietfYangLibraryModule);
203             addChildOfModuleBySpecificModule(IetfYangLibrary.SPECIFIC_MODULE_REVISION_LEAF_QNAME, deviationEntryNode,
204                     lastComponent.getRevision(), ietfYangLibraryModule);
205             deviations.withChild(deviationEntryNode.build());
206         }
207         mapEntryBuilder.withChild(deviations.build());
208     }
209
210     /**
211      * Mapping features of specific module.
212      *
213      * @param qnameOfFeaturesLeafList
214      *             qname of feature leaf-list in ietf-yang-library module
215      * @param mapEntryBuilder
216      *             mapEntryBuilder of parent for mapping children
217      * @param features
218      *             features of specific module
219      * @param ietfYangLibraryModule
220      *             ieat-yang-library module
221      */
222     private static void addFeatureLeafList(final QName qnameOfFeaturesLeafList,
223             final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder,
224             final Set<FeatureDefinition> features, final Module ietfYangLibraryModule) {
225         final DataSchemaNode schemaNode =
226                 findSchemaInListOfModulesSchema(qnameOfFeaturesLeafList, ietfYangLibraryModule);
227         final ListNodeBuilder<Object, LeafSetEntryNode<Object>> leafSetBuilder =
228                 Builders.leafSetBuilder((LeafListSchemaNode) schemaNode);
229         for (final FeatureDefinition feature : features) {
230             leafSetBuilder.withChild(Builders.leafSetEntryBuilder((LeafListSchemaNode) schemaNode)
231                     .withValue(feature.getQName().getLocalName()).build());
232         }
233         mapEntryBuilder.withChild(leafSetBuilder.build());
234     }
235
236     /**
237      * Mapping common leafs (grouping common-leafs in ietf-yang-library) of
238      * specific module.
239      *
240      * @param module
241      *             specific module for getting name and revision
242      * @param mapEntryBuilder
243      *             mapEntryBuilder of parent for mapping children
244      * @param ietfYangLibraryModule
245      *             ietf-yang-library module
246      */
247     private static void addCommonLeafs(final Module module,
248             final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder,
249             final Module ietfYangLibraryModule) {
250         addChildOfModuleBySpecificModuleInternal(IetfYangLibrary.SPECIFIC_MODULE_NAME_LEAF_QNAME, mapEntryBuilder,
251                 module.getName(), ietfYangLibraryModule);
252         addChildOfModuleBySpecificModuleInternal(IetfYangLibrary.SPECIFIC_MODULE_REVISION_LEAF_QNAME, mapEntryBuilder,
253                 module.getQNameModule().getRevision().map(Revision::toString).orElse(""), ietfYangLibraryModule);
254     }
255
256     /**
257      * Mapping data child of grouping module-list by ietf-yang-library.
258      *
259      * @param specificQName
260      *             qname of leaf in module-list grouping
261      * @param mapEntryBuilder
262      *             mapEntryBuilder of parent for mapping children
263      * @param value
264      *             value of leaf
265      * @param ietfYangLibraryModule
266      *             ietf-yang-library module
267      */
268     private static void addChildOfModuleBySpecificModuleOfListChild(final QName specificQName,
269             final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder,
270             final Object value, final Module ietfYangLibraryModule) {
271         final DataSchemaNode leafSch = findSchemaInListOfModulesSchema(specificQName, ietfYangLibraryModule);
272         mapEntryBuilder.withChild(Builders.leafBuilder((LeafSchemaNode) leafSch).withValue(value).build());
273     }
274
275     /**
276      * Find specific schema in gourping module-lsit.
277      *
278      * @param specificQName
279      *             qname of schema
280      * @param ietfYangLibraryModule
281      *             ietf-yang-library module
282      * @return schemaNode of specific child
283      */
284     private static DataSchemaNode findSchemaInListOfModulesSchema(final QName specificQName,
285             final Module ietfYangLibraryModule) {
286         for (final GroupingDefinition groupingDefinition : ietfYangLibraryModule.getGroupings()) {
287             if (groupingDefinition.getQName().equals(IetfYangLibrary.GROUPING_MODULE_LIST_QNAME)) {
288                 final DataSchemaNode dataChildByName =
289                         groupingDefinition.getDataChildByName(IetfYangLibrary.MODULE_QNAME_LIST);
290                 return ((ListSchemaNode) dataChildByName).getDataChildByName(specificQName);
291             }
292         }
293         throw new RestconfDocumentedException(specificQName.getLocalName() + " doesn't exist.");
294     }
295
296     /**
297      * Mapping data child of internal groupings in module-list grouping.
298      *
299      * @param specifiLeafQName
300      *             qnmae of leaf for mapping
301      * @param mapEntryBuilder
302      *             mapEntryBuilder of parent for mapping children
303      * @param value
304      *             value of leaf
305      * @param ietfYangLibraryModule
306      *             ietf-yang-library module
307      */
308     private static void addChildOfModuleBySpecificModuleInternal(final QName specifiLeafQName,
309             final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder,
310             final Object value, final Module ietfYangLibraryModule) {
311         final DataSchemaNode nameLeaf = findNodeInInternGroupings(specifiLeafQName, ietfYangLibraryModule);
312         mapEntryBuilder.withChild(Builders.leafBuilder((LeafSchemaNode) nameLeaf).withValue(value).build());
313     }
314
315     /**
316      * Find schema node of leaf by qname in internal groupings of module-list.
317      * grouping
318      *
319      * @param qnameOfSchema
320      *             qname of leaf
321      * @param ietfYangLibraryModule
322      *             ietf-yang-library module
323      * @return schema node of specific leaf
324      */
325     private static DataSchemaNode findNodeInInternGroupings(final QName qnameOfSchema,
326             final Module ietfYangLibraryModule) {
327         for (final GroupingDefinition groupingDefinition : ietfYangLibraryModule.getGroupings()) {
328             if (groupingDefinition.getQName().equals(IetfYangLibrary.GROUPING_MODULE_LIST_QNAME)) {
329                 for (final GroupingDefinition internalGrouping : groupingDefinition.getGroupings()) {
330                     if (internalGrouping.getDataChildByName(qnameOfSchema) != null) {
331                         return internalGrouping.getDataChildByName(qnameOfSchema);
332                     }
333                 }
334             }
335         }
336         throw new RestconfDocumentedException(qnameOfSchema.getLocalName() + " doesn't exist.");
337     }
338
339     /**
340      * Mapping childrens of list-module.
341      *
342      * @param specifiLeafQName
343      *             qname of leaf
344      * @param mapEntryBuilder
345      *             maptEntryBuilder of parent for mapping children
346      * @param value
347      *             valeu of leaf
348      * @param ietfYangLibraryModule
349      *             ietf-yang-library module
350      */
351     private static void addChildOfModuleBySpecificModule(final QName specifiLeafQName,
352             final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder,
353             final Object value, final Module ietfYangLibraryModule) {
354         final DataSchemaNode nameLeaf = findNodeInGroupings(specifiLeafQName, ietfYangLibraryModule);
355         mapEntryBuilder.withChild(Builders.leafBuilder((LeafSchemaNode) nameLeaf).withValue(value).build());
356     }
357
358     /**
359      * Find schema of specific leaf in list-module grouping.
360      *
361      * @param qnameOfSchema
362      *             qname of leaf
363      * @param ietfYangLibraryModule
364      *             ietf-yang-library module
365      * @return schemaNode of specific leaf
366      */
367     private static DataSchemaNode findNodeInGroupings(final QName qnameOfSchema, final Module ietfYangLibraryModule) {
368         for (final GroupingDefinition groupingDefinition : ietfYangLibraryModule.getGroupings()) {
369             if (groupingDefinition.getDataChildByName(qnameOfSchema) != null) {
370                 return groupingDefinition.getDataChildByName(qnameOfSchema);
371             }
372         }
373         throw new RestconfDocumentedException(qnameOfSchema.getLocalName() + " doesn't exist.");
374     }
375
376     /**
377      * Map capabilites by ietf-restconf-monitoring.
378      *
379      * @param monitoringModule
380      *             ietf-restconf-monitoring module
381      * @return mapped capabilites
382      */
383     public static NormalizedNode<NodeIdentifier, Collection<DataContainerChild<? extends PathArgument, ?>>>
384             mapCapabilites(final Module monitoringModule) {
385         final DataSchemaNode restconfState =
386                 monitoringModule.getDataChildByName(MonitoringModule.CONT_RESTCONF_STATE_QNAME);
387         final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> restStateContBuilder =
388                 Builders.containerBuilder((ContainerSchemaNode) restconfState);
389         final DataSchemaNode capabilitesContSchema =
390                 getChildOfCont((ContainerSchemaNode) restconfState, MonitoringModule.CONT_CAPABILITES_QNAME);
391         final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> capabilitesContBuilder =
392                 Builders.containerBuilder((ContainerSchemaNode) capabilitesContSchema);
393         final DataSchemaNode leafListCapa = getChildOfCont((ContainerSchemaNode) capabilitesContSchema,
394                 MonitoringModule.LEAF_LIST_CAPABILITY_QNAME);
395         final ListNodeBuilder<Object, LeafSetEntryNode<Object>> leafListCapaBuilder =
396                 Builders.orderedLeafSetBuilder((LeafListSchemaNode) leafListCapa);
397         fillLeafListCapa(leafListCapaBuilder, (LeafListSchemaNode) leafListCapa);
398
399         return restStateContBuilder.withChild(capabilitesContBuilder.withChild(leafListCapaBuilder.build()).build())
400                 .build();
401     }
402
403     /**
404      * Map data to leaf-list.
405      *
406      * @param builder
407      *             builder of parent for children
408      * @param leafListSchema
409      *             leaf list schema
410      */
411     @SuppressWarnings({ "unchecked", "rawtypes" })
412     private static void fillLeafListCapa(final ListNodeBuilder builder, final LeafListSchemaNode leafListSchema) {
413         builder.withChild(leafListEntryBuild(leafListSchema, QueryParams.DEPTH));
414         builder.withChild(leafListEntryBuild(leafListSchema, QueryParams.FIELDS));
415         builder.withChild(leafListEntryBuild(leafListSchema, QueryParams.FILTER));
416         builder.withChild(leafListEntryBuild(leafListSchema, QueryParams.REPLAY));
417         builder.withChild(leafListEntryBuild(leafListSchema, QueryParams.WITH_DEFAULTS));
418     }
419
420     /**
421      * Map value to leaf list entry node.
422      *
423      * @param leafListSchema
424      *             leaf list schema of leaf list entry
425      * @param value
426      *             value of leaf entry
427      * @return entry node
428      */
429     @SuppressWarnings("rawtypes")
430     private static LeafSetEntryNode leafListEntryBuild(final LeafListSchemaNode leafListSchema, final String value) {
431         return Builders.leafSetEntryBuilder(leafListSchema).withValue(value).build();
432     }
433
434     /**
435      * Find specific schema node by qname in parent {@link ContainerSchemaNode}.
436      *
437      * @param parent
438      *             schemaNode
439      * @param childQName
440      *             specific qname of child
441      * @return schema node of child by qname
442      */
443     private static DataSchemaNode getChildOfCont(final ContainerSchemaNode parent, final QName childQName) {
444         for (final DataSchemaNode child : parent.getChildNodes()) {
445             if (child.getQName().equals(childQName)) {
446                 return child;
447             }
448         }
449         throw new RestconfDocumentedException(
450                 childQName.getLocalName() + " doesn't exist in container " + MonitoringModule.CONT_RESTCONF_STATE_NAME);
451     }
452
453     /**
454      * Map data of yang notification to normalized node according to
455      * ietf-restconf-monitoring.
456      *
457      * @param notifiQName
458      *             qname of notification from listener
459      * @param notifications
460      *             list of notifications for find schema of notification by
461      *            notifiQName
462      * @param start
463      *             start-time query parameter of notification
464      * @param outputType
465      *             output type of notification
466      * @param uri
467      *             location of registered listener for sending data of
468      *            notification
469      * @param monitoringModule
470      *             ietf-restconf-monitoring module
471      * @param existParent
472      *             true if data of parent -
473      *            ietf-restconf-monitoring:restconf-state/streams - exist in DS
474      * @return mapped data of notification - map entry node if parent exists,
475      *         container streams with list and map entry node if not
476      */
477     @SuppressWarnings("rawtypes")
478     public static NormalizedNode mapYangNotificationStreamByIetfRestconfMonitoring(final QName notifiQName,
479             final Set<NotificationDefinition> notifications, final Instant start, final String outputType,
480             final URI uri, final Module monitoringModule, final boolean existParent) {
481         for (final NotificationDefinition notificationDefinition : notifications) {
482             if (notificationDefinition.getQName().equals(notifiQName)) {
483                 final DataSchemaNode streamListSchema = ((ContainerSchemaNode) ((ContainerSchemaNode) monitoringModule
484                         .getDataChildByName(MonitoringModule.CONT_RESTCONF_STATE_QNAME))
485                                 .getDataChildByName(MonitoringModule.CONT_STREAMS_QNAME))
486                                         .getDataChildByName(MonitoringModule.LIST_STREAM_QNAME);
487                 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> streamEntry =
488                         Builders.mapEntryBuilder((ListSchemaNode) streamListSchema);
489
490                 final ListSchemaNode listSchema = (ListSchemaNode) streamListSchema;
491                 prepareLeafAndFillEntryBuilder(streamEntry,
492                         listSchema.getDataChildByName(MonitoringModule.LEAF_NAME_STREAM_QNAME),
493                         notificationDefinition.getQName().getLocalName());
494
495                 final java.util.Optional<String> optDesc = notificationDefinition.getDescription();
496                 if (optDesc.isPresent()) {
497                     prepareLeafAndFillEntryBuilder(streamEntry,
498                             listSchema.getDataChildByName(MonitoringModule.LEAF_DESCR_STREAM_QNAME), optDesc.get());
499                 }
500                 prepareLeafAndFillEntryBuilder(streamEntry,
501                         listSchema.getDataChildByName(MonitoringModule.LEAF_REPLAY_SUPP_STREAM_QNAME), true);
502                 if (start != null) {
503                     prepareLeafAndFillEntryBuilder(streamEntry,
504                         listSchema.getDataChildByName(MonitoringModule.LEAF_START_TIME_STREAM_QNAME),
505                         DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(OffsetDateTime.ofInstant(start,
506                             ZoneId.systemDefault())));
507                 }
508                 prepareListAndFillEntryBuilder(streamEntry,
509                         (ListSchemaNode) listSchema.getDataChildByName(MonitoringModule.LIST_ACCESS_STREAM_QNAME),
510                         outputType, uri);
511
512                 if (!existParent) {
513                     final DataSchemaNode contStreamsSchema = ((ContainerSchemaNode) monitoringModule
514                             .getDataChildByName(MonitoringModule.CONT_RESTCONF_STATE_QNAME))
515                                     .getDataChildByName(MonitoringModule.CONT_STREAMS_QNAME);
516                     return Builders.containerBuilder((ContainerSchemaNode) contStreamsSchema).withChild(Builders
517                             .mapBuilder((ListSchemaNode) streamListSchema).withChild(streamEntry.build()).build())
518                             .build();
519                 }
520                 return streamEntry.build();
521             }
522         }
523
524         throw new RestconfDocumentedException(notifiQName + " doesn't exist in any modul");
525     }
526
527     private static void prepareListAndFillEntryBuilder(
528             final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> streamEntry,
529             final ListSchemaNode listSchemaNode, final String outputType, final URI uriToWebsocketServer) {
530         final CollectionNodeBuilder<MapEntryNode, MapNode> accessListBuilder = Builders.mapBuilder(listSchemaNode);
531         final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> entryAccessList =
532                 Builders.mapEntryBuilder(listSchemaNode);
533         prepareLeafAndFillEntryBuilder(entryAccessList,
534                 listSchemaNode.getDataChildByName(MonitoringModule.LEAF_ENCODING_ACCESS_QNAME), outputType);
535         prepareLeafAndFillEntryBuilder(entryAccessList,
536                 listSchemaNode.getDataChildByName(MonitoringModule.LEAF_LOCATION_ACCESS_QNAME),
537                 uriToWebsocketServer.toString());
538         streamEntry.withChild(accessListBuilder.withChild(entryAccessList.build()).build());
539     }
540
541     /**
542      * Prepare leaf and fill entry builder.
543      *
544      * @param streamEntry   Stream entry
545      * @param leafSchema    Leaf schema
546      * @param value         Value
547      */
548     private static void prepareLeafAndFillEntryBuilder(
549             final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> streamEntry,
550             final DataSchemaNode leafSchema, final Object value) {
551         streamEntry.withChild(Builders.leafBuilder((LeafSchemaNode) leafSchema).withValue(value).build());
552     }
553
554     /**
555      * Map data of data change notification to normalized node according to
556      * ietf-restconf-monitoring.
557      *
558      * @param path
559      *             path of data to listen on
560      * @param start
561      *             start-time query parameter of notification
562      * @param outputType
563      *             output type of notification
564      * @param uri
565      *             location of registered listener for sending data of
566      *            notification
567      * @param monitoringModule
568      *             ietf-restconf-monitoring module
569      * @param existParent
570      *             true if data of parent -
571      *            ietf-restconf-monitoring:restconf-state/streams - exist in DS
572      * @param schemaContext
573      *             schemaContext for parsing instance identifier to get schema
574      *            node of data
575      * @return mapped data of notification - map entry node if parent exists,
576      *         container streams with list and map entry node if not
577      */
578     @SuppressWarnings("rawtypes")
579     public static NormalizedNode mapDataChangeNotificationStreamByIetfRestconfMonitoring(
580             final YangInstanceIdentifier path, final Instant start, final String outputType, final URI uri,
581             final Module monitoringModule, final boolean existParent, final SchemaContext schemaContext) {
582         final SchemaNode schemaNode = ParserIdentifier
583                 .toInstanceIdentifier(ParserIdentifier.stringFromYangInstanceIdentifier(path, schemaContext),
584                         schemaContext, Optional.empty())
585                 .getSchemaNode();
586         final DataSchemaNode streamListSchema = ((ContainerSchemaNode) ((ContainerSchemaNode) monitoringModule
587                 .getDataChildByName(MonitoringModule.CONT_RESTCONF_STATE_QNAME))
588                         .getDataChildByName(MonitoringModule.CONT_STREAMS_QNAME))
589                                 .getDataChildByName(MonitoringModule.LIST_STREAM_QNAME);
590         final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> streamEntry =
591                 Builders.mapEntryBuilder((ListSchemaNode) streamListSchema);
592
593         final ListSchemaNode listSchema = (ListSchemaNode) streamListSchema;
594         prepareLeafAndFillEntryBuilder(streamEntry,
595                 listSchema.getDataChildByName(MonitoringModule.LEAF_NAME_STREAM_QNAME),
596                 schemaNode.getQName().getLocalName());
597
598         final java.util.Optional<String> optDesc = schemaNode.getDescription();
599         if (optDesc.isPresent()) {
600             prepareLeafAndFillEntryBuilder(streamEntry,
601                     listSchema.getDataChildByName(MonitoringModule.LEAF_DESCR_STREAM_QNAME), optDesc.get());
602         }
603         prepareLeafAndFillEntryBuilder(streamEntry,
604                 listSchema.getDataChildByName(MonitoringModule.LEAF_REPLAY_SUPP_STREAM_QNAME), true);
605         prepareLeafAndFillEntryBuilder(streamEntry,
606                 listSchema.getDataChildByName(MonitoringModule.LEAF_START_TIME_STREAM_QNAME),
607                 DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(OffsetDateTime.ofInstant(start, ZoneId.systemDefault())));
608         prepareListAndFillEntryBuilder(streamEntry,
609                 (ListSchemaNode) listSchema.getDataChildByName(MonitoringModule.LIST_ACCESS_STREAM_QNAME), outputType,
610                 uri);
611
612         if (!existParent) {
613             final DataSchemaNode contStreamsSchema = ((ContainerSchemaNode) monitoringModule
614                     .getDataChildByName(MonitoringModule.CONT_RESTCONF_STATE_QNAME))
615                             .getDataChildByName(MonitoringModule.CONT_STREAMS_QNAME);
616             return Builders
617                     .containerBuilder((ContainerSchemaNode) contStreamsSchema).withChild(Builders
618                             .mapBuilder((ListSchemaNode) streamListSchema).withChild(streamEntry.build()).build())
619                     .build();
620         }
621         return streamEntry.build();
622     }
623 }