+
+
+ /**
+ * Map data from modules to {@link NormalizedNode}.
+ *
+ * @param modules modules for mapping
+ * @param context schema context
+ * @param moduleSetId module-set-id of actual set
+ * @return mapped data as {@link NormalizedNode}
+ */
+ @VisibleForTesting
+ public static ContainerNode mapModulesByIetfYangLibraryYang(final Collection<? extends Module> modules,
+ final SchemaContext context, final String moduleSetId) {
+ final CollectionNodeBuilder<MapEntryNode, UserMapNode> mapBuilder = Builders.orderedMapBuilder()
+ .withNodeIdentifier(new NodeIdentifier(IetfYangLibrary.MODULE_QNAME_LIST));
+ for (final Module module : context.getModules()) {
+ fillMapByModules(mapBuilder, IetfYangLibrary.MODULE_QNAME_LIST, false, module, context);
+ }
+ return Builders.containerBuilder()
+ .withNodeIdentifier(new NodeIdentifier(ModulesState.QNAME))
+ .withChild(ImmutableNodes.leafNode(IetfYangLibrary.MODULE_SET_ID_LEAF_QNAME, moduleSetId))
+ .withChild(mapBuilder.build()).build();
+ }
+
+
+ /**
+ * Map data by the specific module or submodule.
+ *
+ * @param mapBuilder ordered list builder for children
+ * @param mapQName QName corresponding to the list builder
+ * @param isSubmodule true if module is specified as submodule, false otherwise
+ * @param module specific module or submodule
+ * @param context schema context
+ */
+ private static void fillMapByModules(final CollectionNodeBuilder<MapEntryNode, UserMapNode> mapBuilder,
+ final QName mapQName, final boolean isSubmodule, final ModuleLike module, final SchemaContext context) {
+ final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder =
+ newCommonLeafsMapEntryBuilder(mapQName, module);
+
+ mapEntryBuilder.withChild(ImmutableNodes.leafNode(IetfYangLibrary.SPECIFIC_MODULE_SCHEMA_LEAF_QNAME,
+ IetfYangLibrary.BASE_URI_OF_SCHEMA + module.getName() + "/"
+ // FIXME: orElse(null) does not seem appropriate here
+ + module.getQNameModule().getRevision().map(Revision::toString).orElse(null)));
+
+ if (!isSubmodule) {
+ mapEntryBuilder.withChild(ImmutableNodes.leafNode(IetfYangLibrary.SPECIFIC_MODULE_NAMESPACE_LEAF_QNAME,
+ module.getNamespace().toString()));
+
+ // features - not mandatory
+ if (module.getFeatures() != null && !module.getFeatures().isEmpty()) {
+ addFeatureLeafList(mapEntryBuilder, module.getFeatures());
+ }
+ // deviations - not mandatory
+ final ConformanceType conformance;
+ if (module.getDeviations() != null && !module.getDeviations().isEmpty()) {
+ addDeviationList(module, mapEntryBuilder, context);
+ conformance = ConformanceType.Implement;
+ } else {
+ conformance = ConformanceType.Import;
+ }
+ mapEntryBuilder.withChild(
+ ImmutableNodes.leafNode(IetfYangLibrary.SPECIFIC_MODULE_CONFORMANCE_LEAF_QNAME, conformance.getName()));
+
+ // submodules - not mandatory
+ if (module.getSubmodules() != null && !module.getSubmodules().isEmpty()) {
+ addSubmodules(module, mapEntryBuilder, context);
+ }
+ }
+ mapBuilder.withChild(mapEntryBuilder.build());
+ }
+
+ /**
+ * Mapping submodules of specific module.
+ *
+ * @param module module with submodules
+ * @param mapEntryBuilder mapEntryBuilder of parent for mapping children
+ * @param ietfYangLibraryModule ietf-yang-library module
+ * @param context schema context
+ */
+ private static void addSubmodules(final ModuleLike module,
+ final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder,
+ final SchemaContext context) {
+ final CollectionNodeBuilder<MapEntryNode, UserMapNode> mapBuilder = Builders.orderedMapBuilder()
+ .withNodeIdentifier(new NodeIdentifier(IetfYangLibrary.SPECIFIC_MODULE_SUBMODULE_LIST_QNAME));
+
+ for (final Submodule submodule : module.getSubmodules()) {
+ fillMapByModules(mapBuilder, IetfYangLibrary.SPECIFIC_MODULE_SUBMODULE_LIST_QNAME, true, submodule,
+ context);
+ }
+ mapEntryBuilder.withChild(mapBuilder.build());
+ }
+
+ /**
+ * Mapping deviations of specific module.
+ *
+ * @param module
+ * module with deviations
+ * @param mapEntryBuilder
+ * mapEntryBuilder of parent for mapping children
+ * @param context
+ * schema context
+ */
+ private static void addDeviationList(final ModuleLike module,
+ final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder,
+ final SchemaContext context) {
+ final CollectionNodeBuilder<MapEntryNode, SystemMapNode> deviations = Builders.mapBuilder()
+ .withNodeIdentifier(new NodeIdentifier(IetfYangLibrary.SPECIFIC_MODULE_DEVIATION_LIST_QNAME));
+ for (final Deviation deviation : module.getDeviations()) {
+ final List<QName> ids = deviation.getTargetPath().getNodeIdentifiers();
+ final QName lastComponent = ids.get(ids.size() - 1);
+
+ deviations.withChild(newCommonLeafsMapEntryBuilder(IetfYangLibrary.SPECIFIC_MODULE_DEVIATION_LIST_QNAME,
+ context.findModule(lastComponent.getModule()).get())
+ .build());
+ }
+ mapEntryBuilder.withChild(deviations.build());
+ }
+
+ /**
+ * Mapping features of specific module.
+ *
+ * @param mapEntryBuilder mapEntryBuilder of parent for mapping children
+ * @param features features of specific module
+ */
+ private static void addFeatureLeafList(
+ final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder,
+ final Collection<? extends FeatureDefinition> features) {
+ final ListNodeBuilder<String, SystemLeafSetNode<String>> leafSetBuilder = Builders.<String>leafSetBuilder()
+ .withNodeIdentifier(new NodeIdentifier(IetfYangLibrary.SPECIFIC_MODULE_FEATURE_LEAF_LIST_QNAME));
+ for (final FeatureDefinition feature : features) {
+ leafSetBuilder.withChildValue(feature.getQName().getLocalName());
+ }
+ mapEntryBuilder.withChild(leafSetBuilder.build());
+ }
+
+ private static DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> newCommonLeafsMapEntryBuilder(
+ final QName qname, final ModuleLike module) {
+ final var name = module.getName();
+ final var revision = module.getQNameModule().getRevision().map(Revision::toString).orElse("");
+ return Builders.mapEntryBuilder()
+ .withNodeIdentifier(NodeIdentifierWithPredicates.of(qname, Map.of(
+ IetfYangLibrary.SPECIFIC_MODULE_NAME_LEAF_QNAME, name,
+ IetfYangLibrary.SPECIFIC_MODULE_REVISION_LEAF_QNAME, revision)))
+ .withChild(ImmutableNodes.leafNode(IetfYangLibrary.SPECIFIC_MODULE_NAME_LEAF_QNAME, name))
+ .withChild(ImmutableNodes.leafNode(IetfYangLibrary.SPECIFIC_MODULE_REVISION_LEAF_QNAME, revision));
+ }