import static com.google.common.base.Preconditions.checkArgument;
+import com.google.common.annotations.Beta;
import java.net.URI;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
*/
public final class DepthParameter implements Immutable {
private static final @NonNull URI CAPABILITY = URI.create("urn:ietf:params:restconf:capability:depth:1.0");
+ private static final @NonNull DepthParameter MIN = of(1);
+ private static final @NonNull DepthParameter MAX = of(65535);
private final int value;
checkArgument(value >= 1 && value <= 65535);
}
- public static DepthParameter of(final int value) {
+ public static @NonNull DepthParameter of(final int value) {
return new DepthParameter(value);
}
+ @Beta
+ public static @NonNull DepthParameter min() {
+ return MIN;
+ }
+
+ @Beta
+ public static @NonNull DepthParameter max() {
+ return MAX;
+ }
+
public static @Nullable DepthParameter forUriValue(final String uriValue) {
- return uriValue.equals("unbounded") ? null : of(Integer.parseUnsignedInt(uriValue, 10));
+ return uriValue.equals(unboundedUriValue()) ? null : of(Integer.parseUnsignedInt(uriValue, 10));
}
public int value() {
return String.valueOf(value);
}
+ public static String unboundedUriValue() {
+ return "unbounded";
+ }
+
public static @NonNull URI capabilityUri() {
return CAPABILITY;
}
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.Provider;
import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.restconf.nb.rfc8040.DepthParameter;
import org.opendaylight.restconf.nb.rfc8040.MediaTypes;
import org.opendaylight.restconf.nb.rfc8040.jersey.providers.api.RestconfNormalizedNodeWriter;
import org.opendaylight.restconf.nb.rfc8040.legacy.NormalizedNodePayload;
private static void writeNormalizedNode(final JsonWriter jsonWriter,
final SchemaPath path, final InstanceIdentifierContext<SchemaNode> context, final NormalizedNode data,
- final Integer depth, final List<Set<QName>> fields) throws IOException {
+ final DepthParameter depth, final List<Set<QName>> fields) throws IOException {
final RestconfNormalizedNodeWriter nnWriter;
if (context.getSchemaNode() instanceof RpcDefinition) {
private static RestconfNormalizedNodeWriter createNormalizedNodeWriter(
final InstanceIdentifierContext<SchemaNode> context, final SchemaPath path, final JsonWriter jsonWriter,
- final Integer depth, final List<Set<QName>> fields) {
+ final DepthParameter depth, final List<Set<QName>> fields) {
final SchemaNode schema = context.getSchemaNode();
final JSONCodecFactory codecs = getCodecFactory(context);
import java.util.Optional;
import java.util.Set;
import javax.xml.transform.dom.DOMSource;
+import org.opendaylight.restconf.nb.rfc8040.DepthParameter;
import org.opendaylight.restconf.nb.rfc8040.jersey.providers.api.RestconfNormalizedNodeWriter;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
protected final List<Set<QName>> fields;
protected int currentDepth = 0;
- private ParameterAwareNormalizedNodeWriter(final NormalizedNodeStreamWriter writer, final Integer maxDepth,
+ private ParameterAwareNormalizedNodeWriter(final NormalizedNodeStreamWriter writer, final DepthParameter depth,
final List<Set<QName>> fields) {
this.writer = requireNonNull(writer);
- this.maxDepth = maxDepth;
+ maxDepth = depth == null ? null : depth.value();
this.fields = fields;
}
* @return A new instance.
*/
public static ParameterAwareNormalizedNodeWriter forStreamWriter(
- final NormalizedNodeStreamWriter writer, final Integer maxDepth, final List<Set<QName>> fields) {
+ final NormalizedNodeStreamWriter writer, final DepthParameter maxDepth, final List<Set<QName>> fields) {
return forStreamWriter(writer, true, maxDepth, fields);
}
/**
* Create a new writer backed by a {@link NormalizedNodeStreamWriter}. Unlike the simple
- * {@link #forStreamWriter(NormalizedNodeStreamWriter, Integer, List)}
- * method, this allows the caller to switch off RFC6020 XML compliance, providing better
- * throughput. The reason is that the XML mapping rules in RFC6020 require the encoding
- * to emit leaf nodes which participate in a list's key first and in the order in which
- * they are defined in the key. For JSON, this requirement is completely relaxed and leaves
- * can be ordered in any way we see fit. The former requires a bit of work: first a lookup
- * for each key and then for each emitted node we need to check whether it was already
- * emitted.
+ * {@link #forStreamWriter(NormalizedNodeStreamWriter, DepthParameter, List)} method, this allows the caller to
+ * switch off RFC6020 XML compliance, providing better throughput. The reason is that the XML mapping rules in
+ * RFC6020 require the encoding to emit leaf nodes which participate in a list's key first and in the order in which
+ * they are defined in the key. For JSON, this requirement is completely relaxed and leaves can be ordered in any
+ * way we see fit. The former requires a bit of work: first a lookup for each key and then for each emitted node we
+ * need to check whether it was already emitted.
*
* @param writer Back-end writer
* @param orderKeyLeaves whether the returned instance should be RFC6020 XML compliant.
- * @param maxDepth Maximal depth to write
+ * @param depth Maximal depth to write
* @param fields Selected child nodes to write
* @return A new instance.
*/
public static ParameterAwareNormalizedNodeWriter forStreamWriter(final NormalizedNodeStreamWriter writer,
final boolean orderKeyLeaves,
- final Integer maxDepth,
+ final DepthParameter depth,
final List<Set<QName>> fields) {
- return orderKeyLeaves ? new OrderedParameterAwareNormalizedNodeWriter(writer, maxDepth, fields)
- : new ParameterAwareNormalizedNodeWriter(writer, maxDepth, fields);
+ return orderKeyLeaves ? new OrderedParameterAwareNormalizedNodeWriter(writer, depth, fields)
+ : new ParameterAwareNormalizedNodeWriter(writer, depth, fields);
}
/**
private static final class OrderedParameterAwareNormalizedNodeWriter extends ParameterAwareNormalizedNodeWriter {
private static final Logger LOG = LoggerFactory.getLogger(OrderedParameterAwareNormalizedNodeWriter.class);
- OrderedParameterAwareNormalizedNodeWriter(final NormalizedNodeStreamWriter writer, final Integer maxDepth,
+ OrderedParameterAwareNormalizedNodeWriter(final NormalizedNodeStreamWriter writer, final DepthParameter depth,
final List<Set<QName>> fields) {
- super(writer, maxDepth, fields);
+ super(writer, depth, fields);
}
@Override
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.restconf.nb.rfc8040.DepthParameter;
import org.opendaylight.restconf.nb.rfc8040.MediaTypes;
import org.opendaylight.restconf.nb.rfc8040.jersey.providers.api.RestconfNormalizedNodeWriter;
import org.opendaylight.restconf.nb.rfc8040.legacy.NormalizedNodePayload;
}
private static void writeNormalizedNode(final XMLStreamWriter xmlWriter, final SchemaPath path,
- final InstanceIdentifierContext<?> pathContext, final NormalizedNode data, final Integer depth,
+ final InstanceIdentifierContext<?> pathContext, final NormalizedNode data, final DepthParameter depth,
final List<Set<QName>> fields) throws IOException {
final RestconfNormalizedNodeWriter nnWriter;
final EffectiveModelContext schemaCtx = pathContext.getSchemaContext();
}
private static RestconfNormalizedNodeWriter createNormalizedNodeWriter(final XMLStreamWriter xmlWriter,
- final EffectiveModelContext schemaContext, final SchemaPath schemaPath, final Integer depth,
+ final EffectiveModelContext schemaContext, final SchemaPath schemaPath, final DepthParameter depth,
final List<Set<QName>> fields) {
final NormalizedNodeStreamWriter xmlStreamWriter = XMLStreamNormalizedNodeStreamWriter
.create(xmlWriter, schemaContext, schemaPath);
import java.util.List;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
import org.opendaylight.restconf.nb.rfc8040.ContentParameter;
+import org.opendaylight.restconf.nb.rfc8040.DepthParameter;
import org.opendaylight.restconf.nb.rfc8040.WithDefaultsParameter;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
private List<Set<QName>> fields;
private ContentParameter content;
private WithDefaultsParameter withDefault;
- // FIXME: this should be a DepthParameter
- private Integer depth;
+ private DepthParameter depth;
private boolean prettyPrint;
private boolean tagged;
return this;
}
- public Builder setDepth(final int depth) {
+ public Builder setDepth(final DepthParameter depth) {
this.depth = depth;
return this;
}
private final List<Set<QName>> fields;
private final WithDefaultsParameter withDefault;
private final ContentParameter content;
- private final Integer depth;
+ private final DepthParameter depth;
private final boolean prettyPrint;
private final boolean tagged;
return content;
}
- public Integer getDepth() {
+ public @Nullable DepthParameter getDepth() {
return depth;
}
import static org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserFieldsParameter.parseFieldsPaths;
import com.google.common.annotations.VisibleForTesting;
-import com.google.common.primitives.Ints;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.Arrays;
import java.util.Collection;
* </ul>
*/
public final class ReadDataTransactionUtil {
- // depth values
- // FIXME: these are known to DepthParameter
- private static final String UNBOUNDED = "unbounded";
- private static final int MIN_DEPTH = 1;
- private static final int MAX_DEPTH = 65535;
-
private static final Set<String> ALLOWED_PARAMETERS = Set.of(
ContentParameter.uriName(),
DepthParameter.uriName(),
FieldsParameter.uriName(),
WithDefaultsParameter.uriName());
private static final List<String> DEFAULT_CONTENT = List.of(ContentParameter.ALL.uriValue());
- private static final List<String> DEFAULT_DEPTH = List.of(UNBOUNDED);
+ private static final List<String> DEFAULT_DEPTH = List.of(DepthParameter.unboundedUriValue());
private static final List<String> POSSIBLE_CONTENT = Arrays.stream(ContentParameter.values())
.map(ContentParameter::uriValue)
.collect(Collectors.toUnmodifiableList());
checkParameterCount(withDefaults, WithDefaultsParameter.uriName());
// check and set content
- final String contentValueStr = content.get(0);
+ final String contentStr = content.get(0);
builder.setContent(RestconfDocumentedException.throwIfNull(
- ContentParameter.forUriValue(contentValueStr), ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE,
- "Invalid content parameter: %s, allowed values are %s", contentValueStr, POSSIBLE_CONTENT));
-
- // check and set depth
- if (!depth.get(0).equals(UNBOUNDED)) {
- final Integer value = Ints.tryParse(depth.get(0));
-
- if (value == null || value < MIN_DEPTH || value > MAX_DEPTH) {
- throw new RestconfDocumentedException(
- new RestconfError(ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE,
- "Invalid depth parameter: " + depth, null,
- "The depth parameter must be an integer between 1 and 65535 or \"unbounded\""));
- } else {
- builder.setDepth(value);
- }
+ ContentParameter.forUriValue(contentStr), ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE,
+ "Invalid content parameter: %s, allowed values are %s", contentStr, POSSIBLE_CONTENT));
+
+ final String depthStr = depth.get(0);
+ try {
+ builder.setDepth(DepthParameter.forUriValue(depthStr));
+ } catch (IllegalArgumentException e) {
+ throw new RestconfDocumentedException(e, new RestconfError(ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE,
+ "Invalid depth parameter: " + depthStr, null,
+ "The depth parameter must be an integer between 1 and 65535 or \"unbounded\""));
}
// check and set fields
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
+import org.opendaylight.restconf.nb.rfc8040.DepthParameter;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
*/
@Test
public void writeContainerWithoutChildrenDepthTest() throws Exception {
- final ParameterAwareNormalizedNodeWriter parameterWriter = ParameterAwareNormalizedNodeWriter
- .forStreamWriter(writer, 1, null);
+ final ParameterAwareNormalizedNodeWriter parameterWriter = ParameterAwareNormalizedNodeWriter.forStreamWriter(
+ writer, DepthParameter.min(), null);
parameterWriter.write(containerNodeData);
@Test
public void writeContainerWithChildrenDepthTest() throws Exception {
final ParameterAwareNormalizedNodeWriter parameterWriter = ParameterAwareNormalizedNodeWriter.forStreamWriter(
- writer, Integer.MAX_VALUE, null);
+ writer, DepthParameter.max(), null);
parameterWriter.write(containerNodeData);
*/
@Test
public void writeMapNodeWithoutChildrenDepthTest() throws Exception {
- final ParameterAwareNormalizedNodeWriter parameterWriter = ParameterAwareNormalizedNodeWriter
- .forStreamWriter(writer, 1, null);
+ final ParameterAwareNormalizedNodeWriter parameterWriter = ParameterAwareNormalizedNodeWriter.forStreamWriter(
+ writer, DepthParameter.min(), null);
parameterWriter.write(mapNodeData);
@Test
public void writeMapNodeWithChildrenDepthTest() throws Exception {
final ParameterAwareNormalizedNodeWriter parameterWriter = ParameterAwareNormalizedNodeWriter.forStreamWriter(
- writer, Integer.MAX_VALUE, null);
+ writer, DepthParameter.max(), null);
parameterWriter.write(mapNodeData);
@Test
public void writeLeafSetNodeWithoutChildrenDepthTest() throws Exception {
final ParameterAwareNormalizedNodeWriter parameterWriter = ParameterAwareNormalizedNodeWriter.forStreamWriter(
- writer, 1, null);
+ writer, DepthParameter.min(), null);
parameterWriter.write(leafSetNodeData);
@Test
public void writeLeafSetNodeWithChildrenDepthTest() throws Exception {
final ParameterAwareNormalizedNodeWriter parameterWriter = ParameterAwareNormalizedNodeWriter.forStreamWriter(
- writer, Integer.MAX_VALUE, null);
+ writer, DepthParameter.max(), null);
parameterWriter.write(leafSetNodeData);
@Test
public void writeLeafSetEntryNodeDepthTest() throws Exception {
final ParameterAwareNormalizedNodeWriter parameterWriter = ParameterAwareNormalizedNodeWriter.forStreamWriter(
- writer, Integer.MAX_VALUE, null);
+ writer, DepthParameter.max(), null);
parameterWriter.write(leafSetEntryNodeData);
@Test
public void writeMapEntryNodeUnorderedOnlyKeysDepthTest() throws Exception {
final ParameterAwareNormalizedNodeWriter parameterWriter = ParameterAwareNormalizedNodeWriter.forStreamWriter(
- writer, false, 1, null);
+ writer, false, DepthParameter.min(), null);
parameterWriter.write(mapEntryNodeData);
@Test
public void writeMapEntryNodeUnorderedDepthTest() throws Exception {
final ParameterAwareNormalizedNodeWriter parameterWriter = ParameterAwareNormalizedNodeWriter.forStreamWriter(
- writer, false, Integer.MAX_VALUE, null);
+ writer, false, DepthParameter.max(), null);
parameterWriter.write(mapEntryNodeData);
@Test
public void writeMapEntryNodeOrderedWithoutChildrenTest() throws Exception {
final ParameterAwareNormalizedNodeWriter parameterWriter = ParameterAwareNormalizedNodeWriter.forStreamWriter(
- writer, true, 1, null);
+ writer, true, DepthParameter.min(), null);
parameterWriter.write(mapEntryNodeData);
@Test
public void writeMapEntryNodeOrderedTest() throws Exception {
final ParameterAwareNormalizedNodeWriter parameterWriter = ParameterAwareNormalizedNodeWriter.forStreamWriter(
- writer, true, Integer.MAX_VALUE, null);
+ writer, true, DepthParameter.max(), null);
parameterWriter.write(mapEntryNodeData);
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
+import org.opendaylight.restconf.nb.rfc8040.DepthParameter;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
limitedFields.add(Sets.newHashSet(leafSetEntryNodeIdentifier.getNodeType()));
final ParameterAwareNormalizedNodeWriter parameterWriter = ParameterAwareNormalizedNodeWriter.forStreamWriter(
- writer, 1, limitedFields);
+ writer, DepthParameter.min(), limitedFields);
parameterWriter.write(containerNodeData);
final UriInfo uriInfo = mock(UriInfo.class);
final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
- final String depth = "10";
final String fields = containerChildQName.getLocalName();
parameters.put("content", List.of("config"));
- parameters.put("depth", List.of(depth));
+ parameters.put("depth", List.of("10"));
parameters.put("fields", List.of(fields));
when(uriInfo.getQueryParameters()).thenReturn(parameters);
assertEquals(ContentParameter.CONFIG, parsedParameters.getContent());
// depth
- assertNotNull("Not correctly parsed URI parameter",
- parsedParameters.getDepth());
- assertEquals("Not correctly parsed URI parameter",
- depth, parsedParameters.getDepth().toString());
+ final DepthParameter depth = parsedParameters.getDepth();
+ assertNotNull(depth);
+ assertEquals(10, depth.value());
// fields
- assertNotNull("Not correctly parsed URI parameter",
- parsedParameters.getFields());
- assertEquals("Not correctly parsed URI parameter",
- 1, parsedParameters.getFields().size());
- assertEquals("Not correctly parsed URI parameter",
- 1, parsedParameters.getFields().get(0).size());
- assertEquals("Not correctly parsed URI parameter",
- containerChildQName, parsedParameters.getFields().get(0).iterator().next());
+ assertNotNull(parsedParameters.getFields());
+ assertEquals(1, parsedParameters.getFields().size());
+ assertEquals(1, parsedParameters.getFields().get(0).size());
+ assertEquals(containerChildQName, parsedParameters.getFields().get(0).iterator().next());
}
/**