Split Restconf implementations (draft02 and RFC) - Prepare modules
[netconf.git] / restconf / restconf-nb-bierman02 / 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 com.google.common.base.Optional;
11 import java.net.URI;
12 import java.time.Instant;
13 import java.time.OffsetDateTime;
14 import java.time.ZoneId;
15 import java.time.format.DateTimeFormatter;
16 import java.util.Collection;
17 import java.util.Set;
18 import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
19 import org.opendaylight.restconf.Rfc8040.IetfYangLibrary;
20 import org.opendaylight.restconf.Rfc8040.MonitoringModule;
21 import org.opendaylight.restconf.Rfc8040.MonitoringModule.QueryParams;
22 import org.opendaylight.restconf.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.data.api.YangInstanceIdentifier;
26 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
27 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
28 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
29 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
31 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
32 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
33 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
34 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
35 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
36 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
37 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
38 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
39 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
40 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
41 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
42 import org.opendaylight.yangtools.yang.model.api.Deviation;
43 import org.opendaylight.yangtools.yang.model.api.FeatureDefinition;
44 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
45 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
46 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
47 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
48 import org.opendaylight.yangtools.yang.model.api.Module;
49 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
50 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
51 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
52
53 /**
54  * Util class for mapping nodes.
55  *
56  */
57 public final class RestconfMappingNodeUtil {
58
59     private RestconfMappingNodeUtil() {
60         throw new UnsupportedOperationException("Util class");
61     }
62
63     /**
64      * Map data from modules to {@link NormalizedNode}.
65      *
66      * @param modules
67      *             modules for mapping
68      * @param ietfYangLibraryModule
69      *             ietf-yang-library module
70      * @param context
71      *             schema context
72      * @param moduleSetId
73      *             module-set-id of actual set
74      * @return mapped data as {@link NormalizedNode}
75      */
76     public static NormalizedNode<NodeIdentifier, Collection<DataContainerChild<? extends PathArgument, ?>>>
77             mapModulesByIetfYangLibraryYang(final Set<Module> modules, final Module ietfYangLibraryModule,
78                     final SchemaContext context, final String moduleSetId) {
79         final DataSchemaNode modulesStateSch =
80                 ietfYangLibraryModule.getDataChildByName(IetfYangLibrary.MODUELS_STATE_CONT_QNAME);
81         final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> modulesStateBuilder =
82                 Builders.containerBuilder((ContainerSchemaNode) modulesStateSch);
83
84         final DataSchemaNode moduleSetIdSch =
85                 ((ContainerSchemaNode) modulesStateSch).getDataChildByName(IetfYangLibrary.MODULE_SET_ID_LEAF_QNAME);
86         modulesStateBuilder
87                 .withChild(Builders.leafBuilder((LeafSchemaNode) moduleSetIdSch).withValue(moduleSetId).build());
88
89         final DataSchemaNode moduleSch = findNodeInGroupings(IetfYangLibrary.MODULE_QNAME_LIST, ietfYangLibraryModule);
90         final CollectionNodeBuilder<MapEntryNode, OrderedMapNode> mapBuilder =
91                 Builders.orderedMapBuilder((ListSchemaNode) moduleSch);
92         for (final Module module : context.getModules()) {
93             fillMapByModules(mapBuilder, moduleSch, false, module, ietfYangLibraryModule, context);
94         }
95         return modulesStateBuilder.withChild(mapBuilder.build()).build();
96     }
97
98     /**
99      * Map data by the specific module or submodule.
100      *
101      * @param mapBuilder
102      *             ordered list builder for children
103      * @param moduleSch
104      *             schema of list for entryMapBuilder
105      * @param isSubmodule
106      *             true if module is specified as submodule, false otherwise
107      * @param module
108      *             specific module or submodule
109      * @param ietfYangLibraryModule
110      *             ietf-yang-library module
111      * @param context
112      *             schema context
113      */
114     private static void fillMapByModules(final CollectionNodeBuilder<MapEntryNode, OrderedMapNode> mapBuilder,
115             final DataSchemaNode moduleSch, final boolean isSubmodule, final Module module,
116             final Module ietfYangLibraryModule, final SchemaContext context) {
117         final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder =
118                 Builders.mapEntryBuilder((ListSchemaNode) moduleSch);
119         addCommonLeafs(module, mapEntryBuilder, ietfYangLibraryModule);
120         addChildOfModuleBySpecificModuleInternal(
121                 IetfYangLibrary.SPECIFIC_MODULE_SCHEMA_LEAF_QNAME, mapEntryBuilder, IetfYangLibrary.BASE_URI_OF_SCHEMA
122                         + module.getName() + "/" + module.getQNameModule().getFormattedRevision(),
123                 ietfYangLibraryModule);
124         if (!isSubmodule) {
125             addChildOfModuleBySpecificModuleOfListChild(IetfYangLibrary.SPECIFIC_MODULE_NAMESPACE_LEAF_QNAME,
126                     mapEntryBuilder, module.getNamespace().toString(), ietfYangLibraryModule);
127
128             // features - not mandatory
129             if ((module.getFeatures() != null) && !module.getFeatures().isEmpty()) {
130                 addFeatureLeafList(IetfYangLibrary.SPECIFIC_MODULE_FEATURE_LEAF_LIST_QNAME, mapEntryBuilder,
131                         module.getFeatures(), ietfYangLibraryModule);
132             }
133             // deviations - not mandatory
134             if ((module.getDeviations() != null) && !module.getDeviations().isEmpty()) {
135                 addDeviationList(module, mapEntryBuilder, ietfYangLibraryModule, context);
136                 addChildOfModuleBySpecificModuleOfListChild(IetfYangLibrary.SPECIFIC_MODULE_CONFORMANCE_LEAF_QNAME,
137                         mapEntryBuilder, ConformanceType.Implement.getName(), ietfYangLibraryModule);
138             } else {
139                 addChildOfModuleBySpecificModuleOfListChild(IetfYangLibrary.SPECIFIC_MODULE_CONFORMANCE_LEAF_QNAME,
140                         mapEntryBuilder, ConformanceType.Import.getName(), ietfYangLibraryModule);
141             }
142             // submodules - not mandatory
143             if ((module.getSubmodules() != null) && !module.getSubmodules().isEmpty()) {
144                 addSubmodules(module, mapEntryBuilder, ietfYangLibraryModule, context);
145             }
146         }
147         mapBuilder.withChild(mapEntryBuilder.build());
148     }
149
150     /**
151      * Mapping submodules of specific module.
152      *
153      * @param module
154      *             module with submodules
155      * @param mapEntryBuilder
156      *             mapEntryBuilder of parent for mapping children
157      * @param ietfYangLibraryModule
158      *             ietf-yang-library module
159      * @param context
160      *             schema context
161      */
162     private static void addSubmodules(final Module module,
163             final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder,
164             final Module ietfYangLibraryModule, final SchemaContext context) {
165         final DataSchemaNode listSubm = findSchemaInListOfModulesSchema(
166                 IetfYangLibrary.SPECIFIC_MODULE_SUBMODULE_LIST_QNAME, ietfYangLibraryModule);
167         final CollectionNodeBuilder<MapEntryNode, OrderedMapNode> mapBuilder =
168                 Builders.orderedMapBuilder((ListSchemaNode) listSubm);
169         for (final Module submodule : module.getSubmodules()) {
170             fillMapByModules(mapBuilder, listSubm, true, submodule, ietfYangLibraryModule, context);
171         }
172         mapEntryBuilder.withChild(mapBuilder.build());
173     }
174
175     /**
176      * Mapping deviations of specific module.
177      *
178      * @param module
179      *             module with deviations
180      * @param mapEntryBuilder
181      *             mapEntryBuilder of parent for mapping children
182      * @param ietfYangLibraryModule
183      *             ietf-yang-library module
184      * @param context
185      *             schema context
186      */
187     private static void addDeviationList(final Module module,
188             final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder,
189             final Module ietfYangLibraryModule, final SchemaContext context) {
190         final DataSchemaNode deviationsSchema = findSchemaInListOfModulesSchema(
191                 IetfYangLibrary.SPECIFIC_MODULE_DEVIATION_LIST_QNAME, ietfYangLibraryModule);
192         final CollectionNodeBuilder<MapEntryNode, MapNode> deviations =
193                 Builders.mapBuilder((ListSchemaNode) deviationsSchema);
194         for (final Deviation deviation : module.getDeviations()) {
195             final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> deviationEntryNode =
196                     Builders.mapEntryBuilder((ListSchemaNode) deviationsSchema);
197             final QName lastComponent = deviation.getTargetPath().getLastComponent();
198             addChildOfModuleBySpecificModule(IetfYangLibrary.SPECIFIC_MODULE_NAME_LEAF_QNAME, deviationEntryNode,
199                     context.findModuleByNamespaceAndRevision(lastComponent.getNamespace(), lastComponent.getRevision())
200                             .getName(),
201                     ietfYangLibraryModule);
202             addChildOfModuleBySpecificModule(IetfYangLibrary.SPECIFIC_MODULE_REVISION_LEAF_QNAME, deviationEntryNode,
203                     lastComponent.getRevision(), 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 DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder,
223             final Set<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 DataContainerNodeAttrBuilder<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().getFormattedRevision(), 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 DataContainerNodeAttrBuilder<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 DataContainerNodeAttrBuilder<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      * Mapping childrens of list-module.
340      *
341      * @param specifiLeafQName
342      *             qname of leaf
343      * @param mapEntryBuilder
344      *             maptEntryBuilder of parent for mapping children
345      * @param value
346      *             valeu of leaf
347      * @param ietfYangLibraryModule
348      *             ietf-yang-library module
349      */
350     private static void addChildOfModuleBySpecificModule(final QName specifiLeafQName,
351             final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder,
352             final Object value, final Module ietfYangLibraryModule) {
353         final DataSchemaNode nameLeaf = findNodeInGroupings(specifiLeafQName, ietfYangLibraryModule);
354         mapEntryBuilder.withChild(Builders.leafBuilder((LeafSchemaNode) nameLeaf).withValue(value).build());
355     }
356
357     /**
358      * Find schema of specific leaf in list-module grouping.
359      *
360      * @param qnameOfSchema
361      *             qname of leaf
362      * @param ietfYangLibraryModule
363      *             ietf-yang-library module
364      * @return schemaNode of specific leaf
365      */
366     private static DataSchemaNode findNodeInGroupings(final QName qnameOfSchema, final Module ietfYangLibraryModule) {
367         for (final GroupingDefinition groupingDefinition : ietfYangLibraryModule.getGroupings()) {
368             if (groupingDefinition.getDataChildByName(qnameOfSchema) != null) {
369                 return groupingDefinition.getDataChildByName(qnameOfSchema);
370             }
371         }
372         throw new RestconfDocumentedException(qnameOfSchema.getLocalName() + " doesn't exist.");
373     }
374
375     /**
376      * Map capabilites by ietf-restconf-monitoring.
377      *
378      * @param monitoringModule
379      *             ietf-restconf-monitoring module
380      * @return mapped capabilites
381      */
382     public static NormalizedNode<NodeIdentifier, Collection<DataContainerChild<? extends PathArgument, ?>>>
383             mapCapabilites(final Module monitoringModule) {
384         final DataSchemaNode restconfState =
385                 monitoringModule.getDataChildByName(MonitoringModule.CONT_RESTCONF_STATE_QNAME);
386         final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> restStateContBuilder =
387                 Builders.containerBuilder((ContainerSchemaNode) restconfState);
388         final DataSchemaNode capabilitesContSchema =
389                 getChildOfCont((ContainerSchemaNode) restconfState, MonitoringModule.CONT_CAPABILITES_QNAME);
390         final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> capabilitesContBuilder =
391                 Builders.containerBuilder((ContainerSchemaNode) capabilitesContSchema);
392         final DataSchemaNode leafListCapa = getChildOfCont((ContainerSchemaNode) capabilitesContSchema,
393                 MonitoringModule.LEAF_LIST_CAPABILITY_QNAME);
394         final ListNodeBuilder<Object, LeafSetEntryNode<Object>> leafListCapaBuilder =
395                 Builders.orderedLeafSetBuilder((LeafListSchemaNode) leafListCapa);
396         fillLeafListCapa(leafListCapaBuilder, (LeafListSchemaNode) leafListCapa);
397
398         return restStateContBuilder.withChild(capabilitesContBuilder.withChild(leafListCapaBuilder.build()).build())
399                 .build();
400     }
401
402     /**
403      * Map data to leaf-list.
404      *
405      * @param builder
406      *             builder of parent for children
407      * @param leafListSchema
408      *             leaf list schema
409      */
410     @SuppressWarnings({ "unchecked", "rawtypes" })
411     private static void fillLeafListCapa(final ListNodeBuilder builder, final LeafListSchemaNode leafListSchema) {
412         builder.withChild(leafListEntryBuild(leafListSchema, QueryParams.DEPTH));
413         builder.withChild(leafListEntryBuild(leafListSchema, QueryParams.FIELDS));
414         builder.withChild(leafListEntryBuild(leafListSchema, QueryParams.FILTER));
415         builder.withChild(leafListEntryBuild(leafListSchema, QueryParams.REPLAY));
416         builder.withChild(leafListEntryBuild(leafListSchema, QueryParams.WITH_DEFAULTS));
417     }
418
419     /**
420      * Map value to leaf list entry node.
421      *
422      * @param leafListSchema
423      *             leaf list schema of leaf list entry
424      * @param value
425      *             value of leaf entry
426      * @return entry node
427      */
428     @SuppressWarnings("rawtypes")
429     private static LeafSetEntryNode leafListEntryBuild(final LeafListSchemaNode leafListSchema, final String value) {
430         return Builders.leafSetEntryBuilder(leafListSchema).withValue(value).build();
431     }
432
433     /**
434      * Find specific schema node by qname in parent {@link ContainerSchemaNode}.
435      *
436      * @param parent
437      *             schemaNode
438      * @param childQName
439      *             specific qname of child
440      * @return schema node of child by qname
441      */
442     private static DataSchemaNode getChildOfCont(final ContainerSchemaNode parent, final QName childQName) {
443         for (final DataSchemaNode child : parent.getChildNodes()) {
444             if (child.getQName().equals(childQName)) {
445                 return child;
446             }
447         }
448         throw new RestconfDocumentedException(
449                 childQName.getLocalName() + " doesn't exist in container " + MonitoringModule.CONT_RESTCONF_STATE_NAME);
450     }
451
452     /**
453      * Map data of yang notification to normalized node according to
454      * ietf-restconf-monitoring.
455      *
456      * @param notifiQName
457      *             qname of notification from listener
458      * @param notifications
459      *             list of notifications for find schema of notification by
460      *            notifiQName
461      * @param start
462      *             start-time query parameter of notification
463      * @param outputType
464      *             output type of notification
465      * @param uri
466      *             location of registered listener for sending data of
467      *            notification
468      * @param monitoringModule
469      *             ietf-restconf-monitoring module
470      * @param existParent
471      *             true if data of parent -
472      *            ietf-restconf-monitoring:restconf-state/streams - exist in DS
473      * @return mapped data of notification - map entry node if parent exists,
474      *         container streams with list and map entry node if not
475      */
476     @SuppressWarnings("rawtypes")
477     public static NormalizedNode mapYangNotificationStreamByIetfRestconfMonitoring(final QName notifiQName,
478             final Set<NotificationDefinition> notifications, final Instant start, final String outputType,
479             final URI uri, final Module monitoringModule, final boolean existParent) {
480         for (final NotificationDefinition notificationDefinition : notifications) {
481             if (notificationDefinition.getQName().equals(notifiQName)) {
482                 final DataSchemaNode streamListSchema = ((ContainerSchemaNode) ((ContainerSchemaNode) monitoringModule
483                         .getDataChildByName(MonitoringModule.CONT_RESTCONF_STATE_QNAME))
484                                 .getDataChildByName(MonitoringModule.CONT_STREAMS_QNAME))
485                                         .getDataChildByName(MonitoringModule.LIST_STREAM_QNAME);
486                 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> streamEntry =
487                         Builders.mapEntryBuilder((ListSchemaNode) streamListSchema);
488
489                 final ListSchemaNode listSchema = ((ListSchemaNode) streamListSchema);
490                 prepareLeafAndFillEntryBuilder(streamEntry,
491                         listSchema.getDataChildByName(MonitoringModule.LEAF_NAME_STREAM_QNAME),
492                         notificationDefinition.getQName().getLocalName());
493                 if ((notificationDefinition.getDescription() != null)
494                         && !notificationDefinition.getDescription().equals("")) {
495                     prepareLeafAndFillEntryBuilder(streamEntry,
496                             listSchema.getDataChildByName(MonitoringModule.LEAF_DESCR_STREAM_QNAME),
497                             notificationDefinition.getDescription());
498                 }
499                 prepareLeafAndFillEntryBuilder(streamEntry,
500                         listSchema.getDataChildByName(MonitoringModule.LEAF_REPLAY_SUPP_STREAM_QNAME), true);
501                 if (start != null) {
502                     prepareLeafAndFillEntryBuilder(streamEntry,
503                         listSchema.getDataChildByName(MonitoringModule.LEAF_START_TIME_STREAM_QNAME),
504                         DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(OffsetDateTime.ofInstant(start,
505                             ZoneId.systemDefault())));
506                 }
507                 prepareListAndFillEntryBuilder(streamEntry,
508                         (ListSchemaNode) listSchema.getDataChildByName(MonitoringModule.LIST_ACCESS_STREAM_QNAME),
509                         outputType, uri);
510
511                 if (!existParent) {
512                     final DataSchemaNode contStreamsSchema = ((ContainerSchemaNode) monitoringModule
513                             .getDataChildByName(MonitoringModule.CONT_RESTCONF_STATE_QNAME))
514                                     .getDataChildByName(MonitoringModule.CONT_STREAMS_QNAME);
515                     return Builders.containerBuilder((ContainerSchemaNode) contStreamsSchema).withChild(Builders
516                             .mapBuilder((ListSchemaNode) streamListSchema).withChild(streamEntry.build()).build())
517                             .build();
518                 }
519                 return streamEntry.build();
520             }
521         }
522
523         throw new RestconfDocumentedException(notifiQName + " doesn't exist in any modul");
524     }
525
526     private static void prepareListAndFillEntryBuilder(
527             final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> streamEntry,
528             final ListSchemaNode listSchemaNode, final String outputType, final URI uriToWebsocketServer) {
529         final CollectionNodeBuilder<MapEntryNode, MapNode> accessListBuilder = Builders.mapBuilder(listSchemaNode);
530         final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> entryAccessList =
531                 Builders.mapEntryBuilder(listSchemaNode);
532         prepareLeafAndFillEntryBuilder(entryAccessList,
533                 listSchemaNode.getDataChildByName(MonitoringModule.LEAF_ENCODING_ACCESS_QNAME), outputType);
534         prepareLeafAndFillEntryBuilder(entryAccessList,
535                 listSchemaNode.getDataChildByName(MonitoringModule.LEAF_LOCATION_ACCESS_QNAME),
536                 uriToWebsocketServer.toString());
537         streamEntry.withChild(accessListBuilder.withChild(entryAccessList.build()).build());
538     }
539
540     /**
541      * Prepare leaf and fill entry builder.
542      *
543      * @param streamEntry   Stream entry
544      * @param leafSchema    Leaf schema
545      * @param value         Value
546      */
547     private static void prepareLeafAndFillEntryBuilder(
548             final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> streamEntry,
549             final DataSchemaNode leafSchema, final Object value) {
550         streamEntry.withChild(Builders.leafBuilder((LeafSchemaNode) leafSchema).withValue(value).build());
551     }
552
553     /**
554      * Map data of data change notification to normalized node according to
555      * ietf-restconf-monitoring.
556      *
557      * @param path
558      *             path of data to listen on
559      * @param start
560      *             start-time query parameter of notification
561      * @param outputType
562      *             output type of notification
563      * @param uri
564      *             location of registered listener for sending data of
565      *            notification
566      * @param monitoringModule
567      *             ietf-restconf-monitoring module
568      * @param existParent
569      *             true if data of parent -
570      *            ietf-restconf-monitoring:restconf-state/streams - exist in DS
571      * @param schemaContext
572      *             schemaContext for parsing instance identifier to get schema
573      *            node of data
574      * @return mapped data of notification - map entry node if parent exists,
575      *         container streams with list and map entry node if not
576      */
577     @SuppressWarnings("rawtypes")
578     public static NormalizedNode mapDataChangeNotificationStreamByIetfRestconfMonitoring(
579             final YangInstanceIdentifier path, final Instant start, final String outputType, final URI uri,
580             final Module monitoringModule, final boolean existParent, final SchemaContext schemaContext) {
581         final SchemaNode schemaNode = ParserIdentifier
582                 .toInstanceIdentifier(ParserIdentifier.stringFromYangInstanceIdentifier(path, schemaContext),
583                         schemaContext, Optional.absent())
584                 .getSchemaNode();
585         final DataSchemaNode streamListSchema = ((ContainerSchemaNode) ((ContainerSchemaNode) monitoringModule
586                 .getDataChildByName(MonitoringModule.CONT_RESTCONF_STATE_QNAME))
587                         .getDataChildByName(MonitoringModule.CONT_STREAMS_QNAME))
588                                 .getDataChildByName(MonitoringModule.LIST_STREAM_QNAME);
589         final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> streamEntry =
590                 Builders.mapEntryBuilder((ListSchemaNode) streamListSchema);
591
592         final ListSchemaNode listSchema = ((ListSchemaNode) streamListSchema);
593         prepareLeafAndFillEntryBuilder(streamEntry,
594                 listSchema.getDataChildByName(MonitoringModule.LEAF_NAME_STREAM_QNAME),
595                 schemaNode.getQName().getLocalName());
596         if ((schemaNode.getDescription() != null) && !schemaNode.getDescription().equals("")) {
597             prepareLeafAndFillEntryBuilder(streamEntry,
598                     listSchema.getDataChildByName(MonitoringModule.LEAF_DESCR_STREAM_QNAME),
599                     schemaNode.getDescription());
600         }
601         prepareLeafAndFillEntryBuilder(streamEntry,
602                 listSchema.getDataChildByName(MonitoringModule.LEAF_REPLAY_SUPP_STREAM_QNAME), true);
603         prepareLeafAndFillEntryBuilder(streamEntry,
604                 listSchema.getDataChildByName(MonitoringModule.LEAF_START_TIME_STREAM_QNAME),
605                 DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(OffsetDateTime.ofInstant(start, ZoneId.systemDefault())));
606         prepareListAndFillEntryBuilder(streamEntry,
607                 (ListSchemaNode) listSchema.getDataChildByName(MonitoringModule.LIST_ACCESS_STREAM_QNAME), outputType,
608                 uri);
609
610         if (!existParent) {
611             final DataSchemaNode contStreamsSchema = ((ContainerSchemaNode) monitoringModule
612                     .getDataChildByName(MonitoringModule.CONT_RESTCONF_STATE_QNAME))
613                             .getDataChildByName(MonitoringModule.CONT_STREAMS_QNAME);
614             return Builders
615                     .containerBuilder((ContainerSchemaNode) contStreamsSchema).withChild(Builders
616                             .mapBuilder((ListSchemaNode) streamListSchema).withChild(streamEntry.build()).build())
617                     .build();
618         }
619         return streamEntry.build();
620     }
621 }