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