import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyWriter;
import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.restconf.nb.rfc8040.legacy.InstanceIdentifierContext;
import org.opendaylight.restconf.nb.rfc8040.legacy.NormalizedNodePayload;
import org.opendaylight.restconf.nb.rfc8040.legacy.QueryParameters;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.stmt.ActionEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.RpcEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
abstract class AbstractNormalizedNodeBodyWriter implements MessageBodyWriter<NormalizedNodePayload> {
@Override
}
}
- writeTo(context.getInstanceIdentifierContext(), context.getWriterParameters(), data,
- requireNonNull(entityStream));
+ final var output = requireNonNull(entityStream);
+ final var iidContext = context.getInstanceIdentifierContext();
+ final var stack = iidContext.inference().toSchemaInferenceStack();
+ // FIXME: this dispatch is here to handle codec transition to 'output', but that should be completely okay with
+ // the instantiation path we are using (based in Inference).
+ if (!stack.isEmpty()) {
+ final var stmt = stack.currentStatement();
+ if (stmt instanceof RpcEffectiveStatement rpc) {
+ stack.enterSchemaTree(rpc.output().argument());
+ writeOperationOutput(stack, context.getWriterParameters(), (ContainerNode) data, output);
+ } else if (stmt instanceof ActionEffectiveStatement action) {
+ stack.enterSchemaTree(action.output().argument());
+ writeOperationOutput(stack, context.getWriterParameters(), (ContainerNode) data, output);
+ }
+ }
+ writeData(stack, context.getWriterParameters(), data, output);
}
- abstract void writeTo(@NonNull InstanceIdentifierContext context, @NonNull QueryParameters writerParameters,
+ abstract void writeOperationOutput(@NonNull SchemaInferenceStack stack, @NonNull QueryParameters writerParameters,
+ @NonNull ContainerNode output, @NonNull OutputStream entityStream) throws IOException;
+
+ abstract void writeData(@NonNull SchemaInferenceStack stack, @NonNull QueryParameters writerParameters,
@NonNull NormalizedNode data, @NonNull OutputStream entityStream) throws IOException;
}
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
-import java.util.List;
-import java.util.Set;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.Provider;
import org.eclipse.jdt.annotation.Nullable;
-import org.opendaylight.restconf.api.query.DepthParam;
+import org.opendaylight.restconf.api.query.PrettyPrintParam;
import org.opendaylight.restconf.nb.rfc8040.MediaTypes;
import org.opendaylight.restconf.nb.rfc8040.jersey.providers.api.RestconfNormalizedNodeWriter;
-import org.opendaylight.restconf.nb.rfc8040.legacy.InstanceIdentifierContext;
import org.opendaylight.restconf.nb.rfc8040.legacy.QueryParameters;
-import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.XMLNamespace;
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
import org.opendaylight.yangtools.yang.data.codec.gson.JSONNormalizedNodeStreamWriter;
import org.opendaylight.yangtools.yang.data.codec.gson.JsonWriterFactory;
import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
-import org.opendaylight.yangtools.yang.model.api.ActionDefinition;
-import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack.Inference;
private static final int DEFAULT_INDENT_SPACES_NUM = 2;
@Override
- void writeTo(final InstanceIdentifierContext context, final QueryParameters writerParameters,
- final NormalizedNode data, final OutputStream entityStream) throws IOException {
- final var pretty = writerParameters.prettyPrint();
- try (var jsonWriter = createJsonWriter(entityStream, pretty == null ? false : pretty.value())) {
- jsonWriter.beginObject();
- writeNormalizedNode(jsonWriter, context, data, writerParameters.depth(), writerParameters.fields());
- jsonWriter.endObject();
- jsonWriter.flush();
+ void writeOperationOutput(final SchemaInferenceStack stack, final QueryParameters writerParameters,
+ final ContainerNode output, final OutputStream entityStream) throws IOException {
+ // RpcDefinition/ActionDefinition is not supported as initial codec in JSONStreamWriter, so we need to emit
+ // initial output declaration
+ try (var jsonWriter = createJsonWriter(entityStream, writerParameters.prettyPrint())) {
+ final var module = stack.currentModule();
+ jsonWriter.beginObject().name(module.argument().getLocalName() + ":output").beginObject();
+
+ final var nnWriter = createNormalizedNodeWriter(stack.toInference(), jsonWriter, writerParameters,
+ module.namespace().argument());
+ writeChildren(nnWriter, output);
+ nnWriter.flush();
+
+ jsonWriter.endObject().endObject();
}
}
- private static void writeNormalizedNode(final JsonWriter jsonWriter, final InstanceIdentifierContext context,
- final NormalizedNode data, final DepthParam depth, final List<Set<QName>> fields) throws IOException {
- final var schemaNode = context.getSchemaNode();
- if (schemaNode instanceof RpcDefinition rpc) {
- // RpcDefinition is not supported as initial codec in JSONStreamWriter, so we need to emit initial output
- // declaration
- final var stack = SchemaInferenceStack.of(context.getSchemaContext());
- stack.enterSchemaTree(rpc.getQName());
- stack.enterSchemaTree(rpc.getOutput().getQName());
-
- jsonWriter.name(stack.currentModule().argument().getLocalName() + ":output");
- jsonWriter.beginObject();
-
- final var nnWriter = createNormalizedNodeWriter(context, stack.toInference(), jsonWriter, depth, fields,
- rpc.getQName().getNamespace());
- writeChildren(nnWriter, (ContainerNode) data);
- nnWriter.flush();
-
- jsonWriter.endObject();
- } else if (schemaNode instanceof ActionDefinition action) {
- // FIXME: why is this different from RPC?!
+ @Override
+ void writeData(final SchemaInferenceStack stack, final QueryParameters writerParameters, final NormalizedNode data,
+ final OutputStream entityStream) throws IOException {
+ if (!stack.isEmpty()) {
+ stack.exit();
+ }
- // ActionDefinition is not supported as initial codec in JSONStreamWriter, so we need to emit initial output
- // declaration
- final var stack = context.inference().toSchemaInferenceStack();
- stack.enterSchemaTree(action.getOutput().getQName());
+ // RESTCONF allows returning one list item. We need to wrap it in map node in order to serialize it properly
+ final var toSerialize = data instanceof MapEntryNode mapEntry
+ ? ImmutableNodes.mapNodeBuilder(data.name().getNodeType()).withChild(mapEntry).build() : data;
- jsonWriter.name(stack.currentModule().argument().getLocalName() + ":output");
+ try (var jsonWriter = createJsonWriter(entityStream, writerParameters.prettyPrint())) {
jsonWriter.beginObject();
- final var nnWriter = createNormalizedNodeWriter(context, stack.toInference(), jsonWriter, depth, fields,
- null);
- writeChildren(nnWriter, (ContainerNode) data);
- nnWriter.flush();
-
- jsonWriter.endObject();
- } else {
- final var stack = context.inference().toSchemaInferenceStack();
- if (!stack.isEmpty()) {
- stack.exit();
- }
-
- // RESTCONF allows returning one list item. We need to wrap it in map node in order to serialize it properly
- final var toSerialize = data instanceof MapEntryNode mapEntry
- ? ImmutableNodes.mapNodeBuilder(data.name().getNodeType()).withChild(mapEntry).build() : data;
-
- final var nnWriter = createNormalizedNodeWriter(context, stack.toInference(), jsonWriter, depth, fields,
- null);
+ final var nnWriter = createNormalizedNodeWriter(stack.toInference(), jsonWriter, writerParameters, null);
nnWriter.write(toSerialize);
nnWriter.flush();
+
+ jsonWriter.endObject().flush();
}
}
}
}
- private static RestconfNormalizedNodeWriter createNormalizedNodeWriter(final InstanceIdentifierContext context,
- final Inference inference, final JsonWriter jsonWriter, final DepthParam depth,
- final List<Set<QName>> fields, final @Nullable XMLNamespace initialNamespace) {
+ private static RestconfNormalizedNodeWriter createNormalizedNodeWriter(final Inference inference,
+ final JsonWriter jsonWriter, final QueryParameters writerParameters,
+ final @Nullable XMLNamespace initialNamespace) {
// TODO: Performance: Cache JSON Codec factory and schema context
- final var codecs = JSONCodecFactorySupplier.RFC7951.getShared(context.getSchemaContext());
+ final var codecs = JSONCodecFactorySupplier.RFC7951.getShared(inference.getEffectiveModelContext());
return ParameterAwareNormalizedNodeWriter.forStreamWriter(
JSONNormalizedNodeStreamWriter.createNestedWriter(codecs, inference,
- initialNamespace, jsonWriter), depth, fields);
+ initialNamespace, jsonWriter), writerParameters.depth(), writerParameters.fields());
}
- private static JsonWriter createJsonWriter(final OutputStream entityStream, final boolean prettyPrint) {
+ private static JsonWriter createJsonWriter(final OutputStream entityStream,
+ final @Nullable PrettyPrintParam prettyPrint) {
final var outputWriter = new OutputStreamWriter(entityStream, StandardCharsets.UTF_8);
- return prettyPrint ? JsonWriterFactory.createJsonWriter(outputWriter, DEFAULT_INDENT_SPACES_NUM)
- : JsonWriterFactory.createJsonWriter(outputWriter);
+ return prettyPrint != null && prettyPrint.value()
+ ? JsonWriterFactory.createJsonWriter(outputWriter, DEFAULT_INDENT_SPACES_NUM)
+ : JsonWriterFactory.createJsonWriter(outputWriter);
}
}
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
-import java.util.List;
-import java.util.Set;
import javanet.staxutils.IndentingXMLStreamWriter;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
-import org.opendaylight.restconf.api.query.DepthParam;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.restconf.api.query.PrettyPrintParam;
import org.opendaylight.restconf.nb.rfc8040.MediaTypes;
import org.opendaylight.restconf.nb.rfc8040.jersey.providers.api.RestconfNormalizedNodeWriter;
-import org.opendaylight.restconf.nb.rfc8040.legacy.InstanceIdentifierContext;
import org.opendaylight.restconf.nb.rfc8040.legacy.QueryParameters;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.data.codec.xml.XMLStreamNormalizedNodeStreamWriter;
import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
-import org.opendaylight.yangtools.yang.model.api.ActionDefinition;
-import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack.Inference;
}
@Override
- void writeTo(final InstanceIdentifierContext context, final QueryParameters writerParameters,
- final NormalizedNode data, final OutputStream entityStream) throws IOException {
- XMLStreamWriter xmlWriter;
- try {
- xmlWriter = XML_FACTORY.createXMLStreamWriter(entityStream, StandardCharsets.UTF_8.name());
-
- final var prettyPrint = writerParameters.prettyPrint();
- if (prettyPrint != null && prettyPrint.value()) {
- xmlWriter = new IndentingXMLStreamWriter(xmlWriter);
- }
- } catch (XMLStreamException | FactoryConfigurationError e) {
- throw new IllegalStateException(e);
- }
-
- writeNormalizedNode(xmlWriter, context, data, writerParameters.depth(), writerParameters.fields());
+ void writeOperationOutput(final SchemaInferenceStack stack, final QueryParameters writerParameters,
+ final ContainerNode output, final OutputStream entityStream) throws IOException {
+ // RpcDefinition/ActionDefinition is not supported as initial codec in XMLStreamWriter, so we need to emit
+ // initial output declaration.
+ final var xmlWriter = createXmlWriter(entityStream, writerParameters.prettyPrint());
+ final var nnWriter = createNormalizedNodeWriter(xmlWriter, stack.toInference(), writerParameters);
+ writeElements(xmlWriter, nnWriter, output);
+ nnWriter.flush();
}
- private static void writeNormalizedNode(final XMLStreamWriter xmlWriter,
- final InstanceIdentifierContext pathContext, final NormalizedNode data, final DepthParam depth,
- final List<Set<QName>> fields) throws IOException {
- final var schemaNode = pathContext.getSchemaNode();
- if (schemaNode instanceof RpcDefinition rpc) {
- // RpcDefinition is not supported as initial codec in XMLStreamWriter, so we need to emit initial output
- // declaration.
- final var stack = SchemaInferenceStack.of(pathContext.getSchemaContext());
- stack.enterSchemaTree(rpc.getQName());
- stack.enterSchemaTree(rpc.getOutput().getQName());
-
- final var nnWriter = createNormalizedNodeWriter(xmlWriter, stack.toInference(), depth, fields);
- writeElements(xmlWriter, nnWriter, (ContainerNode) data);
- nnWriter.flush();
- } else if (schemaNode instanceof ActionDefinition action) {
- // ActionDefinition is not supported as initial codec in XMLStreamWriter, so we need to emit initial output
- // declaration.
- final var stack = pathContext.inference().toSchemaInferenceStack();
- stack.enterSchemaTree(action.getOutput().getQName());
-
- final var nnWriter = createNormalizedNodeWriter(xmlWriter, stack.toInference(), depth, fields);
- writeElements(xmlWriter, nnWriter, (ContainerNode) data);
- nnWriter.flush();
+ @Override
+ void writeData(final SchemaInferenceStack stack, final QueryParameters writerParameters, final NormalizedNode data,
+ final OutputStream entityStream) throws IOException {
+ final boolean isRoot;
+ if (!stack.isEmpty()) {
+ stack.exit();
+ isRoot = false;
} else {
- final var stack = pathContext.inference().toSchemaInferenceStack();
- final boolean isRoot;
- if (!stack.isEmpty()) {
- stack.exit();
- isRoot = false;
- } else {
- isRoot = true;
- }
+ isRoot = true;
+ }
- final var nnWriter = createNormalizedNodeWriter(xmlWriter, stack.toInference(), depth, fields);
- if (data instanceof MapEntryNode mapEntry) {
- // Restconf allows returning one list item. We need to wrap it
- // in map node in order to serialize it properly
- nnWriter.write(ImmutableNodes.mapNodeBuilder(data.name().getNodeType()).addChild(mapEntry).build());
- } else if (isRoot) {
- if (data instanceof ContainerNode container && container.isEmpty()) {
- writeEmptyDataNode(xmlWriter, container);
- } else {
- writeAndWrapInDataNode(xmlWriter, nnWriter, data);
- }
+ final var xmlWriter = createXmlWriter(entityStream, writerParameters.prettyPrint());
+ final var nnWriter = createNormalizedNodeWriter(xmlWriter, stack.toInference(), writerParameters);
+ if (data instanceof MapEntryNode mapEntry) {
+ // Restconf allows returning one list item. We need to wrap it
+ // in map node in order to serialize it properly
+ nnWriter.write(ImmutableNodes.mapNodeBuilder(data.name().getNodeType()).addChild(mapEntry).build());
+ } else if (isRoot) {
+ if (data instanceof ContainerNode container && container.isEmpty()) {
+ writeEmptyDataNode(xmlWriter, container);
} else {
- nnWriter.write(data);
+ writeAndWrapInDataNode(xmlWriter, nnWriter, data);
}
- nnWriter.flush();
+ } else {
+ nnWriter.write(data);
}
+ nnWriter.flush();
+ }
+
+ private static XMLStreamWriter createXmlWriter(final OutputStream entityStream,
+ final @Nullable PrettyPrintParam prettyPrint) {
+ final XMLStreamWriter xmlWriter;
+ try {
+ xmlWriter = XML_FACTORY.createXMLStreamWriter(entityStream, StandardCharsets.UTF_8.name());
+ } catch (XMLStreamException | FactoryConfigurationError e) {
+ throw new IllegalStateException(e);
+ }
+
+ return prettyPrint != null && prettyPrint.value() ? new IndentingXMLStreamWriter(xmlWriter) : xmlWriter;
}
private static RestconfNormalizedNodeWriter createNormalizedNodeWriter(final XMLStreamWriter xmlWriter,
- final Inference inference, final DepthParam depth,
- final List<Set<QName>> fields) {
+ final Inference inference, final QueryParameters writerParameters) {
return ParameterAwareNormalizedNodeWriter.forStreamWriter(
- XMLStreamNormalizedNodeStreamWriter.create(xmlWriter, inference), depth, fields);
+ XMLStreamNormalizedNodeStreamWriter.create(xmlWriter, inference),
+ writerParameters.depth(), writerParameters.fields());
}
private static void writeAndWrapInDataNode(final XMLStreamWriter xmlWriter,