* @return an Optional containing the data in JSON format if present.
* @throws OperationFailedException if the request fails.
*/
- Optional<String> get(String uriPath, LogicalDatastoreType datastoreType) throws OperationFailedException;
+ Optional<String> get(String uriPath, LogicalDatastoreType datastoreType, UriInfo uriInfo)
+ throws OperationFailedException;
/**
* Invokes a yang-defined RPC.
import org.opendaylight.netconf.sal.streams.listeners.ListenerAdapter;
import org.opendaylight.netconf.sal.streams.listeners.NotificationListenerAdapter;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
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.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.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.NormalizedNodeAttrBuilder;
import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
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.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaPath;
}
}
- // READ configuration
+ /**
+ * Read config data by path
+ *
+ * @param path
+ * - path of data
+ * @return read date
+ */
public NormalizedNode<?, ?> readConfigurationData(final YangInstanceIdentifier path) {
+ return readConfigurationData(path, null);
+ }
+
+ /**
+ * Read config data by path
+ *
+ * @param path
+ * - path of data
+ * @param withDefa
+ * - value of with-defaults parameter
+ * @return read date
+ */
+ public NormalizedNode<?, ?> readConfigurationData(final YangInstanceIdentifier path, final String withDefa) {
checkPreconditions();
- return readDataViaTransaction(this.domDataBroker.newReadOnlyTransaction(), CONFIGURATION, path);
+ return readDataViaTransaction(this.domDataBroker.newReadOnlyTransaction(), CONFIGURATION, path, withDefa);
}
- public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
+ /**
+ * Read config data from mount point by path.
+ *
+ * @param mountPoint
+ * - mount point for reading data
+ * @param path
+ * - path of data
+ * @return read data
+ */
+ public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint,
+ final YangInstanceIdentifier path) {
+ return readConfigurationData(mountPoint, path, null);
+ }
+
+ /**
+ * Read config data from mount point by path.
+ *
+ * @param mountPoint
+ * - mount point for reading data
+ * @param path
+ * - path of data
+ * @param withDefa
+ * - value of with-defaults parameter
+ * @return read data
+ */
+ public NormalizedNode<?, ?> readConfigurationData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path,
+ final String withDefa) {
final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
if (domDataBrokerService.isPresent()) {
- return readDataViaTransaction(domDataBrokerService.get().newReadOnlyTransaction(), CONFIGURATION, path);
+ return readDataViaTransaction(domDataBrokerService.get().newReadOnlyTransaction(), CONFIGURATION, path,
+ withDefa);
}
final String errMsg = "DOM data broker service isn't available for mount point " + path;
LOG.warn(errMsg);
throw new RestconfDocumentedException(errMsg);
}
- // READ operational
+ /**
+ * Read operational data by path.
+ *
+ * @param path
+ * - path of data
+ * @return read data
+ */
public NormalizedNode<?, ?> readOperationalData(final YangInstanceIdentifier path) {
checkPreconditions();
return readDataViaTransaction(this.domDataBroker.newReadOnlyTransaction(), OPERATIONAL, path);
}
+ /**
+ * Read operational data from mount point by path.
+ *
+ * @param mountPoint
+ * - mount point for reading data
+ * @param path
+ * - path of data
+ * @return read data
+ */
public NormalizedNode<?, ?> readOperationalData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
if (domDataBrokerService.isPresent()) {
private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
final LogicalDatastoreType datastore, final YangInstanceIdentifier path) {
+ return readDataViaTransaction(transaction, datastore, path, null);
+ }
+
+ private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
+ final LogicalDatastoreType datastore, final YangInstanceIdentifier path, final String withDefa) {
LOG.trace("Read {} via Restconf: {}", datastore.name(), path);
final ListenableFuture<Optional<NormalizedNode<?, ?>>> listenableFuture = transaction.read(datastore, path);
final ReadDataResult<NormalizedNode<?, ?>> readData = new ReadDataResult<>();
LOG.warn(msg);
throw new RestconfDocumentedException(msg, e);
}
- return readData.getResult();
+ if (withDefa == null) {
+ return readData.getResult();
+ } else {
+ return prepareDataByParamWithDef(readData.getResult(), path, withDefa);
+ }
+
+ }
+
+ private NormalizedNode<?, ?> prepareDataByParamWithDef(final NormalizedNode<?, ?> result,
+ final YangInstanceIdentifier path, final String withDefa) {
+ boolean trim;
+ switch (withDefa) {
+ case "trim":
+ trim = true;
+ break;
+ case "explicit":
+ trim = false;
+ break;
+ default:
+ throw new RestconfDocumentedException("Bad value used with with-defaults parameter : " + withDefa);
+ }
+
+ final SchemaContext ctx = ControllerContext.getInstance().getGlobalSchema();
+ final DataSchemaContextTree baseSchemaCtxTree = DataSchemaContextTree.from(ctx);
+ final DataSchemaNode baseSchemaNode = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
+ if (result instanceof ContainerNode) {
+ final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder =
+ Builders.containerBuilder((ContainerSchemaNode) baseSchemaNode);
+ buildCont(builder, (ContainerNode) result, baseSchemaCtxTree, path, trim);
+ return builder.build();
+ } else {
+ final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder =
+ Builders.mapEntryBuilder((ListSchemaNode) baseSchemaNode);
+ buildMapEntryBuilder(builder, (MapEntryNode) result, baseSchemaCtxTree, path, trim,
+ ((ListSchemaNode) baseSchemaNode).getKeyDefinition());
+ return builder.build();
+ }
+ }
+
+ private void buildMapEntryBuilder(final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder,
+ final MapEntryNode result, final DataSchemaContextTree baseSchemaCtxTree,
+ final YangInstanceIdentifier actualPath, final boolean trim, final List<QName> keys) {
+ for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
+ final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
+ final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
+ if (child instanceof ContainerNode) {
+ final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> childBuilder =
+ Builders.containerBuilder((ContainerSchemaNode) childSchema);
+ buildCont(childBuilder, (ContainerNode) child, baseSchemaCtxTree, path, trim);
+ builder.withChild(childBuilder.build());
+ } else if (child instanceof MapNode) {
+ final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
+ Builders.mapBuilder((ListSchemaNode) childSchema);
+ buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
+ ((ListSchemaNode) childSchema).getKeyDefinition());
+ builder.withChild(childBuilder.build());
+ } else if (child instanceof LeafNode) {
+ final String defaultVal = ((LeafSchemaNode) childSchema).getDefault();
+ final String nodeVal = ((LeafNode<String>) child).getValue();
+ final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
+ Builders.leafBuilder((LeafSchemaNode) childSchema);
+ if (keys.contains(child.getNodeType())) {
+ leafBuilder.withValue(((LeafNode) child).getValue());
+ builder.withChild(leafBuilder.build());
+ } else {
+ if (trim) {
+ if ((defaultVal == null) || !defaultVal.equals(nodeVal)) {
+ leafBuilder.withValue(((LeafNode) child).getValue());
+ builder.withChild(leafBuilder.build());
+ }
+ } else {
+ if ((defaultVal != null) && defaultVal.equals(nodeVal)) {
+ leafBuilder.withValue(((LeafNode) child).getValue());
+ builder.withChild(leafBuilder.build());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void buildList(final CollectionNodeBuilder<MapEntryNode, MapNode> builder, final MapNode result,
+ final DataSchemaContextTree baseSchemaCtxTree, final YangInstanceIdentifier path, final boolean trim,
+ final List<QName> keys) {
+ for (final MapEntryNode mapEntryNode : result.getValue()) {
+ final YangInstanceIdentifier actualNode = path.node(mapEntryNode.getIdentifier());
+ final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(actualNode).getDataSchemaNode();
+ final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder =
+ Builders.mapEntryBuilder((ListSchemaNode) childSchema);
+ buildMapEntryBuilder(mapEntryBuilder, mapEntryNode, baseSchemaCtxTree, actualNode, trim, keys);
+ builder.withChild(mapEntryBuilder.build());
+ }
+ }
+
+ private void buildCont(final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder,
+ final ContainerNode result, final DataSchemaContextTree baseSchemaCtxTree,
+ final YangInstanceIdentifier actualPath, final boolean trim) {
+ for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
+ final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
+ final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
+ if(child instanceof ContainerNode){
+ final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builderChild =
+ Builders.containerBuilder((ContainerSchemaNode) childSchema);
+ buildCont(builderChild, result, baseSchemaCtxTree, actualPath, trim);
+ builder.withChild(builderChild.build());
+ } else if (child instanceof MapNode) {
+ final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
+ Builders.mapBuilder((ListSchemaNode) childSchema);
+ buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
+ ((ListSchemaNode) childSchema).getKeyDefinition());
+ builder.withChild(childBuilder.build());
+ } else if (child instanceof LeafNode) {
+ final String defaultVal = ((LeafSchemaNode) childSchema).getDefault();
+ final String nodeVal = ((LeafNode<String>) child).getValue();
+ final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
+ Builders.leafBuilder((LeafSchemaNode) childSchema);
+ if (trim) {
+ if ((defaultVal == null) || !defaultVal.equals(nodeVal)) {
+ leafBuilder.withValue(((LeafNode) child).getValue());
+ builder.withChild(leafBuilder.build());
+ }
+ } else {
+ if ((defaultVal != null) && defaultVal.equals(nodeVal)) {
+ leafBuilder.withValue(((LeafNode) child).getValue());
+ builder.withChild(leafBuilder.build());
+ }
+ }
+ }
+ }
}
/**
}
@Override
- public Optional<String> get(final String uriPath, final LogicalDatastoreType datastoreType) throws OperationFailedException {
+ public Optional<String> get(final String uriPath, final LogicalDatastoreType datastoreType, final UriInfo uriInfo)
+ throws OperationFailedException {
LOG.debug("get: uriPath: {}", uriPath);
try {
NormalizedNodeContext readData;
if(datastoreType == LogicalDatastoreType.CONFIGURATION) {
- readData = RestconfImpl.getInstance().readConfigurationData(uriPath, null);
+ readData = RestconfImpl.getInstance().readConfigurationData(uriPath, uriInfo);
} else {
- readData = RestconfImpl.getInstance().readOperationalData(uriPath, null);
+ readData = RestconfImpl.getInstance().readOperationalData(uriPath, uriInfo);
}
final Optional<String> result = Optional.of(toJson(readData));
@Override
public String toString() {
- return uriParameterName;
+ return this.uriParameterName;
}
}
public static WriterParameters parseWriterParameters(final UriInfo info) {
- WriterParameters.WriterParametersBuilder wpBuilder = new WriterParameters.WriterParametersBuilder();
+ return parseParams(info, false);
+ }
+
+ private static WriterParameters parseParams(final UriInfo info, final boolean tagged) {
+ final WriterParameters.WriterParametersBuilder wpBuilder = new WriterParameters.WriterParametersBuilder();
+ wpBuilder.setTagged(tagged);
if(info == null) {
return wpBuilder.build();
}
return wpBuilder.build();
}
+ public static WriterParameters parseWriterParameters(final UriInfo uriInfo, final boolean tagged) {
+ return parseParams(uriInfo, tagged);
+ }
+
}
@Override
public NormalizedNodeContext readConfigurationData(final String identifier, final UriInfo uriInfo) {
+ boolean withDefa_used = false;
+ String withDefa = null;
+
+ for (final Entry<String, List<String>> entry : uriInfo.getQueryParameters().entrySet()) {
+ switch (entry.getKey()) {
+ case "with-defaults":
+ if (!withDefa_used) {
+ withDefa_used = true;
+ withDefa = entry.getValue().iterator().next();
+ } else {
+ throw new RestconfDocumentedException("With-defaults parameter can be used only once.");
+ }
+ break;
+ }
+ }
+ boolean tagged = false;
+ if (withDefa_used) {
+ if (withDefa.equals("report-all-tagged")) {
+ tagged = true;
+ withDefa = null;
+ }
+ if (withDefa.equals("report-all")) {
+ withDefa = null;
+ }
+ }
+
final InstanceIdentifierContext<?> iiWithData = this.controllerContext.toInstanceIdentifier(identifier);
final DOMMountPoint mountPoint = iiWithData.getMountPoint();
NormalizedNode<?, ?> data = null;
final YangInstanceIdentifier normalizedII = iiWithData.getInstanceIdentifier();
if (mountPoint != null) {
- data = this.broker.readConfigurationData(mountPoint, normalizedII);
+ data = this.broker.readConfigurationData(mountPoint, normalizedII, withDefa);
} else {
- data = this.broker.readConfigurationData(normalizedII);
+ data = this.broker.readConfigurationData(normalizedII, withDefa);
}
if(data == null) {
final String errMsg = "Request could not be completed because the relevant data model content does not exist ";
LOG.debug(errMsg + identifier);
throw new RestconfDocumentedException(errMsg, ErrorType.APPLICATION, ErrorTag.DATA_MISSING);
}
- return new NormalizedNodeContext(iiWithData, data, QueryParametersParser.parseWriterParameters(uriInfo));
+ return new NormalizedNodeContext(iiWithData, data,
+ QueryParametersParser.parseWriterParameters(uriInfo, tagged));
}
@Override
default:
throw new RestconfDocumentedException("Bad parameter for post: " + entry.getKey());
}
- }
+ }
if (point_used && !insert_used) {
throw new RestconfDocumentedException("Point parameter can't be used without Insert parameter.");
private final Integer depth;
private final List<Set<QName>> fields;
private final boolean prettyPrint;
+ private final boolean tagged;
private WriterParameters(final WriterParametersBuilder builder) {
this.content = builder.content;
this.depth = builder.depth;
this.fields = builder.fields;
this.prettyPrint = builder.prettyPrint;
+ this.tagged = builder.tagged;
}
public String getContent() {
- return content;
+ return this.content;
}
public Integer getDepth() {
- return depth;
+ return this.depth;
}
public List<Set<QName>> getFields() {
- return fields;
+ return this.fields;
}
public boolean isPrettyPrint() {
- return prettyPrint;
+ return this.prettyPrint;
+ }
+
+ public boolean isTagged() {
+ return this.tagged;
}
public static class WriterParametersBuilder {
private Integer depth;
private List<Set<QName>> fields;
private boolean prettyPrint;
+ private boolean tagged;
public WriterParametersBuilder() {}
public WriterParameters build() {
return new WriterParameters(this);
}
+
+ public void setTagged(final boolean tagged) {
+ this.tagged = tagged;
+ }
}
}
final InstanceIdentifierContext<?> instanceIdentifier = ParserIdentifier.toInstanceIdentifier(
identifier, schemaContextRef.get(), Optional.of(this.mountPointServiceHandler.get()));
+ boolean withDefa_used = false;
+ String withDefa = null;
+
+ for (final Entry<String, List<String>> entry : uriInfo.getQueryParameters().entrySet()) {
+ switch (entry.getKey()) {
+ case "with-defaults":
+ if (!withDefa_used) {
+ withDefa_used = true;
+ withDefa = entry.getValue().iterator().next();
+ } else {
+ throw new RestconfDocumentedException("With-defaults parameter can be used only once.");
+ }
+ break;
+ }
+ }
+ boolean tagged = false;
+ if (withDefa_used) {
+ if (withDefa.equals("report-all-tagged")) {
+ tagged = true;
+ withDefa = null;
+ }
+ if (withDefa.equals("report-all")) {
+ withDefa = null;
+ }
+ }
+
final WriterParameters parameters = ReadDataTransactionUtil.parseUriParameters(
- instanceIdentifier, uriInfo);
+ instanceIdentifier, uriInfo, tagged);
final DOMMountPoint mountPoint = instanceIdentifier.getMountPoint();
final DOMTransactionChain transactionChain;
final TransactionVarsWrapper transactionNode = new TransactionVarsWrapper(
instanceIdentifier, mountPoint, transactionChain);
- final NormalizedNode<?, ?> node = ReadDataTransactionUtil.readData(parameters.getContent(), transactionNode);
+ final NormalizedNode<?, ?> node =
+ ReadDataTransactionUtil.readData(parameters.getContent(), transactionNode, withDefa);
if (node == null) {
throw new RestconfDocumentedException(
"Request could not be completed because the relevant data model content does not exist",
import javax.ws.rs.core.UriInfo;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
import org.opendaylight.netconf.sal.restconf.impl.InstanceIdentifierContext;
import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
import org.opendaylight.netconf.sal.restconf.impl.RestconfError;
import org.opendaylight.netconf.sal.restconf.impl.WriterParameters.WriterParametersBuilder;
import org.opendaylight.restconf.restful.transaction.TransactionVarsWrapper;
import org.opendaylight.restconf.utils.parser.ParserFieldsParameter;
+import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
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.NormalizedNodeAttrBuilder;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
+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.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
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.
throw new UnsupportedOperationException("Util class.");
}
+ /**
+ * 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}
+ */
+ public static @Nonnull 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.
*
*/
public static @Nonnull 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) {
final WriterParametersBuilder builder = new WriterParametersBuilder();
+ builder.setTagged(tagged);
if (uriInfo == null) {
return builder.build();
uriInfo.getQueryParameters().keySet(),
RestconfDataServiceConstant.ReadData.CONTENT,
RestconfDataServiceConstant.ReadData.DEPTH,
- RestconfDataServiceConstant.ReadData.FIELDS);
+ RestconfDataServiceConstant.ReadData.FIELDS, RestconfDataServiceConstant.ReadData.WITH_DEFAULTS);
// read parameters from URI or set default values
final List<String> content = uriInfo.getQueryParameters().getOrDefault(
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,
* @return {@link NormalizedNode}
*/
public static @Nullable NormalizedNode<?, ?> readData(@Nonnull final String valueOfContent,
- @Nonnull final TransactionVarsWrapper transactionNode) {
+ @Nonnull final TransactionVarsWrapper transactionNode) {
+ return readData(valueOfContent, transactionNode, null);
+ }
+
+ /**
+ * 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 withDefa
+ * - vaule of with-defaults parameter
+ * @return {@link NormalizedNode}
+ */
+ public static @Nullable NormalizedNode<?, ?> readData(@Nonnull final String valueOfContent,
+ @Nonnull final TransactionVarsWrapper transactionNode, final String withDefa) {
switch (valueOfContent) {
case RestconfDataServiceConstant.ReadData.CONFIG:
transactionNode.setLogicalDatastoreType(LogicalDatastoreType.CONFIGURATION);
- return readDataViaTransaction(transactionNode);
-
+ if (withDefa == null) {
+ return readDataViaTransaction(transactionNode);
+ } else {
+ return prepareDataByParamWithDef(readDataViaTransaction(transactionNode),
+ transactionNode.getInstanceIdentifier().getInstanceIdentifier(), withDefa);
+ }
case RestconfDataServiceConstant.ReadData.NONCONFIG:
transactionNode.setLogicalDatastoreType(LogicalDatastoreType.OPERATIONAL);
return readDataViaTransaction(transactionNode);
case RestconfDataServiceConstant.ReadData.ALL:
- return readAllData(transactionNode);
+ return readAllData(transactionNode, withDefa);
default:
throw new RestconfDocumentedException(
}
}
+ private static NormalizedNode<?, ?> prepareDataByParamWithDef(final NormalizedNode<?, ?> result,
+ final YangInstanceIdentifier path, final String withDefa) {
+ boolean trim;
+ switch (withDefa) {
+ case "trim":
+ trim = true;
+ break;
+ case "explicit":
+ trim = false;
+ break;
+ default:
+ throw new RestconfDocumentedException("");
+ }
+
+ final SchemaContext ctx = ControllerContext.getInstance().getGlobalSchema();
+ final DataSchemaContextTree baseSchemaCtxTree = DataSchemaContextTree.from(ctx);
+ final DataSchemaNode baseSchemaNode = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
+ if (result instanceof ContainerNode) {
+ final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder =
+ Builders.containerBuilder((ContainerSchemaNode) baseSchemaNode);
+ buildCont(builder, (ContainerNode) result, baseSchemaCtxTree, path, trim);
+ return builder.build();
+ } else {
+ final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder =
+ Builders.mapEntryBuilder((ListSchemaNode) baseSchemaNode);
+ buildMapEntryBuilder(builder, (MapEntryNode) result, baseSchemaCtxTree, path, trim,
+ ((ListSchemaNode) baseSchemaNode).getKeyDefinition());
+ return builder.build();
+ }
+ }
+
+ private static void buildMapEntryBuilder(
+ final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder,
+ final MapEntryNode result, final DataSchemaContextTree baseSchemaCtxTree,
+ final YangInstanceIdentifier actualPath, final boolean trim, final List<QName> keys) {
+ for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
+ final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
+ final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
+ if (child instanceof ContainerNode) {
+ final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> childBuilder =
+ Builders.containerBuilder((ContainerSchemaNode) childSchema);
+ buildCont(childBuilder, (ContainerNode) child, baseSchemaCtxTree, path, trim);
+ builder.withChild(childBuilder.build());
+ } else if (child instanceof MapNode) {
+ final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
+ Builders.mapBuilder((ListSchemaNode) childSchema);
+ buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
+ ((ListSchemaNode) childSchema).getKeyDefinition());
+ builder.withChild(childBuilder.build());
+ } else if (child instanceof LeafNode) {
+ final String defaultVal = ((LeafSchemaNode) childSchema).getDefault();
+ final String nodeVal = ((LeafNode<String>) child).getValue();
+ final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
+ Builders.leafBuilder((LeafSchemaNode) childSchema);
+ if (keys.contains(child.getNodeType())) {
+ leafBuilder.withValue(((LeafNode) child).getValue());
+ builder.withChild(leafBuilder.build());
+ } else {
+ if (trim) {
+ if ((defaultVal == null) || !defaultVal.equals(nodeVal)) {
+ leafBuilder.withValue(((LeafNode) child).getValue());
+ builder.withChild(leafBuilder.build());
+ }
+ } else {
+ if ((defaultVal != null) && defaultVal.equals(nodeVal)) {
+ leafBuilder.withValue(((LeafNode) child).getValue());
+ builder.withChild(leafBuilder.build());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private static void buildList(final CollectionNodeBuilder<MapEntryNode, MapNode> builder, final MapNode result,
+ final DataSchemaContextTree baseSchemaCtxTree, final YangInstanceIdentifier path, final boolean trim,
+ final List<QName> keys) {
+ for (final MapEntryNode mapEntryNode : result.getValue()) {
+ final YangInstanceIdentifier actualNode = path.node(mapEntryNode.getIdentifier());
+ final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(actualNode).getDataSchemaNode();
+ final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder =
+ Builders.mapEntryBuilder((ListSchemaNode) childSchema);
+ buildMapEntryBuilder(mapEntryBuilder, mapEntryNode, baseSchemaCtxTree, actualNode, trim, keys);
+ builder.withChild(mapEntryBuilder.build());
+ }
+ }
+
+ private static void buildCont(final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder,
+ final ContainerNode result, final DataSchemaContextTree baseSchemaCtxTree,
+ final YangInstanceIdentifier actualPath, final boolean trim) {
+ for (final DataContainerChild<? extends PathArgument, ?> child : result.getValue()) {
+ final YangInstanceIdentifier path = actualPath.node(child.getIdentifier());
+ final DataSchemaNode childSchema = baseSchemaCtxTree.getChild(path).getDataSchemaNode();
+ if (child instanceof ContainerNode) {
+ final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builderChild =
+ Builders.containerBuilder((ContainerSchemaNode) childSchema);
+ buildCont(builderChild, result, baseSchemaCtxTree, actualPath, trim);
+ builder.withChild(builderChild.build());
+ } else if (child instanceof MapNode) {
+ final CollectionNodeBuilder<MapEntryNode, MapNode> childBuilder =
+ Builders.mapBuilder((ListSchemaNode) childSchema);
+ buildList(childBuilder, (MapNode) child, baseSchemaCtxTree, path, trim,
+ ((ListSchemaNode) childSchema).getKeyDefinition());
+ builder.withChild(childBuilder.build());
+ } else if (child instanceof LeafNode) {
+ final String defaultVal = ((LeafSchemaNode) childSchema).getDefault();
+ final String nodeVal = ((LeafNode<String>) child).getValue();
+ final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
+ Builders.leafBuilder((LeafSchemaNode) childSchema);
+ if (trim) {
+ if ((defaultVal == null) || !defaultVal.equals(nodeVal)) {
+ leafBuilder.withValue(((LeafNode) child).getValue());
+ builder.withChild(leafBuilder.build());
+ }
+ } else {
+ if ((defaultVal != null) && defaultVal.equals(nodeVal)) {
+ leafBuilder.withValue(((LeafNode) child).getValue());
+ builder.withChild(leafBuilder.build());
+ }
+ }
+ }
+ }
+ }
+
/**
* If is set specific {@link LogicalDatastoreType} in
* {@link TransactionVarsWrapper}, then read this type of data from DS. If
*
* @param transactionNode
* - {@link TransactionVarsWrapper} - wrapper for variables
+ * @param withDefa
* @return {@link NormalizedNode}
*/
- private static @Nullable NormalizedNode<?, ?> readAllData(@Nonnull final TransactionVarsWrapper transactionNode) {
+ private static @Nullable NormalizedNode<?, ?> readAllData(@Nonnull final TransactionVarsWrapper transactionNode,
+ final String withDefa) {
// PREPARE STATE DATA NODE
transactionNode.setLogicalDatastoreType(LogicalDatastoreType.OPERATIONAL);
final NormalizedNode<?, ?> stateDataNode = readDataViaTransaction(transactionNode);
// PREPARE CONFIG DATA NODE
transactionNode.setLogicalDatastoreType(LogicalDatastoreType.CONFIGURATION);
- final NormalizedNode<?, ?> configDataNode = readDataViaTransaction(transactionNode);
+ final NormalizedNode<?, ?> configDataNode;
+ if (withDefa == null) {
+ configDataNode = readDataViaTransaction(transactionNode);
+ } else {
+ configDataNode = prepareDataByParamWithDef(readDataViaTransaction(transactionNode),
+ transactionNode.getInstanceIdentifier().getInstanceIdentifier(), withDefa);
+ }
// if no data exists
if ((stateDataNode == null) && (configDataNode == null)) {
public static final int MAX_DEPTH = 65535;
public static final String READ_TYPE_TX = "READ";
+ public static final String WITH_DEFAULTS = "with-defaults";
private ReadData() {
throw new UnsupportedOperationException("Util class.");
@Test
public void testGetWithNoData() throws OperationFailedException {
- doReturn(null).when(brokerFacade).readConfigurationData(notNull(YangInstanceIdentifier.class));
+ doReturn(null).when(brokerFacade).readConfigurationData(notNull(YangInstanceIdentifier.class),
+ Mockito.anyString());
final String uriPath = "ietf-interfaces:interfaces";
- this.service.get(uriPath, LogicalDatastoreType.CONFIGURATION);
+ final UriInfo uriInfo = Mockito.mock(UriInfo.class);
+ final MultivaluedMap<String, String> value = Mockito.mock(MultivaluedMap.class);
+ Mockito.when(value.entrySet()).thenReturn(new HashSet<>());
+ Mockito.when(uriInfo.getQueryParameters()).thenReturn(value);
+ this.service.get(uriPath, LogicalDatastoreType.CONFIGURATION, uriInfo);
}
@Test(expected=OperationFailedException.class)
public void testGetFailure() throws Exception {
final String invalidUriPath = "/ietf-interfaces:interfaces/invalid";
-
- this.service.get(invalidUriPath, LogicalDatastoreType.CONFIGURATION);
+ final UriInfo uriInfo = Mockito.mock(UriInfo.class);
+ final MultivaluedMap<String, String> value = Mockito.mock(MultivaluedMap.class);
+ Mockito.when(value.entrySet()).thenReturn(new HashSet<>());
+ Mockito.when(uriInfo.getQueryParameters()).thenReturn(value);
+ this.service.get(invalidUriPath, LogicalDatastoreType.CONFIGURATION, uriInfo);
}
@SuppressWarnings("rawtypes")
.build();
if(datastoreType == LogicalDatastoreType.CONFIGURATION) {
- doReturn(entryNode).when(brokerFacade).readConfigurationData(notNull(YangInstanceIdentifier.class));
+ doReturn(entryNode).when(brokerFacade).readConfigurationData(notNull(YangInstanceIdentifier.class),
+ Mockito.anyString());
} else {
doReturn(entryNode).when(brokerFacade).readOperationalData(notNull(YangInstanceIdentifier.class));
}
final String uriPath = "/ietf-interfaces:interfaces/interface/eth0";
+ final UriInfo uriInfo = Mockito.mock(UriInfo.class);
+ final MultivaluedMap<String, String> value = Mockito.mock(MultivaluedMap.class);
+ Mockito.when(value.entrySet()).thenReturn(new HashSet<>());
+ Mockito.when(uriInfo.getQueryParameters()).thenReturn(value);
+ Mockito.when(uriInfo.getQueryParameters(false)).thenReturn(value);
+ Mockito.when(value.getFirst("depth")).thenReturn("");
- final Optional<String> optionalResp = this.service.get(uriPath, datastoreType);
+ final Optional<String> optionalResp = this.service.get(uriPath, datastoreType, uriInfo);
assertEquals("Response present", true, optionalResp.isPresent());
final String jsonResp = optionalResp.get();
final ArgumentCaptor<YangInstanceIdentifier> capturedPath = ArgumentCaptor.forClass(YangInstanceIdentifier.class);
if (datastoreType == LogicalDatastoreType.CONFIGURATION) {
- verify(brokerFacade).readConfigurationData(capturedPath.capture());
+ verify(brokerFacade).readConfigurationData(capturedPath.capture(), Mockito.anyString());
} else {
verify(brokerFacade).readOperationalData(capturedPath.capture());
}
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
+import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
@SuppressWarnings("unchecked")
@Test
public void getDataWithUrlMountPoint() throws UnsupportedEncodingException, URISyntaxException, ParseException {
- when(brokerFacade.readConfigurationData(any(DOMMountPoint.class), any(YangInstanceIdentifier.class))).thenReturn(
+ when(brokerFacade.readConfigurationData(any(DOMMountPoint.class), any(YangInstanceIdentifier.class),
+ Mockito.anyString())).thenReturn(
prepareCnDataForMountPointTest(false));
final DOMMountPoint mountInstance = mock(DOMMountPoint.class);
when(mountInstance.getSchemaContext()).thenReturn(schemaContextTestModule);
@Test
public void getDataWithSlashesBehindMountPoint() throws Exception {
final YangInstanceIdentifier awaitedInstanceIdentifier = prepareInstanceIdentifierForList();
- when(brokerFacade.readConfigurationData(any(DOMMountPoint.class), eq(awaitedInstanceIdentifier))).thenReturn(
- prepareCnDataForSlashesBehindMountPointTest());
+ when(brokerFacade.readConfigurationData(any(DOMMountPoint.class), eq(awaitedInstanceIdentifier),
+ Mockito.anyString())).thenReturn(prepareCnDataForSlashesBehindMountPointTest());
final DOMMountPoint mountInstance = mock(DOMMountPoint.class);
when(mountInstance.getSchemaContext()).thenReturn(schemaContextTestModule);
final DOMMountPointService mockMountService = mock(DOMMountPointService.class);
@Test
public void getDataMountPointIntoHighestElement() throws UnsupportedEncodingException, URISyntaxException,
ParseException {
- when(brokerFacade.readConfigurationData(any(DOMMountPoint.class), any(YangInstanceIdentifier.class))).thenReturn(
+ when(brokerFacade.readConfigurationData(any(DOMMountPoint.class), any(YangInstanceIdentifier.class),
+ Mockito.anyString())).thenReturn(
prepareCnDataForMountPointTest(true));
final DOMMountPoint mountInstance = mock(DOMMountPoint.class);
when(mountInstance.getSchemaContext()).thenReturn(schemaContextTestModule);
.withChild(ImmutableNodes.leafNode(newTestModuleQName("type"), newTestModuleQName("test-identity")))
.withChild(ImmutableNodes.leafNode(newTestModuleQName("name"), "foo"))
.withChild(ImmutableNodes.leafNode(newTestModuleQName("data"), "bar")).build()).build();
- when(brokerFacade.readConfigurationData(iid)).thenReturn(data);
+ when(brokerFacade.readConfigurationData(iid, null)).thenReturn(data);
final String uri = "/config/test-module:modules/module/test-module:test-identity/foo";
assertEquals(200, get(uri, MediaType.APPLICATION_XML));
@SuppressWarnings("unchecked")
private void mockReadConfigurationDataMethod() {
- when(brokerFacade.readConfigurationData(any(YangInstanceIdentifier.class))).thenReturn(answerFromGet);
+ when(brokerFacade.readConfigurationData(any(YangInstanceIdentifier.class), Mockito.anyString()))
+ .thenReturn(answerFromGet);
}
@SuppressWarnings("rawtypes")