2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.restconf.utils.mapping;
10 import com.google.common.base.Preconditions;
11 import java.text.SimpleDateFormat;
12 import java.util.Collection;
14 import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
15 import org.opendaylight.restconf.Draft18.IetfYangLibrary;
16 import org.opendaylight.restconf.Draft18.MonitoringModule;
17 import org.opendaylight.restconf.Draft18.MonitoringModule.QueryParams;
18 import org.opendaylight.restconf.utils.schema.context.RestconfSchemaUtil;
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev160621.module.list.Module.ConformanceType;
20 import org.opendaylight.yangtools.yang.common.QName;
21 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
22 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
23 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
24 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
25 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
26 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
27 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
28 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
29 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
31 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
32 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
33 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
34 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
35 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
36 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
37 import org.opendaylight.yangtools.yang.model.api.Deviation;
38 import org.opendaylight.yangtools.yang.model.api.FeatureDefinition;
39 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
40 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
41 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
42 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
43 import org.opendaylight.yangtools.yang.model.api.Module;
44 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
47 * Util class for mapping nodes
50 public final class RestconfMappingNodeUtil {
52 private RestconfMappingNodeUtil() {
53 throw new UnsupportedOperationException("Util class");
57 * Map data from modules to {@link NormalizedNode}
60 * - modules for mapping
61 * @param ietfYangLibraryModule
62 * - ietf-yang-library module
66 * - module-set-id of actual set
67 * @return mapped data as {@link NormalizedNode}
69 public static NormalizedNode<NodeIdentifier, Collection<DataContainerChild<? extends PathArgument, ?>>>
70 mapModulesByIetfYangLibraryYang(final Set<Module> modules, final Module ietfYangLibraryModule,
71 final SchemaContext context, final String moduleSetId) {
72 final DataSchemaNode modulesStateSch =
73 ietfYangLibraryModule.getDataChildByName(IetfYangLibrary.MODUELS_STATE_CONT_QNAME);
74 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> modulesStateBuilder =
75 Builders.containerBuilder((ContainerSchemaNode) modulesStateSch);
77 final DataSchemaNode moduleSetIdSch =
78 ((ContainerSchemaNode) modulesStateSch).getDataChildByName(IetfYangLibrary.MODULE_SET_ID_LEAF_QNAME);
80 .withChild(Builders.leafBuilder((LeafSchemaNode) moduleSetIdSch).withValue(moduleSetId).build());
82 final DataSchemaNode moduleSch = findNodeInGroupings(IetfYangLibrary.MODULE_QNAME_LIST, ietfYangLibraryModule);
83 final CollectionNodeBuilder<MapEntryNode, OrderedMapNode> mapBuilder =
84 Builders.orderedMapBuilder((ListSchemaNode) moduleSch);
85 for (final Module module : context.getModules()) {
86 fillMapByModules(mapBuilder, moduleSch, false, module, ietfYangLibraryModule, context);
88 return modulesStateBuilder.withChild(mapBuilder.build()).build();
92 * Map data by the specific module or submodule
95 * - ordered list builder for children
97 * - schema of list for entryMapBuilder
99 * - true if module is specified as submodule, false otherwise
101 * - specific module or submodule
102 * @param ietfYangLibraryModule
103 * - ietf-yang-library module
107 private static void fillMapByModules(final CollectionNodeBuilder<MapEntryNode, OrderedMapNode> mapBuilder,
108 final DataSchemaNode moduleSch, final boolean isSubmodule, final Module module,
109 final Module ietfYangLibraryModule, final SchemaContext context) {
110 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder =
111 Builders.mapEntryBuilder((ListSchemaNode) moduleSch);
112 addCommonLeafs(module, mapEntryBuilder, ietfYangLibraryModule);
113 addChildOfModuleBySpecificModuleInternal(
114 IetfYangLibrary.SPECIFIC_MODULE_SCHEMA_LEAF_QNAME, mapEntryBuilder, IetfYangLibrary.BASE_URI_OF_SCHEMA
115 + module.getName() + "/" + new SimpleDateFormat("yyyy-MM-dd").format(module.getRevision()),
116 ietfYangLibraryModule);
118 addChildOfModuleBySpecificModuleOfListChild(IetfYangLibrary.SPECIFIC_MODULE_NAMESPACE_LEAF_QNAME,
119 mapEntryBuilder, module.getNamespace().toString(), ietfYangLibraryModule);
121 // features - not mandatory
122 if ((module.getFeatures() != null) && !module.getFeatures().isEmpty()) {
123 addFeatureLeafList(IetfYangLibrary.SPECIFIC_MODULE_FEATURE_LEAF_LIST_QNAME, mapEntryBuilder,
124 module.getFeatures(), ietfYangLibraryModule);
126 // deviations - not mandatory
127 if ((module.getDeviations() != null) && !module.getDeviations().isEmpty()) {
128 addDeviationList(module, mapEntryBuilder, ietfYangLibraryModule, context);
129 addChildOfModuleBySpecificModuleOfListChild(IetfYangLibrary.SPECIFIC_MODULE_CONFORMANCE_LEAF_QNAME,
130 mapEntryBuilder, ConformanceType.Implement.getName(), ietfYangLibraryModule);
132 addChildOfModuleBySpecificModuleOfListChild(IetfYangLibrary.SPECIFIC_MODULE_CONFORMANCE_LEAF_QNAME,
133 mapEntryBuilder, ConformanceType.Import.getName(), ietfYangLibraryModule);
135 // submodules - not mandatory
136 if ((module.getSubmodules() != null) && !module.getSubmodules().isEmpty()) {
137 addSubmodules(module, mapEntryBuilder, ietfYangLibraryModule, context);
140 mapBuilder.withChild(mapEntryBuilder.build());
144 * Mapping submodules of specific module
147 * - module with submodules
148 * @param mapEntryBuilder
149 * - mapEntryBuilder of parent for mapping children
150 * @param ietfYangLibraryModule
151 * - ietf-yang-library module
155 private static void addSubmodules(final Module module,
156 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder,
157 final Module ietfYangLibraryModule, final SchemaContext context) {
158 final DataSchemaNode listSubm = findSchemaInListOfModulesSchema(
159 IetfYangLibrary.SPECIFIC_MODULE_SUBMODULE_LIST_QNAME, ietfYangLibraryModule);
160 final CollectionNodeBuilder<MapEntryNode, OrderedMapNode> mapBuilder =
161 Builders.orderedMapBuilder((ListSchemaNode) listSubm);
162 for (final Module submodule : module.getSubmodules()) {
163 fillMapByModules(mapBuilder, listSubm, true, submodule, ietfYangLibraryModule, context);
165 mapEntryBuilder.withChild(mapBuilder.build());
169 * Mapping deviations of specific module
172 * - module with deviations
173 * @param mapEntryBuilder
174 * - mapEntryBuilder of parent for mapping children
175 * @param ietfYangLibraryModule
176 * - ietf-yang-library module
180 private static void addDeviationList(final Module module,
181 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder,
182 final Module ietfYangLibraryModule, final SchemaContext context) {
183 final DataSchemaNode deviationsSchema = findSchemaInListOfModulesSchema(
184 IetfYangLibrary.SPECIFIC_MODULE_DEVIATION_LIST_QNAME, ietfYangLibraryModule);
185 final CollectionNodeBuilder<MapEntryNode, MapNode> deviations =
186 Builders.mapBuilder((ListSchemaNode) deviationsSchema);
187 for (final Deviation deviation : module.getDeviations()) {
188 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> deviationEntryNode =
189 Builders.mapEntryBuilder((ListSchemaNode) deviationsSchema);
190 final QName lastComponent = deviation.getTargetPath().getLastComponent();
191 addChildOfModuleBySpecificModule(IetfYangLibrary.SPECIFIC_MODULE_NAME_LEAF_QNAME, deviationEntryNode,
192 context.findModuleByNamespaceAndRevision(lastComponent.getNamespace(), lastComponent.getRevision())
194 ietfYangLibraryModule);
195 addChildOfModuleBySpecificModule(IetfYangLibrary.SPECIFIC_MODULE_REVISION_LEAF_QNAME, deviationEntryNode,
196 lastComponent.getRevision(), ietfYangLibraryModule);
197 deviations.withChild(deviationEntryNode.build());
199 mapEntryBuilder.withChild(deviations.build());
203 * Mapping features of specific module
205 * @param qnameOfFeaturesLeafList
206 * - qname of feature leaf-list in ietf-yang-library module
207 * @param mapEntryBuilder
208 * - mapEntryBuilder of parent for mapping children
210 * - features of specific module
211 * @param ietfYangLibraryModule
212 * - ieat-yang-library module
214 private static void addFeatureLeafList(final QName qnameOfFeaturesLeafList,
215 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder,
216 final Set<FeatureDefinition> features, final Module ietfYangLibraryModule) {
217 final DataSchemaNode schemaNode =
218 findSchemaInListOfModulesSchema(qnameOfFeaturesLeafList, ietfYangLibraryModule);
219 final ListNodeBuilder<Object, LeafSetEntryNode<Object>> leafSetBuilder =
220 Builders.leafSetBuilder((LeafListSchemaNode) schemaNode);
221 for (final FeatureDefinition feature : features) {
222 leafSetBuilder.withChild(Builders.leafSetEntryBuilder((LeafListSchemaNode) schemaNode)
223 .withValue(feature.getQName().getLocalName()).build());
225 mapEntryBuilder.withChild(leafSetBuilder.build());
229 * Mapping common leafs (grouping common-leafs in ietf-yang-library) of
233 * - specific module for getting name and revision
234 * @param mapEntryBuilder
235 * - mapEntryBuilder of parent for mapping children
236 * @param ietfYangLibraryModule
237 * - ietf-yang-library module
239 private static void addCommonLeafs(final Module module,
240 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder,
241 final Module ietfYangLibraryModule) {
242 addChildOfModuleBySpecificModuleInternal(IetfYangLibrary.SPECIFIC_MODULE_NAME_LEAF_QNAME, mapEntryBuilder,
243 module.getName(), ietfYangLibraryModule);
244 addChildOfModuleBySpecificModuleInternal(IetfYangLibrary.SPECIFIC_MODULE_REVISION_LEAF_QNAME, mapEntryBuilder,
245 new SimpleDateFormat("yyyy-MM-dd").format(module.getRevision()), ietfYangLibraryModule);
249 * Mapping data child of grouping module-list by ietf-yang-library
251 * @param specificQName
252 * - qname of leaf in module-list grouping
253 * @param mapEntryBuilder
254 * - mapEntryBuilder of parent for mapping children
257 * @param ietfYangLibraryModule
258 * - ietf-yang-library module
260 private static void addChildOfModuleBySpecificModuleOfListChild(final QName specificQName,
261 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder,
262 final Object value, final Module ietfYangLibraryModule) {
263 final DataSchemaNode leafSch = findSchemaInListOfModulesSchema(specificQName, ietfYangLibraryModule);
264 mapEntryBuilder.withChild(Builders.leafBuilder((LeafSchemaNode) leafSch).withValue(value).build());
268 * Find specific schema in gourping module-lsit
270 * @param specificQName
272 * @param ietfYangLibraryModule
273 * - ietf-yang-library module
274 * @return schemaNode of specific child
276 private static DataSchemaNode findSchemaInListOfModulesSchema(final QName specificQName,
277 final Module ietfYangLibraryModule) {
278 for (final GroupingDefinition groupingDefinition : ietfYangLibraryModule.getGroupings()) {
279 if (groupingDefinition.getQName().equals(IetfYangLibrary.GROUPING_MODULE_LIST_QNAME)) {
280 final DataSchemaNode dataChildByName =
281 groupingDefinition.getDataChildByName(IetfYangLibrary.MODULE_QNAME_LIST);
282 return ((ListSchemaNode) dataChildByName).getDataChildByName(specificQName);
285 throw new RestconfDocumentedException(specificQName.getLocalName() + " doesn't exist.");
289 * Mapping data child of internal groupings in module-list grouping
291 * @param specifiLeafQName
292 * - qnmae of leaf for mapping
293 * @param mapEntryBuilder
294 * - mapEntryBuilder of parent for mapping children
297 * @param ietfYangLibraryModule
298 * - ietf-yang-library module
300 private static void addChildOfModuleBySpecificModuleInternal(final QName specifiLeafQName,
301 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder,
302 final Object value, final Module ietfYangLibraryModule) {
303 final DataSchemaNode nameLeaf = findNodeInInternGroupings(specifiLeafQName, ietfYangLibraryModule);
304 mapEntryBuilder.withChild(Builders.leafBuilder((LeafSchemaNode) nameLeaf).withValue(value).build());
308 * Find schema node of leaf by qname in internal groupings of module-list
311 * @param qnameOfSchema
313 * @param ietfYangLibraryModule
314 * - ietf-yang-library module
315 * @return schema node of specific leaf
317 private static DataSchemaNode findNodeInInternGroupings(final QName qnameOfSchema,
318 final Module ietfYangLibraryModule) {
319 for (final GroupingDefinition groupingDefinition : ietfYangLibraryModule.getGroupings()) {
320 if (groupingDefinition.getQName().equals(IetfYangLibrary.GROUPING_MODULE_LIST_QNAME)) {
321 for (final GroupingDefinition internalGrouping : groupingDefinition.getGroupings()) {
322 if (internalGrouping.getDataChildByName(qnameOfSchema) != null) {
323 return internalGrouping.getDataChildByName(qnameOfSchema);
328 throw new RestconfDocumentedException(qnameOfSchema.getLocalName() + " doesn't exist.");
332 * Mapping childrens of list-module
334 * @param specifiLeafQName
336 * @param mapEntryBuilder
337 * - maptEntryBuilder of parent for mapping children
340 * @param ietfYangLibraryModule
341 * - ietf-yang-library module
343 private static void addChildOfModuleBySpecificModule(final QName specifiLeafQName,
344 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder,
345 final Object value, final Module ietfYangLibraryModule) {
346 final DataSchemaNode nameLeaf = findNodeInGroupings(specifiLeafQName, ietfYangLibraryModule);
347 mapEntryBuilder.withChild(Builders.leafBuilder((LeafSchemaNode) nameLeaf).withValue(value).build());
351 * Find schema of specific leaf in list-module grouping
353 * @param qnameOfSchema
355 * @param ietfYangLibraryModule
356 * - ietf-yang-library module
357 * @return schemaNode of specific leaf
359 private static DataSchemaNode findNodeInGroupings(final QName qnameOfSchema, final Module ietfYangLibraryModule) {
360 for (final GroupingDefinition groupingDefinition : ietfYangLibraryModule.getGroupings()) {
361 if (groupingDefinition.getDataChildByName(qnameOfSchema) != null) {
362 return groupingDefinition.getDataChildByName(qnameOfSchema);
365 throw new RestconfDocumentedException(qnameOfSchema.getLocalName() + " doesn't exist.");
369 * Mapping {@link MapEntryNode} stream entries of stream to
370 * {@link ListSchemaNode}
374 * @param streamListSchemaNode
375 * - mapped {@link DataSchemaNode}
376 * @return {@link MapEntryNode}
378 public static MapEntryNode toStreamEntryNode(final String streamName, final DataSchemaNode streamListSchemaNode) {
379 Preconditions.checkState(streamListSchemaNode instanceof ListSchemaNode);
380 final ListSchemaNode listStreamSchemaNode = (ListSchemaNode) streamListSchemaNode;
381 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> streamNodeValues = Builders
382 .mapEntryBuilder(listStreamSchemaNode);
385 fillListWithLeaf(listStreamSchemaNode, streamNodeValues, RestconfMappingNodeConstants.NAME, streamName);
387 // STREAM DESCRIPTION
388 fillListWithLeaf(listStreamSchemaNode, streamNodeValues, RestconfMappingNodeConstants.DESCRIPTION,
389 RestconfMappingStreamConstants.DESCRIPTION);
391 // STREAM REPLAY_SUPPORT
392 fillListWithLeaf(listStreamSchemaNode, streamNodeValues, RestconfMappingNodeConstants.REPLAY_SUPPORT,
393 RestconfMappingStreamConstants.REPLAY_SUPPORT);
396 fillListWithLeaf(listStreamSchemaNode, streamNodeValues, RestconfMappingNodeConstants.REPLAY_LOG,
397 RestconfMappingStreamConstants.REPLAY_LOG);
400 fillListWithLeaf(listStreamSchemaNode, streamNodeValues, RestconfMappingNodeConstants.EVENTS,
401 RestconfMappingStreamConstants.EVENTS);
403 return streamNodeValues.build();
407 * Method for filling {@link ListSchemaNode} with {@link LeafSchemaNode}
409 * @param listStreamSchemaNode
410 * - {@link ListSchemaNode}
411 * @param streamNodeValues
412 * - filled {@link DataContainerNodeAttrBuilder}
413 * @param nameSchemaNode
414 * - name of mapped leaf
416 * - value for mapped node
418 private static void fillListWithLeaf(
419 final ListSchemaNode listStreamSchemaNode,
420 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> streamNodeValues,
421 final String nameSchemaNode, final Object value) {
422 final DataSchemaNode schemaNode = RestconfSchemaUtil
423 .findSchemaNodeInCollection(listStreamSchemaNode.getChildNodes(), nameSchemaNode);
424 Preconditions.checkState(schemaNode instanceof LeafSchemaNode);
425 streamNodeValues.withChild(Builders.leafBuilder((LeafSchemaNode) schemaNode).withValue(value).build());
429 * Map capabilites by ietf-restconf-monitoring
431 * @param monitoringModule
432 * - ietf-restconf-monitoring module
433 * @return mapped capabilites
435 public static NormalizedNode<NodeIdentifier, Collection<DataContainerChild<? extends PathArgument, ?>>>
436 mapCapabilites(final Module monitoringModule) {
437 final DataSchemaNode restconfState =
438 monitoringModule.getDataChildByName(MonitoringModule.CONT_RESTCONF_STATE_QNAME);
439 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> restStateContBuilder =
440 Builders.containerBuilder((ContainerSchemaNode) restconfState);
441 final DataSchemaNode capabilitesContSchema =
442 getChildOfCont((ContainerSchemaNode) restconfState, MonitoringModule.CONT_CAPABILITES_QNAME);
443 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> capabilitesContBuilder =
444 Builders.containerBuilder((ContainerSchemaNode) capabilitesContSchema);
445 final DataSchemaNode leafListCapa = getChildOfCont((ContainerSchemaNode) capabilitesContSchema,
446 MonitoringModule.LEAF_LIST_CAPABILITY_QNAME);
447 final ListNodeBuilder<Object, LeafSetEntryNode<Object>> leafListCapaBuilder =
448 Builders.orderedLeafSetBuilder((LeafListSchemaNode) leafListCapa);
449 fillLeafListCapa(leafListCapaBuilder, (LeafListSchemaNode) leafListCapa);
451 return restStateContBuilder.withChild(capabilitesContBuilder.withChild(leafListCapaBuilder.build()).build())
456 * Map data to leaf-list
459 * - builder of parent for children
460 * @param leafListSchema
462 @SuppressWarnings("unchecked")
463 private static void fillLeafListCapa(final ListNodeBuilder builder, final LeafListSchemaNode leafListSchema) {
464 builder.withChild(leafListEntryBuild(leafListSchema, QueryParams.DEPTH));
465 builder.withChild(leafListEntryBuild(leafListSchema, QueryParams.FIELDS));
466 builder.withChild(leafListEntryBuild(leafListSchema, QueryParams.FILTER));
467 builder.withChild(leafListEntryBuild(leafListSchema, QueryParams.REPLAY));
468 builder.withChild(leafListEntryBuild(leafListSchema, QueryParams.WITH_DEFAULTS));
472 * Map value to leaf list entry node
474 * @param leafListSchema
475 * - leaf list schema of leaf list entry
477 * - value of leaf entry
480 @SuppressWarnings("rawtypes")
481 private static LeafSetEntryNode leafListEntryBuild(final LeafListSchemaNode leafListSchema, final String value) {
482 return Builders.leafSetEntryBuilder(leafListSchema).withValue(value).build();
486 * Find specific schema node by qname in parent {@link ContainerSchemaNode}
491 * - specific qname of child
492 * @return schema node of child by qname
494 private static DataSchemaNode getChildOfCont(final ContainerSchemaNode parent, final QName childQName) {
495 for (final DataSchemaNode child : parent.getChildNodes()) {
496 if (child.getQName().equals(childQName)) {
500 throw new RestconfDocumentedException(
501 childQName.getLocalName() + " doesn't exist in container " + MonitoringModule.CONT_RESTCONF_STATE_NAME);