X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=restconf%2Frestconf-nb-rfc8040%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Frestconf%2Fnb%2Frfc8040%2Frests%2Futils%2FReadDataTransactionUtil.java;h=f8bfacc34d0770ed479e5dbea2cbc650d8e5c91d;hb=4f8fe6ca68115fecdb9ce43573af5a2e26c50b50;hp=a309c035527f320ecdb6b62328f1010d781f3a05;hpb=b7537d2482ffb05582749ce80a7ca44c64a5ad6c;p=netconf.git diff --git a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/utils/ReadDataTransactionUtil.java b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/utils/ReadDataTransactionUtil.java index a309c03552..f8bfacc34d 100644 --- a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/utils/ReadDataTransactionUtil.java +++ b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/utils/ReadDataTransactionUtil.java @@ -7,37 +7,35 @@ */ package org.opendaylight.restconf.nb.rfc8040.rests.utils; -import static org.opendaylight.restconf.nb.rfc8040.rests.utils.RestconfStreamsConstants.STREAMS_PATH; -import static org.opendaylight.restconf.nb.rfc8040.rests.utils.RestconfStreamsConstants.STREAM_PATH_PART; +import static org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserFieldsParameter.parseFieldsParameter; +import static org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserFieldsParameter.parseFieldsPaths; -import com.google.common.collect.Iterables; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.Sets; import com.google.common.primitives.Ints; -import com.google.common.util.concurrent.FluentFuture; -import java.net.URI; +import com.google.common.util.concurrent.ListenableFuture; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import javax.ws.rs.core.UriInfo; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; import org.opendaylight.mdsal.common.api.LogicalDatastoreType; -import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction; -import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction; +import org.opendaylight.mdsal.dom.api.DOMTransactionChain; import org.opendaylight.restconf.common.context.InstanceIdentifierContext; import org.opendaylight.restconf.common.context.WriterParameters; import org.opendaylight.restconf.common.context.WriterParameters.WriterParametersBuilder; import org.opendaylight.restconf.common.errors.RestconfDocumentedException; import org.opendaylight.restconf.common.errors.RestconfError; -import org.opendaylight.restconf.nb.rfc8040.references.SchemaContextRef; -import org.opendaylight.restconf.nb.rfc8040.rests.transactions.TransactionVarsWrapper; -import org.opendaylight.restconf.nb.rfc8040.streams.listeners.NotificationListenerAdapter; -import org.opendaylight.restconf.nb.rfc8040.utils.mapping.RestconfMappingNodeUtil; -import org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserFieldsParameter; -import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.NotificationOutputTypeGrouping.NotificationOutputType; +import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag; +import org.opendaylight.restconf.common.errors.RestconfError.ErrorType; +import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy; +import org.opendaylight.restconf.nb.rfc8040.rests.utils.RestconfDataServiceConstant.ReadData.WithDefaults; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.QNameModule; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; @@ -55,26 +53,27 @@ import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode; import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; import org.opendaylight.yangtools.yang.data.api.schema.MapNode; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.data.api.schema.OrderedLeafSetNode; -import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode; +import org.opendaylight.yangtools.yang.data.api.schema.SystemLeafSetNode; +import org.opendaylight.yangtools.yang.data.api.schema.SystemMapNode; import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode; import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode; +import org.opendaylight.yangtools.yang.data.api.schema.UserLeafSetNode; +import org.opendaylight.yangtools.yang.data.api.schema.UserMapNode; +import org.opendaylight.yangtools.yang.data.api.schema.builder.CollectionNodeBuilder; +import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder; +import org.opendaylight.yangtools.yang.data.api.schema.builder.ListNodeBuilder; +import org.opendaylight.yangtools.yang.data.api.schema.builder.NormalizedNodeBuilder; +import org.opendaylight.yangtools.yang.data.api.schema.builder.NormalizedNodeContainerBuilder; import org.opendaylight.yangtools.yang.data.impl.schema.Builders; import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; -import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder; -import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder; -import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder; -import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder; -import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder; -import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.SchemaAwareBuilders; import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree; import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; -import org.opendaylight.yangtools.yang.model.api.NotificationDefinition; import org.opendaylight.yangtools.yang.model.api.RpcDefinition; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; /** * Util class for read data from data store via transaction. @@ -83,9 +82,9 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContext; *
  • state *
  • all (config + state) * - * */ public final class ReadDataTransactionUtil { + private static final String READ_TYPE_TX = "READ"; private ReadDataTransactionUtil() { throw new UnsupportedOperationException("Util class."); @@ -94,50 +93,20 @@ public final class ReadDataTransactionUtil { /** * Parse parameters from URI request and check their types and values. * - * - * @param identifier - * {@link InstanceIdentifierContext} - * @param uriInfo - * URI info - * @param tagged - * set tagged for {@link WriterParameters} - * @return {@link WriterParameters} - */ - @Nonnull - public static WriterParameters parseUriParameters(@Nonnull final InstanceIdentifierContext identifier, - @Nullable final UriInfo uriInfo, final boolean tagged) { - return parseParams(identifier, uriInfo, tagged); - } - - /** - * Parse parameters from URI request and check their types and values. - * - * - * @param identifier - * {@link InstanceIdentifierContext} - * @param uriInfo - * URI info + * @param identifier {@link InstanceIdentifierContext} + * @param uriInfo URI info * @return {@link WriterParameters} */ - @Nonnull - public static WriterParameters parseUriParameters(@Nonnull final InstanceIdentifierContext identifier, - @Nullable final UriInfo uriInfo) { - return parseParams(identifier, uriInfo, false); - } - - private static WriterParameters parseParams(final InstanceIdentifierContext identifier, final UriInfo uriInfo, - final boolean tagged) { + public static WriterParameters parseUriParameters(final InstanceIdentifierContext identifier, + final UriInfo uriInfo) { final WriterParametersBuilder builder = new WriterParametersBuilder(); - builder.setTagged(tagged); if (uriInfo == null) { return builder.build(); } // check only allowed parameters - ParametersUtil.checkParametersTypes( - RestconfDataServiceConstant.ReadData.READ_TYPE_TX, - uriInfo.getQueryParameters().keySet(), + checkParametersTypes(uriInfo.getQueryParameters().keySet(), RestconfDataServiceConstant.ReadData.CONTENT, RestconfDataServiceConstant.ReadData.DEPTH, RestconfDataServiceConstant.ReadData.FIELDS, RestconfDataServiceConstant.ReadData.WITH_DEFAULTS); @@ -149,15 +118,19 @@ public final class ReadDataTransactionUtil { final List depth = uriInfo.getQueryParameters().getOrDefault( RestconfDataServiceConstant.ReadData.DEPTH, Collections.singletonList(RestconfDataServiceConstant.ReadData.UNBOUNDED)); + final List withDefaults = uriInfo.getQueryParameters().getOrDefault( + RestconfDataServiceConstant.ReadData.WITH_DEFAULTS, + Collections.emptyList()); // fields final List fields = uriInfo.getQueryParameters().getOrDefault( RestconfDataServiceConstant.ReadData.FIELDS, Collections.emptyList()); // parameter can be in URI at most once - ParametersUtil.checkParameterCount(content, RestconfDataServiceConstant.ReadData.CONTENT); - ParametersUtil.checkParameterCount(depth, RestconfDataServiceConstant.ReadData.DEPTH); - ParametersUtil.checkParameterCount(fields, RestconfDataServiceConstant.ReadData.FIELDS); + checkParameterCount(content, RestconfDataServiceConstant.ReadData.CONTENT); + checkParameterCount(depth, RestconfDataServiceConstant.ReadData.DEPTH); + checkParameterCount(fields, RestconfDataServiceConstant.ReadData.FIELDS); + checkParameterCount(fields, RestconfDataServiceConstant.ReadData.WITH_DEFAULTS); // check and set content final String contentValue = content.get(0); @@ -177,9 +150,8 @@ public final class ReadDataTransactionUtil { if (!depth.get(0).equals(RestconfDataServiceConstant.ReadData.UNBOUNDED)) { final Integer value = Ints.tryParse(depth.get(0)); - if (value == null - || !(value >= RestconfDataServiceConstant.ReadData.MIN_DEPTH - && value <= RestconfDataServiceConstant.ReadData.MAX_DEPTH)) { + if (value == null || value < RestconfDataServiceConstant.ReadData.MIN_DEPTH + || value > RestconfDataServiceConstant.ReadData.MAX_DEPTH) { throw new RestconfDocumentedException( new RestconfError(RestconfError.ErrorType.PROTOCOL, RestconfError.ErrorTag.INVALID_VALUE, "Invalid depth parameter: " + depth, null, @@ -191,61 +163,64 @@ public final class ReadDataTransactionUtil { // check and set fields if (!fields.isEmpty()) { - builder.setFields(ParserFieldsParameter.parseFieldsParameter(identifier, fields.get(0))); + if (identifier.getMountPoint() != null) { + builder.setFieldPaths(parseFieldsPaths(identifier, fields.get(0))); + } else { + builder.setFields(parseFieldsParameter(identifier, fields.get(0))); + } } - return builder.build(); - } + // check and set withDefaults parameter + if (!withDefaults.isEmpty()) { + final String str = withDefaults.get(0); + final WithDefaults val = WithDefaults.forValue(str); + if (val == null) { + throw new RestconfDocumentedException(new RestconfError(RestconfError.ErrorType.PROTOCOL, + RestconfError.ErrorTag.INVALID_VALUE, "Invalid with-defaults parameter: " + str, null, + "The with-defaults parameter must be a string in " + WithDefaults.possibleValues())); + } - /** - * Read specific type of data from data store via transaction. - * - * @param valueOfContent - * type of data to read (config, state, all) - * @param transactionNode - * {@link TransactionVarsWrapper} - wrapper for variables - * @param schemaContext - * schema context - * @return {@link NormalizedNode} - */ - @Nullable - public static NormalizedNode readData(@Nonnull final String valueOfContent, - @Nonnull final TransactionVarsWrapper transactionNode, final SchemaContext schemaContext) { - return readData(valueOfContent, transactionNode, null, schemaContext); + switch (val) { + case REPORT_ALL: + break; + case REPORT_ALL_TAGGED: + builder.setTagged(true); + break; + default: + builder.setWithDefault(val.value()); + } + } + return builder.build(); } /** - * Read specific type of data from data store via transaction. + * Read specific type of data from data store via transaction. Close {@link DOMTransactionChain} if any + * inside of object {@link RestconfStrategy} provided as a parameter. * - * @param valueOfContent - * type of data to read (config, state, all) - * @param transactionNode - * {@link TransactionVarsWrapper} - wrapper for variables - * @param withDefa - * vaule of with-defaults parameter - * @param ctx - * schema context + * @param valueOfContent type of data to read (config, state, all) + * @param path the path to read + * @param strategy {@link RestconfStrategy} - object that perform the actual DS operations + * @param withDefa value of with-defaults parameter + * @param ctx schema context * @return {@link NormalizedNode} */ - @Nullable - public static NormalizedNode readData(@Nonnull final String valueOfContent, - @Nonnull final TransactionVarsWrapper transactionNode, final String withDefa, final SchemaContext ctx) { + public static @Nullable NormalizedNode readData(final @NonNull String valueOfContent, + final @NonNull YangInstanceIdentifier path, + final @NonNull RestconfStrategy strategy, + final String withDefa, final EffectiveModelContext ctx) { switch (valueOfContent) { case RestconfDataServiceConstant.ReadData.CONFIG: - transactionNode.setLogicalDatastoreType(LogicalDatastoreType.CONFIGURATION); if (withDefa == null) { - return readDataViaTransaction(transactionNode); + return readDataViaTransaction(strategy, LogicalDatastoreType.CONFIGURATION, path, true); } else { - return prepareDataByParamWithDef(readDataViaTransaction(transactionNode), - transactionNode.getInstanceIdentifier().getInstanceIdentifier(), withDefa, ctx); + return prepareDataByParamWithDef( + readDataViaTransaction(strategy, LogicalDatastoreType.CONFIGURATION, path, true), + path, withDefa, ctx); } case RestconfDataServiceConstant.ReadData.NONCONFIG: - transactionNode.setLogicalDatastoreType(LogicalDatastoreType.OPERATIONAL); - return readDataViaTransaction(transactionNode); - + return readDataViaTransaction(strategy, LogicalDatastoreType.OPERATIONAL, path, true); case RestconfDataServiceConstant.ReadData.ALL: - return readAllData(transactionNode, withDefa, ctx); - + return readAllData(strategy, path, withDefa, ctx); default: throw new RestconfDocumentedException( new RestconfError(RestconfError.ErrorType.PROTOCOL, RestconfError.ErrorTag.INVALID_VALUE, @@ -255,57 +230,79 @@ public final class ReadDataTransactionUtil { } /** - * Read specific type of data from data store via transaction and if identifier read data from - * streams then put streams from actual schema context to datastore. + * Read specific type of data from data store via transaction with specified subtrees that should only be read. + * Close {@link DOMTransactionChain} inside of object {@link RestconfStrategy} provided as a parameter. * - * @param identifier - * identifier of data to read - * @param content - * type of data to read (config, state, all) - * @param transactionNode - * {@link TransactionVarsWrapper} - wrapper for variables - * @param withDefa - * vaule of with-defaults parameter - * @param schemaContextRef - * schema context - * @param uriInfo - * uri info + * @param valueOfContent type of data to read (config, state, all) + * @param path the parent path to read + * @param strategy {@link RestconfStrategy} - object that perform the actual DS operations + * @param withDefa value of with-defaults parameter + * @param ctx schema context + * @param fields paths to selected subtrees which should be read, relative to to the parent path * @return {@link NormalizedNode} */ - public static NormalizedNode readData(final String identifier, final String content, - final TransactionVarsWrapper transactionNode, final String withDefa, - final SchemaContextRef schemaContextRef, final UriInfo uriInfo) { - final SchemaContext schemaContext = schemaContextRef.get(); - if (identifier.contains(STREAMS_PATH) && !identifier.contains(STREAM_PATH_PART)) { - final DOMDataTreeReadWriteTransaction wTx = transactionNode.getTransactionChain().newReadWriteTransaction(); - final boolean exist = SubscribeToStreamUtil.checkExist(schemaContext, wTx); - - for (final NotificationDefinition notificationDefinition : schemaContextRef.get().getNotifications()) { - final List notifiStreamXML = - CreateStreamUtil.createYangNotifiStream(notificationDefinition, schemaContextRef, - NotificationOutputType.XML.getName()); - final List notifiStreamJSON = - CreateStreamUtil.createYangNotifiStream(notificationDefinition, schemaContextRef, - NotificationOutputType.JSON.getName()); - for (final NotificationListenerAdapter listener : Iterables.concat(notifiStreamXML, notifiStreamJSON)) { - final URI uri = SubscribeToStreamUtil.prepareUriByStreamName(uriInfo, listener.getStreamName()); - final NormalizedNode mapToStreams = - RestconfMappingNodeUtil.mapYangNotificationStreamByIetfRestconfMonitoring( - listener.getSchemaPath().getLastComponent(), schemaContext.getNotifications(), - null, listener.getOutputType(), uri, - SubscribeToStreamUtil.getMonitoringModule(schemaContext), exist); - SubscribeToStreamUtil.writeDataToDS(schemaContext, - listener.getSchemaPath().getLastComponent().getLocalName(), wTx, exist, - mapToStreams); + public static @Nullable NormalizedNode readData(final @NonNull String valueOfContent, + final @NonNull YangInstanceIdentifier path, final @NonNull RestconfStrategy strategy, + final @Nullable String withDefa, @NonNull final EffectiveModelContext ctx, + final @NonNull List fields) { + switch (valueOfContent) { + case RestconfDataServiceConstant.ReadData.CONFIG: + if (withDefa == null) { + return readDataViaTransaction(strategy, LogicalDatastoreType.CONFIGURATION, path, true, fields); + } else { + return prepareDataByParamWithDef( + readDataViaTransaction(strategy, LogicalDatastoreType.CONFIGURATION, path, true, fields), + path, withDefa, ctx); } - } - SubscribeToStreamUtil.submitData(wTx); + case RestconfDataServiceConstant.ReadData.NONCONFIG: + return readDataViaTransaction(strategy, LogicalDatastoreType.OPERATIONAL, path, true, fields); + case RestconfDataServiceConstant.ReadData.ALL: + return readAllData(strategy, path, withDefa, ctx, fields); + default: + throw new RestconfDocumentedException(new RestconfError(RestconfError.ErrorType.PROTOCOL, + RestconfError.ErrorTag.INVALID_VALUE, "Invalid content parameter: " + valueOfContent, null, + "The content parameter value must be either config, nonconfig or all (default)")); } - return readData(content, transactionNode, withDefa, schemaContext); } - private static NormalizedNode prepareDataByParamWithDef(final NormalizedNode result, - final YangInstanceIdentifier path, final String withDefa, final SchemaContext ctx) { + /** + * Check if URI does not contain value for the same parameter more than once. + * + * @param parameterValues URI parameter values + * @param parameterName URI parameter name + */ + @VisibleForTesting + static void checkParameterCount(final @NonNull List parameterValues, final @NonNull String parameterName) { + if (parameterValues.size() > 1) { + throw new RestconfDocumentedException( + "Parameter " + parameterName + " can appear at most once in request URI", + ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE); + } + } + + /** + * Check if URI does not contain not allowed parameters for specified operation. + * + * @param usedParameters parameters used in URI request + * @param allowedParameters allowed parameters for operation + */ + @VisibleForTesting + static void checkParametersTypes(final @NonNull Set usedParameters, + final @NonNull String... allowedParameters) { + // FIXME: there should be a speedier way to do this + final Set notAllowedParameters = Sets.newHashSet(usedParameters); + notAllowedParameters.removeAll(Sets.newHashSet(allowedParameters)); + + if (!notAllowedParameters.isEmpty()) { + throw new RestconfDocumentedException( + "Not allowed parameters for " + READ_TYPE_TX + " operation: " + notAllowedParameters, + RestconfError.ErrorType.PROTOCOL, + RestconfError.ErrorTag.INVALID_VALUE); + } + } + + private static NormalizedNode prepareDataByParamWithDef(final NormalizedNode result, + final YangInstanceIdentifier path, final String withDefa, final EffectiveModelContext ctx) { boolean trim; switch (withDefa) { case "trim": @@ -319,15 +316,15 @@ public final class ReadDataTransactionUtil { } final DataSchemaContextTree baseSchemaCtxTree = DataSchemaContextTree.from(ctx); - final DataSchemaNode baseSchemaNode = baseSchemaCtxTree.getChild(path).getDataSchemaNode(); + final DataSchemaNode baseSchemaNode = baseSchemaCtxTree.findChild(path).orElseThrow().getDataSchemaNode(); if (result instanceof ContainerNode) { - final DataContainerNodeAttrBuilder builder = - Builders.containerBuilder((ContainerSchemaNode) baseSchemaNode); + final DataContainerNodeBuilder builder = + SchemaAwareBuilders.containerBuilder((ContainerSchemaNode) baseSchemaNode); buildCont(builder, (ContainerNode) result, baseSchemaCtxTree, path, trim); return builder.build(); } else { - final DataContainerNodeAttrBuilder builder = - Builders.mapEntryBuilder((ListSchemaNode) baseSchemaNode); + final DataContainerNodeBuilder builder = + SchemaAwareBuilders.mapEntryBuilder((ListSchemaNode) baseSchemaNode); buildMapEntryBuilder(builder, (MapEntryNode) result, baseSchemaCtxTree, path, trim, ((ListSchemaNode) baseSchemaNode).getKeyDefinition()); return builder.build(); @@ -335,40 +332,40 @@ public final class ReadDataTransactionUtil { } private static void buildMapEntryBuilder( - final DataContainerNodeAttrBuilder builder, + final DataContainerNodeBuilder builder, final MapEntryNode result, final DataSchemaContextTree baseSchemaCtxTree, final YangInstanceIdentifier actualPath, final boolean trim, final List keys) { - for (final DataContainerChild child : result.getValue()) { + for (final DataContainerChild child : result.body()) { final YangInstanceIdentifier path = actualPath.node(child.getIdentifier()); - final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode(); + final DataSchemaNode childSchema = baseSchemaCtxTree.findChild(path).orElseThrow().getDataSchemaNode(); if (child instanceof ContainerNode) { - final DataContainerNodeAttrBuilder childBuilder = - Builders.containerBuilder((ContainerSchemaNode) childSchema); + final DataContainerNodeBuilder childBuilder = + SchemaAwareBuilders.containerBuilder((ContainerSchemaNode) childSchema); buildCont(childBuilder, (ContainerNode) child, baseSchemaCtxTree, path, trim); builder.withChild(childBuilder.build()); } else if (child instanceof MapNode) { - final CollectionNodeBuilder childBuilder = - Builders.mapBuilder((ListSchemaNode) childSchema); + final CollectionNodeBuilder childBuilder = + SchemaAwareBuilders.mapBuilder((ListSchemaNode) childSchema); buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim, ((ListSchemaNode) childSchema).getKeyDefinition()); builder.withChild(childBuilder.build()); } else if (child instanceof LeafNode) { final Object defaultVal = ((LeafSchemaNode) childSchema).getType().getDefaultValue().orElse(null); - final Object nodeVal = child.getValue(); - final NormalizedNodeAttrBuilder> leafBuilder = - Builders.leafBuilder((LeafSchemaNode) childSchema); - if (keys.contains(child.getNodeType())) { - leafBuilder.withValue(((LeafNode) child).getValue()); + final Object nodeVal = child.body(); + final NormalizedNodeBuilder> leafBuilder = + SchemaAwareBuilders.leafBuilder((LeafSchemaNode) childSchema); + if (keys.contains(child.getIdentifier().getNodeType())) { + leafBuilder.withValue(((LeafNode) child).body()); builder.withChild(leafBuilder.build()); } else { if (trim) { if (defaultVal == null || !defaultVal.equals(nodeVal)) { - leafBuilder.withValue(((LeafNode) child).getValue()); + leafBuilder.withValue(((LeafNode) child).body()); builder.withChild(leafBuilder.build()); } } else { if (defaultVal != null && defaultVal.equals(nodeVal)) { - leafBuilder.withValue(((LeafNode) child).getValue()); + leafBuilder.withValue(((LeafNode) child).body()); builder.withChild(leafBuilder.build()); } } @@ -377,49 +374,50 @@ public final class ReadDataTransactionUtil { } } - private static void buildList(final CollectionNodeBuilder builder, final MapNode result, - final DataSchemaContextTree baseSchemaCtxTree, final YangInstanceIdentifier path, final boolean trim, - final List keys) { - for (final MapEntryNode mapEntryNode : result.getValue()) { + private static void buildList(final CollectionNodeBuilder builder, + final MapNode result, final DataSchemaContextTree baseSchemaCtxTree, final YangInstanceIdentifier path, + final boolean trim, final List keys) { + for (final MapEntryNode mapEntryNode : result.body()) { final YangInstanceIdentifier actualNode = path.node(mapEntryNode.getIdentifier()); - final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(actualNode).getDataSchemaNode(); - final DataContainerNodeAttrBuilder mapEntryBuilder = - Builders.mapEntryBuilder((ListSchemaNode) childSchema); + final DataSchemaNode childSchema = baseSchemaCtxTree.findChild(actualNode).orElseThrow() + .getDataSchemaNode(); + final DataContainerNodeBuilder mapEntryBuilder = + SchemaAwareBuilders.mapEntryBuilder((ListSchemaNode) childSchema); buildMapEntryBuilder(mapEntryBuilder, mapEntryNode, baseSchemaCtxTree, actualNode, trim, keys); builder.withChild(mapEntryBuilder.build()); } } - private static void buildCont(final DataContainerNodeAttrBuilder builder, + private static void buildCont(final DataContainerNodeBuilder builder, final ContainerNode result, final DataSchemaContextTree baseSchemaCtxTree, final YangInstanceIdentifier actualPath, final boolean trim) { - for (final DataContainerChild child : result.getValue()) { + for (final DataContainerChild child : result.body()) { final YangInstanceIdentifier path = actualPath.node(child.getIdentifier()); - final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode(); + final DataSchemaNode childSchema = baseSchemaCtxTree.findChild(path).orElseThrow().getDataSchemaNode(); if (child instanceof ContainerNode) { - final DataContainerNodeAttrBuilder builderChild = - Builders.containerBuilder((ContainerSchemaNode) childSchema); + final DataContainerNodeBuilder builderChild = + SchemaAwareBuilders.containerBuilder((ContainerSchemaNode) childSchema); buildCont(builderChild, result, baseSchemaCtxTree, actualPath, trim); builder.withChild(builderChild.build()); } else if (child instanceof MapNode) { - final CollectionNodeBuilder childBuilder = - Builders.mapBuilder((ListSchemaNode) childSchema); + final CollectionNodeBuilder childBuilder = + SchemaAwareBuilders.mapBuilder((ListSchemaNode) childSchema); buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim, ((ListSchemaNode) childSchema).getKeyDefinition()); builder.withChild(childBuilder.build()); } else if (child instanceof LeafNode) { final Object defaultVal = ((LeafSchemaNode) childSchema).getType().getDefaultValue().orElse(null); - final Object nodeVal = child.getValue(); - final NormalizedNodeAttrBuilder> leafBuilder = - Builders.leafBuilder((LeafSchemaNode) childSchema); + final Object nodeVal = child.body(); + final NormalizedNodeBuilder> leafBuilder = + SchemaAwareBuilders.leafBuilder((LeafSchemaNode) childSchema); if (trim) { if (defaultVal == null || !defaultVal.equals(nodeVal)) { - leafBuilder.withValue(((LeafNode) child).getValue()); + leafBuilder.withValue(((LeafNode) child).body()); builder.withChild(leafBuilder.build()); } } else { if (defaultVal != null && defaultVal.equals(nodeVal)) { - leafBuilder.withValue(((LeafNode) child).getValue()); + leafBuilder.withValue(((LeafNode) child).body()); builder.withChild(leafBuilder.build()); } } @@ -428,56 +426,117 @@ public final class ReadDataTransactionUtil { } /** - * If is set specific {@link LogicalDatastoreType} in - * {@link TransactionVarsWrapper}, then read this type of data from DS. If - * don't, we have to read all data from DS (state + config) + * If is set specific {@link LogicalDatastoreType} in {@link RestconfStrategy}, then read this type of data from DS. + * If don't, we have to read all data from DS (state + config) * - * @param transactionNode - * {@link TransactionVarsWrapper} - wrapper for variables + * @param strategy {@link RestconfStrategy} - object that perform the actual DS operations + * @param closeTransactionChain If is set to true, after transaction it will close transactionChain + * in {@link RestconfStrategy} if any * @return {@link NormalizedNode} */ - @Nullable - private static NormalizedNode readDataViaTransaction( - @Nonnull final TransactionVarsWrapper transactionNode) { + static @Nullable NormalizedNode readDataViaTransaction(final @NonNull RestconfStrategy strategy, + final LogicalDatastoreType store, final YangInstanceIdentifier path, + final boolean closeTransactionChain) { + final ListenableFuture> listenableFuture = strategy.read(store, path); + return extractReadData(strategy, path, closeTransactionChain, listenableFuture); + } + + /** + * Read specific type of data {@link LogicalDatastoreType} via transaction in {@link RestconfStrategy} with + * specified subtrees that should only be read. + * + * @param strategy {@link RestconfStrategy} - object that perform the actual DS operations + * @param store datastore type + * @param path parent path to selected fields + * @param closeTransactionChain if it is set to {@code true}, after transaction it will close transactionChain + * in {@link RestconfStrategy} if any + * @param fields paths to selected subtrees which should be read, relative to to the parent path + * @return {@link NormalizedNode} + */ + private static @Nullable NormalizedNode readDataViaTransaction(final @NonNull RestconfStrategy strategy, + final @NonNull LogicalDatastoreType store, final @NonNull YangInstanceIdentifier path, + final boolean closeTransactionChain, final @NonNull List fields) { + final ListenableFuture> listenableFuture = strategy.read(store, path, fields); + return extractReadData(strategy, path, closeTransactionChain, listenableFuture); + } + + private static NormalizedNode extractReadData(final RestconfStrategy strategy, + final YangInstanceIdentifier path, final boolean closeTransactionChain, + final ListenableFuture> dataFuture) { final NormalizedNodeFactory dataFactory = new NormalizedNodeFactory(); - try (DOMDataTreeReadTransaction tx = transactionNode.getTransactionChain().newReadOnlyTransaction()) { - final FluentFuture>> listenableFuture = tx.read( - transactionNode.getLogicalDatastoreType(), - transactionNode.getInstanceIdentifier().getInstanceIdentifier()); - FutureCallbackTx.addCallback(listenableFuture, RestconfDataServiceConstant.ReadData.READ_TYPE_TX, - dataFactory); + if (closeTransactionChain) { + //Method close transactionChain if any + FutureCallbackTx.addCallback(dataFuture, READ_TYPE_TX, dataFactory, strategy, path); + } else { + FutureCallbackTx.addCallback(dataFuture, READ_TYPE_TX, dataFactory); } return dataFactory.build(); } /** - * Read config and state data, then map them. + * Read config and state data, then map them. Close {@link DOMTransactionChain} inside of object + * {@link RestconfStrategy} provided as a parameter if any. * - * @param transactionNode - * {@link TransactionVarsWrapper} - wrapper for variables - * @param withDefa - * with-defaults parameter - * @param ctx - * schema context + * @param strategy {@link RestconfStrategy} - object that perform the actual DS operations + * @param withDefa with-defaults parameter + * @param ctx schema context * @return {@link NormalizedNode} */ - @Nullable - private static NormalizedNode readAllData(@Nonnull final TransactionVarsWrapper transactionNode, - final String withDefa, final SchemaContext ctx) { + private static @Nullable NormalizedNode readAllData(final @NonNull RestconfStrategy strategy, + final YangInstanceIdentifier path, final String withDefa, final EffectiveModelContext ctx) { // PREPARE STATE DATA NODE - transactionNode.setLogicalDatastoreType(LogicalDatastoreType.OPERATIONAL); - final NormalizedNode stateDataNode = readDataViaTransaction(transactionNode); + final NormalizedNode stateDataNode = readDataViaTransaction(strategy, LogicalDatastoreType.OPERATIONAL, path, + false); // PREPARE CONFIG DATA NODE - transactionNode.setLogicalDatastoreType(LogicalDatastoreType.CONFIGURATION); - final NormalizedNode configDataNode; + final NormalizedNode configDataNode; + //Here will be closed transactionChain if any if (withDefa == null) { - configDataNode = readDataViaTransaction(transactionNode); + configDataNode = readDataViaTransaction( + strategy, LogicalDatastoreType.CONFIGURATION, path, true); } else { - configDataNode = prepareDataByParamWithDef(readDataViaTransaction(transactionNode), - transactionNode.getInstanceIdentifier().getInstanceIdentifier(), withDefa, ctx); + configDataNode = prepareDataByParamWithDef( + readDataViaTransaction(strategy, LogicalDatastoreType.CONFIGURATION, path, true), + path, withDefa, ctx); } + return mergeConfigAndSTateDataIfNeeded(stateDataNode, configDataNode); + } + + /** + * Read config and state data with selected subtrees that should only be read, then map them. + * Close {@link DOMTransactionChain} inside of object {@link RestconfStrategy} provided as a parameter. + * + * @param strategy {@link RestconfStrategy} - object that perform the actual DS operations + * @param path parent path to selected fields + * @param withDefa with-defaults parameter + * @param ctx schema context + * @param fields paths to selected subtrees which should be read, relative to to the parent path + * @return {@link NormalizedNode} + */ + private static @Nullable NormalizedNode readAllData(final @NonNull RestconfStrategy strategy, + final @NonNull YangInstanceIdentifier path, final @Nullable String withDefa, + final @NonNull EffectiveModelContext ctx, final @NonNull List fields) { + // PREPARE STATE DATA NODE + final NormalizedNode stateDataNode = readDataViaTransaction(strategy, LogicalDatastoreType.OPERATIONAL, path, + false, fields); + + // PREPARE CONFIG DATA NODE + final NormalizedNode configDataNode; + //Here will be closed transactionChain if any + if (withDefa == null) { + configDataNode = readDataViaTransaction(strategy, LogicalDatastoreType.CONFIGURATION, path, true, fields); + } else { + configDataNode = prepareDataByParamWithDef( + readDataViaTransaction(strategy, LogicalDatastoreType.CONFIGURATION, path, true, fields), + path, withDefa, ctx); + } + + return mergeConfigAndSTateDataIfNeeded(stateDataNode, configDataNode); + } + + private static NormalizedNode mergeConfigAndSTateDataIfNeeded(final NormalizedNode stateDataNode, + final NormalizedNode configDataNode) { // if no data exists if (stateDataNode == null && configDataNode == null) { return null; @@ -494,22 +553,19 @@ public final class ReadDataTransactionUtil { } // merge data from config and state - return mapNode(stateDataNode, configDataNode); + return mergeStateAndConfigData(stateDataNode, configDataNode); } /** - * Map data by type of read node. + * Merge state and config data into a single NormalizedNode. * - * @param stateDataNode - * data node of state data - * @param configDataNode - * data node of config data + * @param stateDataNode data node of state data + * @param configDataNode data node of config data * @return {@link NormalizedNode} */ - @Nonnull - private static NormalizedNode mapNode(@Nonnull final NormalizedNode stateDataNode, - @Nonnull final NormalizedNode configDataNode) { - validPossibilityOfMergeNodes(stateDataNode, configDataNode); + private static @NonNull NormalizedNode mergeStateAndConfigData( + final @NonNull NormalizedNode stateDataNode, final @NonNull NormalizedNode configDataNode) { + validateNodeMerge(stateDataNode, configDataNode); if (configDataNode instanceof RpcDefinition) { return prepareRpcData(configDataNode, stateDataNode); } else { @@ -518,34 +574,29 @@ public final class ReadDataTransactionUtil { } /** - * Valid of can be data merged together. + * Validates whether the two NormalizedNodes can be merged. * - * @param stateDataNode - * data node of state data - * @param configDataNode - * data node of config data + * @param stateDataNode data node of state data + * @param configDataNode data node of config data */ - private static void validPossibilityOfMergeNodes(@Nonnull final NormalizedNode stateDataNode, - @Nonnull final NormalizedNode configDataNode) { + private static void validateNodeMerge(final @NonNull NormalizedNode stateDataNode, + final @NonNull NormalizedNode configDataNode) { final QNameModule moduleOfStateData = stateDataNode.getIdentifier().getNodeType().getModule(); final QNameModule moduleOfConfigData = configDataNode.getIdentifier().getNodeType().getModule(); - if (moduleOfStateData != moduleOfConfigData) { - throw new RestconfDocumentedException("It is not possible to merge "); + if (!moduleOfStateData.equals(moduleOfConfigData)) { + throw new RestconfDocumentedException("Unable to merge data from different modules."); } } /** * Prepare and map data for rpc. * - * @param configDataNode - * data node of config data - * @param stateDataNode - * data node of state data + * @param configDataNode data node of config data + * @param stateDataNode data node of state data * @return {@link NormalizedNode} */ - @Nonnull - private static NormalizedNode prepareRpcData(@Nonnull final NormalizedNode configDataNode, - @Nonnull final NormalizedNode stateDataNode) { + private static @NonNull NormalizedNode prepareRpcData(final @NonNull NormalizedNode configDataNode, + final @NonNull NormalizedNode stateDataNode) { final DataContainerNodeBuilder mapEntryBuilder = ImmutableNodes .mapEntryBuilder(); mapEntryBuilder.withNodeIdentifier((NodeIdentifierWithPredicates) configDataNode.getIdentifier()); @@ -555,50 +606,46 @@ public final class ReadDataTransactionUtil { // MAP STATE DATA mapRpcDataNode(stateDataNode, mapEntryBuilder); - return ImmutableNodes.mapNodeBuilder(configDataNode.getNodeType()).addChild(mapEntryBuilder.build()).build(); + return ImmutableNodes.mapNodeBuilder(configDataNode.getIdentifier().getNodeType()) + .addChild(mapEntryBuilder.build()) + .build(); } /** * Map node to map entry builder. * - * @param dataNode - * data node - * @param mapEntryBuilder - * builder for mapping data + * @param dataNode data node + * @param mapEntryBuilder builder for mapping data */ - private static void mapRpcDataNode(@Nonnull final NormalizedNode dataNode, - @Nonnull final DataContainerNodeBuilder< - NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder) { - ((ContainerNode) dataNode).getValue().forEach(mapEntryBuilder::addChild); + private static void mapRpcDataNode(final @NonNull NormalizedNode dataNode, + final @NonNull DataContainerNodeBuilder mapEntryBuilder) { + ((ContainerNode) dataNode).body().forEach(mapEntryBuilder::addChild); } /** * Prepare and map all data from DS. * - * @param configDataNode - * data node of config data - * @param stateDataNode - * data node of state data + * @param configDataNode data node of config data + * @param stateDataNode data node of state data * @return {@link NormalizedNode} */ @SuppressWarnings("unchecked") - @Nonnull - private static NormalizedNode prepareData(@Nonnull final NormalizedNode configDataNode, - @Nonnull final NormalizedNode stateDataNode) { - if (configDataNode instanceof OrderedMapNode) { - final CollectionNodeBuilder builder = Builders + private static @NonNull NormalizedNode prepareData(final @NonNull NormalizedNode configDataNode, + final @NonNull NormalizedNode stateDataNode) { + if (configDataNode instanceof UserMapNode) { + final CollectionNodeBuilder builder = Builders .orderedMapBuilder().withNodeIdentifier(((MapNode) configDataNode).getIdentifier()); mapValueToBuilder( - ((OrderedMapNode) configDataNode).getValue(), ((OrderedMapNode) stateDataNode).getValue(), builder); + ((UserMapNode) configDataNode).body(), ((UserMapNode) stateDataNode).body(), builder); return builder.build(); } else if (configDataNode instanceof MapNode) { - final CollectionNodeBuilder builder = ImmutableNodes + final CollectionNodeBuilder builder = ImmutableNodes .mapNodeBuilder().withNodeIdentifier(((MapNode) configDataNode).getIdentifier()); mapValueToBuilder( - ((MapNode) configDataNode).getValue(), ((MapNode) stateDataNode).getValue(), builder); + ((MapNode) configDataNode).body(), ((MapNode) stateDataNode).body(), builder); return builder.build(); } else if (configDataNode instanceof MapEntryNode) { @@ -606,23 +653,23 @@ public final class ReadDataTransactionUtil { .mapEntryBuilder().withNodeIdentifier(((MapEntryNode) configDataNode).getIdentifier()); mapValueToBuilder( - ((MapEntryNode) configDataNode).getValue(), ((MapEntryNode) stateDataNode).getValue(), builder); + ((MapEntryNode) configDataNode).body(), ((MapEntryNode) stateDataNode).body(), builder); return builder.build(); } else if (configDataNode instanceof ContainerNode) { - final DataContainerNodeAttrBuilder builder = Builders + final DataContainerNodeBuilder builder = Builders .containerBuilder().withNodeIdentifier(((ContainerNode) configDataNode).getIdentifier()); mapValueToBuilder( - ((ContainerNode) configDataNode).getValue(), ((ContainerNode) stateDataNode).getValue(), builder); + ((ContainerNode) configDataNode).body(), ((ContainerNode) stateDataNode).body(), builder); return builder.build(); } else if (configDataNode instanceof AugmentationNode) { final DataContainerNodeBuilder builder = Builders .augmentationBuilder().withNodeIdentifier(((AugmentationNode) configDataNode).getIdentifier()); - mapValueToBuilder(((AugmentationNode) configDataNode).getValue(), - ((AugmentationNode) stateDataNode).getValue(), builder); + mapValueToBuilder(((AugmentationNode) configDataNode).body(), + ((AugmentationNode) stateDataNode).body(), builder); return builder.build(); } else if (configDataNode instanceof ChoiceNode) { @@ -630,38 +677,43 @@ public final class ReadDataTransactionUtil { .choiceBuilder().withNodeIdentifier(((ChoiceNode) configDataNode).getIdentifier()); mapValueToBuilder( - ((ChoiceNode) configDataNode).getValue(), ((ChoiceNode) stateDataNode).getValue(), builder); + ((ChoiceNode) configDataNode).body(), ((ChoiceNode) stateDataNode).body(), builder); return builder.build(); } else if (configDataNode instanceof LeafNode) { - return ImmutableNodes.leafNode(configDataNode.getNodeType(), configDataNode.getValue()); - } else if (configDataNode instanceof OrderedLeafSetNode) { - final ListNodeBuilder> builder = Builders - .orderedLeafSetBuilder().withNodeIdentifier(((OrderedLeafSetNode) configDataNode).getIdentifier()); + return ImmutableNodes.leafNode(configDataNode.getIdentifier().getNodeType(), configDataNode.body()); + } else if (configDataNode instanceof UserLeafSetNode) { + final ListNodeBuilder> builder = Builders + .orderedLeafSetBuilder().withNodeIdentifier(((UserLeafSetNode) configDataNode).getIdentifier()); - mapValueToBuilder(((OrderedLeafSetNode) configDataNode).getValue(), - ((OrderedLeafSetNode) stateDataNode).getValue(), builder); + mapValueToBuilder(((UserLeafSetNode) configDataNode).body(), + ((UserLeafSetNode) stateDataNode).body(), builder); return builder.build(); } else if (configDataNode instanceof LeafSetNode) { - final ListNodeBuilder> builder = Builders + final ListNodeBuilder> builder = Builders .leafSetBuilder().withNodeIdentifier(((LeafSetNode) configDataNode).getIdentifier()); - mapValueToBuilder(((LeafSetNode) configDataNode).getValue(), - ((LeafSetNode) stateDataNode).getValue(), builder); + mapValueToBuilder(((LeafSetNode) configDataNode).body(), + ((LeafSetNode) stateDataNode).body(), builder); return builder.build(); + } else if (configDataNode instanceof LeafSetEntryNode) { + return Builders.leafSetEntryBuilder() + .withNodeIdentifier(((LeafSetEntryNode) configDataNode).getIdentifier()) + .withValue(configDataNode.body()) + .build(); } else if (configDataNode instanceof UnkeyedListNode) { final CollectionNodeBuilder builder = Builders .unkeyedListBuilder().withNodeIdentifier(((UnkeyedListNode) configDataNode).getIdentifier()); - mapValueToBuilder(((UnkeyedListNode) configDataNode).getValue(), - ((UnkeyedListNode) stateDataNode).getValue(), builder); + mapValueToBuilder(((UnkeyedListNode) configDataNode).body(), + ((UnkeyedListNode) stateDataNode).body(), builder); return builder.build(); } else if (configDataNode instanceof UnkeyedListEntryNode) { - final DataContainerNodeAttrBuilder builder = Builders + final DataContainerNodeBuilder builder = Builders .unkeyedListEntryBuilder().withNodeIdentifier(((UnkeyedListEntryNode) configDataNode).getIdentifier()); - mapValueToBuilder(((UnkeyedListEntryNode) configDataNode).getValue(), - ((UnkeyedListEntryNode) stateDataNode).getValue(), builder); + mapValueToBuilder(((UnkeyedListEntryNode) configDataNode).body(), + ((UnkeyedListEntryNode) stateDataNode).body(), builder); return builder.build(); } else { throw new RestconfDocumentedException("Unexpected node type: " + configDataNode.getClass().getName()); @@ -671,17 +723,13 @@ public final class ReadDataTransactionUtil { /** * Map value from container node to builder. * - * @param configData - * collection of config data nodes - * @param stateData - * collection of state data nodes - * @param builder - * builder + * @param configData collection of config data nodes + * @param stateData collection of state data nodes + * @param builder builder */ - private static > void mapValueToBuilder( - @Nonnull final Collection configData, - @Nonnull final Collection stateData, - @Nonnull final NormalizedNodeContainerBuilder builder) { + private static void mapValueToBuilder( + final @NonNull Collection configData, final @NonNull Collection stateData, + final @NonNull NormalizedNodeContainerBuilder builder) { final Map configMap = configData.stream().collect( Collectors.toMap(NormalizedNode::getIdentifier, Function.identity())); final Map stateMap = stateData.stream().collect( @@ -698,17 +746,13 @@ public final class ReadDataTransactionUtil { * Map data with different identifiers to builder. Data with different identifiers can be just added * as childs to parent node. * - * @param configMap - * map of config data nodes - * @param stateMap - * map of state data nodes - * @param builder - * - builder + * @param configMap map of config data nodes + * @param stateMap map of state data nodes + * @param builder - builder */ - private static > void mapDataToBuilder( - @Nonnull final Map configMap, - @Nonnull final Map stateMap, - @Nonnull final NormalizedNodeContainerBuilder builder) { + private static void mapDataToBuilder( + final @NonNull Map configMap, final @NonNull Map stateMap, + final @NonNull NormalizedNodeContainerBuilder builder) { configMap.entrySet().stream().filter(x -> !stateMap.containsKey(x.getKey())).forEach( y -> builder.addChild(y.getValue())); stateMap.entrySet().stream().filter(x -> !configMap.containsKey(x.getKey())).forEach( @@ -719,18 +763,14 @@ public final class ReadDataTransactionUtil { * Map data with the same identifiers to builder. Data with the same identifiers cannot be just added but we need to * go one level down with {@code prepareData} method. * - * @param configMap - * immutable config data - * @param stateMap - * immutable state data - * @param builder - * - builder + * @param configMap immutable config data + * @param stateMap immutable state data + * @param builder - builder */ @SuppressWarnings("unchecked") - private static > void mergeDataToBuilder( - @Nonnull final Map configMap, - @Nonnull final Map stateMap, - @Nonnull final NormalizedNodeContainerBuilder builder) { + private static void mergeDataToBuilder( + final @NonNull Map configMap, final @NonNull Map stateMap, + final @NonNull NormalizedNodeContainerBuilder builder) { // it is enough to process only config data because operational contains the same data configMap.entrySet().stream().filter(x -> stateMap.containsKey(x.getKey())).forEach( y -> builder.addChild((T) prepareData(y.getValue(), stateMap.get(y.getKey()))));