Bug 5679 - ietf-yang-library module implemetation
[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 com.google.common.base.Preconditions;
11 import java.text.SimpleDateFormat;
12 import java.util.Collection;
13 import java.util.Set;
14 import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
15 import org.opendaylight.restconf.Draft18.IetfYangLibrary;
16 import org.opendaylight.restconf.utils.schema.context.RestconfSchemaUtil;
17 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev160621.module.list.Module.ConformanceType;
18 import org.opendaylight.yangtools.yang.common.QName;
19 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
20 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
21 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
22 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
23 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
24 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
25 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
26 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
27 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
28 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
29 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
30 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
31 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
32 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
33 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
34 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
35 import org.opendaylight.yangtools.yang.model.api.Deviation;
36 import org.opendaylight.yangtools.yang.model.api.FeatureDefinition;
37 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
38 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
39 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
40 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
41 import org.opendaylight.yangtools.yang.model.api.Module;
42 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
43
44 /**
45  * Util class for mapping nodes
46  *
47  */
48 public final class RestconfMappingNodeUtil {
49
50     private RestconfMappingNodeUtil() {
51         throw new UnsupportedOperationException("Util class");
52     }
53
54     /**
55      * Map data from modules to {@link NormalizedNode}
56      *
57      * @param modules
58      *            - modules for mapping
59      * @param ietfYangLibraryModule
60      *            - ietf-yang-library module
61      * @param context
62      *            - schema context
63      * @param moduleSetId
64      *            - module-set-id of actual set
65      * @return mapped data as {@link NormalizedNode}
66      */
67     public static NormalizedNode<NodeIdentifier, Collection<DataContainerChild<? extends PathArgument, ?>>>
68             mapModulesByIetfYangLibraryYang(final Set<Module> modules, final Module ietfYangLibraryModule,
69                     final SchemaContext context, final String moduleSetId) {
70         final DataSchemaNode modulesStateSch =
71                 ietfYangLibraryModule.getDataChildByName(IetfYangLibrary.MODUELS_STATE_CONT_QNAME);
72         final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> modulesStateBuilder =
73                 Builders.containerBuilder((ContainerSchemaNode) modulesStateSch);
74
75         final DataSchemaNode moduleSetIdSch =
76                 ((ContainerSchemaNode) modulesStateSch).getDataChildByName(IetfYangLibrary.MODULE_SET_ID_LEAF_QNAME);
77         modulesStateBuilder
78                 .withChild(Builders.leafBuilder((LeafSchemaNode) moduleSetIdSch).withValue(moduleSetId).build());
79
80         final DataSchemaNode moduleSch = findNodeInGroupings(IetfYangLibrary.MODULE_QNAME_LIST, ietfYangLibraryModule);
81         final CollectionNodeBuilder<MapEntryNode, OrderedMapNode> mapBuilder =
82                 Builders.orderedMapBuilder((ListSchemaNode) moduleSch);
83         for (final Module module : context.getModules()) {
84             fillMapByModules(mapBuilder, moduleSch, false, module, ietfYangLibraryModule, context);
85         }
86         return modulesStateBuilder.withChild(mapBuilder.build()).build();
87     }
88
89     /**
90      * Map data by the specific module or submodule
91      *
92      * @param mapBuilder
93      *            - ordered list builder for children
94      * @param moduleSch
95      *            - schema of list for entryMapBuilder
96      * @param isSubmodule
97      *            - true if module is specified as submodule, false otherwise
98      * @param module
99      *            - specific module or submodule
100      * @param ietfYangLibraryModule
101      *            - ietf-yang-library module
102      * @param context
103      *            - schema context
104      */
105     private static void fillMapByModules(final CollectionNodeBuilder<MapEntryNode, OrderedMapNode> mapBuilder,
106             final DataSchemaNode moduleSch, final boolean isSubmodule, final Module module,
107             final Module ietfYangLibraryModule, final SchemaContext context) {
108         final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder =
109                 Builders.mapEntryBuilder((ListSchemaNode) moduleSch);
110         addCommonLeafs(module, mapEntryBuilder, ietfYangLibraryModule);
111         addChildOfModuleBySpecificModuleInternal(
112                 IetfYangLibrary.SPECIFIC_MODULE_SCHEMA_LEAF_QNAME, mapEntryBuilder, IetfYangLibrary.BASE_URI_OF_SCHEMA
113                         + module.getName() + "/" + new SimpleDateFormat("yyyy-MM-dd").format(module.getRevision()),
114                 ietfYangLibraryModule);
115         if (!isSubmodule) {
116             addChildOfModuleBySpecificModuleOfListChild(IetfYangLibrary.SPECIFIC_MODULE_NAMESPACE_LEAF_QNAME,
117                     mapEntryBuilder, module.getNamespace().toString(), ietfYangLibraryModule);
118
119             // features - not mandatory
120             if ((module.getFeatures() != null) && !module.getFeatures().isEmpty()) {
121                 addFeatureLeafList(IetfYangLibrary.SPECIFIC_MODULE_FEATURE_LEAF_LIST_QNAME, mapEntryBuilder,
122                         module.getFeatures(), ietfYangLibraryModule);
123             }
124             // deviations - not mandatory
125             if ((module.getDeviations() != null) && !module.getDeviations().isEmpty()) {
126                 addDeviationList(module, mapEntryBuilder, ietfYangLibraryModule, context);
127                 addChildOfModuleBySpecificModuleOfListChild(IetfYangLibrary.SPECIFIC_MODULE_CONFORMANCE_LEAF_QNAME,
128                         mapEntryBuilder, ConformanceType.Implement.getName(), ietfYangLibraryModule);
129             } else {
130                 addChildOfModuleBySpecificModuleOfListChild(IetfYangLibrary.SPECIFIC_MODULE_CONFORMANCE_LEAF_QNAME,
131                         mapEntryBuilder, ConformanceType.Import.getName(), ietfYangLibraryModule);
132             }
133             // submodules - not mandatory
134             if ((module.getSubmodules() != null) && !module.getSubmodules().isEmpty()) {
135                 addSubmodules(module, mapEntryBuilder, ietfYangLibraryModule, context);
136             }
137         }
138         mapBuilder.withChild(mapEntryBuilder.build());
139     }
140
141     /**
142      * Mapping submodules of specific module
143      *
144      * @param module
145      *            - module with submodules
146      * @param mapEntryBuilder
147      *            - mapEntryBuilder of parent for mapping children
148      * @param ietfYangLibraryModule
149      *            - ietf-yang-library module
150      * @param context
151      *            - schema context
152      */
153     private static void addSubmodules(final Module module,
154             final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder,
155             final Module ietfYangLibraryModule, final SchemaContext context) {
156         final DataSchemaNode listSubm = findSchemaInListOfModulesSchema(
157                 IetfYangLibrary.SPECIFIC_MODULE_SUBMODULE_LIST_QNAME, ietfYangLibraryModule);
158         final CollectionNodeBuilder<MapEntryNode, OrderedMapNode> mapBuilder =
159                 Builders.orderedMapBuilder((ListSchemaNode) listSubm);
160         for (final Module submodule : module.getSubmodules()) {
161             fillMapByModules(mapBuilder, listSubm, true, submodule, ietfYangLibraryModule, context);
162         }
163         mapEntryBuilder.withChild(mapBuilder.build());
164     }
165
166     /**
167      * Mapping deviations of specific module
168      *
169      * @param module
170      *            - module with deviations
171      * @param mapEntryBuilder
172      *            - mapEntryBuilder of parent for mapping children
173      * @param ietfYangLibraryModule
174      *            - ietf-yang-library module
175      * @param context
176      *            - schema context
177      */
178     private static void addDeviationList(final Module module,
179             final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder,
180             final Module ietfYangLibraryModule, final SchemaContext context) {
181         final DataSchemaNode deviationsSchema = findSchemaInListOfModulesSchema(
182                 IetfYangLibrary.SPECIFIC_MODULE_DEVIATION_LIST_QNAME, ietfYangLibraryModule);
183         final CollectionNodeBuilder<MapEntryNode, MapNode> deviations =
184                 Builders.mapBuilder((ListSchemaNode) deviationsSchema);
185         for (final Deviation deviation : module.getDeviations()) {
186             final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> deviationEntryNode =
187                     Builders.mapEntryBuilder((ListSchemaNode) deviationsSchema);
188             final QName lastComponent = deviation.getTargetPath().getLastComponent();
189             addChildOfModuleBySpecificModule(IetfYangLibrary.SPECIFIC_MODULE_NAME_LEAF_QNAME, deviationEntryNode,
190                     context.findModuleByNamespaceAndRevision(lastComponent.getNamespace(), lastComponent.getRevision())
191                             .getName(),
192                     ietfYangLibraryModule);
193             addChildOfModuleBySpecificModule(IetfYangLibrary.SPECIFIC_MODULE_REVISION_LEAF_QNAME, deviationEntryNode,
194                     lastComponent.getRevision(), ietfYangLibraryModule);
195             deviations.withChild(deviationEntryNode.build());
196         }
197         mapEntryBuilder.withChild(deviations.build());
198     }
199
200     /**
201      * Mapping features of specific module
202      *
203      * @param qnameOfFeaturesLeafList
204      *            - qname of feature leaf-list in ietf-yang-library module
205      * @param mapEntryBuilder
206      *            - mapEntryBuilder of parent for mapping children
207      * @param features
208      *            - features of specific module
209      * @param ietfYangLibraryModule
210      *            - ieat-yang-library module
211      */
212     private static void addFeatureLeafList(final QName qnameOfFeaturesLeafList,
213             final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder,
214             final Set<FeatureDefinition> features, final Module ietfYangLibraryModule) {
215         final DataSchemaNode schemaNode =
216                 findSchemaInListOfModulesSchema(qnameOfFeaturesLeafList, ietfYangLibraryModule);
217         final ListNodeBuilder<Object, LeafSetEntryNode<Object>> leafSetBuilder =
218                 Builders.leafSetBuilder((LeafListSchemaNode) schemaNode);
219         for (final FeatureDefinition feature : features) {
220             leafSetBuilder.withChild(Builders.leafSetEntryBuilder((LeafListSchemaNode) schemaNode)
221                     .withValue(feature.getQName().getLocalName()).build());
222         }
223         mapEntryBuilder.withChild(leafSetBuilder.build());
224     }
225
226     /**
227      * Mapping common leafs (grouping common-leafs in ietf-yang-library) of
228      * specific module
229      *
230      * @param module
231      *            - specific module for getting name and revision
232      * @param mapEntryBuilder
233      *            - mapEntryBuilder of parent for mapping children
234      * @param ietfYangLibraryModule
235      *            - ietf-yang-library module
236      */
237     private static void addCommonLeafs(final Module module,
238             final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder,
239             final Module ietfYangLibraryModule) {
240         addChildOfModuleBySpecificModuleInternal(IetfYangLibrary.SPECIFIC_MODULE_NAME_LEAF_QNAME, mapEntryBuilder,
241                 module.getName(), ietfYangLibraryModule);
242         addChildOfModuleBySpecificModuleInternal(IetfYangLibrary.SPECIFIC_MODULE_REVISION_LEAF_QNAME, mapEntryBuilder,
243                 new SimpleDateFormat("yyyy-MM-dd").format(module.getRevision()), ietfYangLibraryModule);
244     }
245
246     /**
247      * Mapping data child of grouping module-list by ietf-yang-library
248      *
249      * @param specificQName
250      *            - qname of leaf in module-list grouping
251      * @param mapEntryBuilder
252      *            - mapEntryBuilder of parent for mapping children
253      * @param value
254      *            - value of leaf
255      * @param ietfYangLibraryModule
256      *            - ietf-yang-library module
257      */
258     private static void addChildOfModuleBySpecificModuleOfListChild(final QName specificQName,
259             final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder,
260             final Object value, final Module ietfYangLibraryModule) {
261         final DataSchemaNode leafSch = findSchemaInListOfModulesSchema(specificQName, ietfYangLibraryModule);
262         mapEntryBuilder.withChild(Builders.leafBuilder((LeafSchemaNode) leafSch).withValue(value).build());
263     }
264
265     /**
266      * Find specific schema in gourping module-lsit
267      *
268      * @param specificQName
269      *            - qname of schema
270      * @param ietfYangLibraryModule
271      *            - ietf-yang-library module
272      * @return schemaNode of specific child
273      */
274     private static DataSchemaNode findSchemaInListOfModulesSchema(final QName specificQName,
275             final Module ietfYangLibraryModule) {
276         for (final GroupingDefinition groupingDefinition : ietfYangLibraryModule.getGroupings()) {
277             if (groupingDefinition.getQName().equals(IetfYangLibrary.GROUPING_MODULE_LIST_QNAME)) {
278                 final DataSchemaNode dataChildByName =
279                         groupingDefinition.getDataChildByName(IetfYangLibrary.MODULE_QNAME_LIST);
280                 return ((ListSchemaNode) dataChildByName).getDataChildByName(specificQName);
281             }
282         }
283         throw new RestconfDocumentedException(specificQName.getLocalName() + " doesn't exist.");
284     }
285
286     /**
287      * Mapping data child of internal groupings in module-list grouping
288      *
289      * @param specifiLeafQName
290      *            - qnmae of leaf for mapping
291      * @param mapEntryBuilder
292      *            - mapEntryBuilder of parent for mapping children
293      * @param value
294      *            - value of leaf
295      * @param ietfYangLibraryModule
296      *            - ietf-yang-library module
297      */
298     private static void addChildOfModuleBySpecificModuleInternal(final QName specifiLeafQName,
299             final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder,
300             final Object value, final Module ietfYangLibraryModule) {
301         final DataSchemaNode nameLeaf = findNodeInInternGroupings(specifiLeafQName, ietfYangLibraryModule);
302         mapEntryBuilder.withChild(Builders.leafBuilder((LeafSchemaNode) nameLeaf).withValue(value).build());
303     }
304
305     /**
306      * Find schema node of leaf by qname in internal groupings of module-list
307      * grouping
308      *
309      * @param qnameOfSchema
310      *            - qname of leaf
311      * @param ietfYangLibraryModule
312      *            - ietf-yang-library module
313      * @return schema node of specific leaf
314      */
315     private static DataSchemaNode findNodeInInternGroupings(final QName qnameOfSchema,
316             final Module ietfYangLibraryModule) {
317         for (final GroupingDefinition groupingDefinition : ietfYangLibraryModule.getGroupings()) {
318             if (groupingDefinition.getQName().equals(IetfYangLibrary.GROUPING_MODULE_LIST_QNAME)) {
319                 for (final GroupingDefinition internalGrouping : groupingDefinition.getGroupings()) {
320                     if (internalGrouping.getDataChildByName(qnameOfSchema) != null) {
321                         return internalGrouping.getDataChildByName(qnameOfSchema);
322                     }
323                 }
324             }
325         }
326         throw new RestconfDocumentedException(qnameOfSchema.getLocalName() + " doesn't exist.");
327     }
328
329     /**
330      * Mapping childrens of list-module
331      *
332      * @param specifiLeafQName
333      *            - qname of leaf
334      * @param mapEntryBuilder
335      *            - maptEntryBuilder of parent for mapping children
336      * @param value
337      *            - valeu of leaf
338      * @param ietfYangLibraryModule
339      *            - ietf-yang-library module
340      */
341     private static void addChildOfModuleBySpecificModule(final QName specifiLeafQName,
342             final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder,
343             final Object value, final Module ietfYangLibraryModule) {
344         final DataSchemaNode nameLeaf = findNodeInGroupings(specifiLeafQName, ietfYangLibraryModule);
345         mapEntryBuilder.withChild(Builders.leafBuilder((LeafSchemaNode) nameLeaf).withValue(value).build());
346     }
347
348     /**
349      * Find schema of specific leaf in list-module grouping
350      *
351      * @param qnameOfSchema
352      *            - qname of leaf
353      * @param ietfYangLibraryModule
354      *            - ietf-yang-library module
355      * @return schemaNode of specific leaf
356      */
357     private static DataSchemaNode findNodeInGroupings(final QName qnameOfSchema, final Module ietfYangLibraryModule) {
358         for (final GroupingDefinition groupingDefinition : ietfYangLibraryModule.getGroupings()) {
359             if (groupingDefinition.getDataChildByName(qnameOfSchema) != null) {
360                 return groupingDefinition.getDataChildByName(qnameOfSchema);
361             }
362         }
363         throw new RestconfDocumentedException(qnameOfSchema.getLocalName() + " doesn't exist.");
364     }
365
366     /**
367      * Mapping {@link MapEntryNode} stream entries of stream to
368      * {@link ListSchemaNode}
369      *
370      * @param streamName
371      *            - stream name
372      * @param streamListSchemaNode
373      *            - mapped {@link DataSchemaNode}
374      * @return {@link MapEntryNode}
375      */
376     public static MapEntryNode toStreamEntryNode(final String streamName, final DataSchemaNode streamListSchemaNode) {
377         Preconditions.checkState(streamListSchemaNode instanceof ListSchemaNode);
378         final ListSchemaNode listStreamSchemaNode = (ListSchemaNode) streamListSchemaNode;
379         final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> streamNodeValues = Builders
380                 .mapEntryBuilder(listStreamSchemaNode);
381
382         // STREAM NAME
383         fillListWithLeaf(listStreamSchemaNode, streamNodeValues, RestconfMappingNodeConstants.NAME, streamName);
384
385         // STREAM DESCRIPTION
386         fillListWithLeaf(listStreamSchemaNode, streamNodeValues, RestconfMappingNodeConstants.DESCRIPTION,
387                 RestconfMappingStreamConstants.DESCRIPTION);
388
389         // STREAM REPLAY_SUPPORT
390         fillListWithLeaf(listStreamSchemaNode, streamNodeValues, RestconfMappingNodeConstants.REPLAY_SUPPORT,
391                 RestconfMappingStreamConstants.REPLAY_SUPPORT);
392
393         // STREAM REPLAY_LOG
394         fillListWithLeaf(listStreamSchemaNode, streamNodeValues, RestconfMappingNodeConstants.REPLAY_LOG,
395                 RestconfMappingStreamConstants.REPLAY_LOG);
396
397         // STREAM EVENTS
398         fillListWithLeaf(listStreamSchemaNode, streamNodeValues, RestconfMappingNodeConstants.EVENTS,
399                 RestconfMappingStreamConstants.EVENTS);
400
401         return streamNodeValues.build();
402     }
403
404     /**
405      * Method for filling {@link ListSchemaNode} with {@link LeafSchemaNode}
406      *
407      * @param listStreamSchemaNode
408      *            - {@link ListSchemaNode}
409      * @param streamNodeValues
410      *            - filled {@link DataContainerNodeAttrBuilder}
411      * @param nameSchemaNode
412      *            - name of mapped leaf
413      * @param value
414      *            - value for mapped node
415      */
416     private static void fillListWithLeaf(
417             final ListSchemaNode listStreamSchemaNode,
418             final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> streamNodeValues,
419             final String nameSchemaNode, final Object value) {
420         final DataSchemaNode schemaNode = RestconfSchemaUtil
421                 .findSchemaNodeInCollection(listStreamSchemaNode.getChildNodes(), nameSchemaNode);
422         Preconditions.checkState(schemaNode instanceof LeafSchemaNode);
423         streamNodeValues.withChild(Builders.leafBuilder((LeafSchemaNode) schemaNode).withValue(value).build());
424     }
425 }