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