*/
package org.opendaylight.netconf.sal.rest.impl;
+import com.google.common.base.Throwables;
import com.google.common.collect.Iterables;
import com.google.gson.stream.JsonReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
+import java.util.Optional;
import javax.ws.rs.Consumes;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import org.opendaylight.netconf.sal.rest.api.RestconfService;
import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
-import org.opendaylight.restconf.common.context.NormalizedNodeContext;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
-import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
-import org.opendaylight.restconf.common.errors.RestconfError.ErrorType;
+import org.opendaylight.restconf.common.util.RestUtil;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.common.ErrorType;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
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.MapNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactorySupplier;
import org.opendaylight.yangtools.yang.data.codec.gson.JsonParserStream;
import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
import org.opendaylight.yangtools.yang.data.impl.schema.ResultAlreadySetException;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaNode;
-import org.opendaylight.yangtools.yang.model.api.SchemaPath;
-import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
+import org.opendaylight.yangtools.yang.model.api.stmt.RpcEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Provider
-@Consumes({ Draft02.MediaTypes.DATA + RestconfService.JSON, Draft02.MediaTypes.OPERATION + RestconfService.JSON,
- MediaType.APPLICATION_JSON })
+@Consumes({
+ Draft02.MediaTypes.DATA + RestconfService.JSON,
+ Draft02.MediaTypes.OPERATION + RestconfService.JSON,
+ MediaType.APPLICATION_JSON
+})
public class JsonNormalizedNodeBodyReader
extends AbstractIdentifierAwareJaxRsProvider implements MessageBodyReader<NormalizedNodeContext> {
private static final Logger LOG = LoggerFactory.getLogger(JsonNormalizedNodeBodyReader.class);
+ public JsonNormalizedNodeBodyReader(final ControllerContext controllerContext) {
+ super(controllerContext);
+ }
+
@Override
public boolean isReadable(final Class<?> type, final Type genericType, final Annotation[] annotations,
final MediaType mediaType) {
@Override
public NormalizedNodeContext readFrom(final Class<NormalizedNodeContext> type, final Type genericType,
final Annotation[] annotations, final MediaType mediaType,
- final MultivaluedMap<String, String> httpHeaders, final InputStream entityStream) throws IOException,
- WebApplicationException {
+ final MultivaluedMap<String, String> httpHeaders, final InputStream entityStream) throws
+ WebApplicationException {
try {
return readFrom(getInstanceIdentifierContext(), entityStream, isPost());
} catch (final Exception e) {
@SuppressWarnings("checkstyle:IllegalCatch")
public static NormalizedNodeContext readFrom(final String uriPath, final InputStream entityStream,
- final boolean isPost) throws RestconfDocumentedException {
+ final boolean isPost, final ControllerContext controllerContext) throws RestconfDocumentedException {
try {
- return readFrom(ControllerContext.getInstance().toInstanceIdentifier(uriPath), entityStream, isPost);
+ return readFrom(controllerContext.toInstanceIdentifier(uriPath), entityStream, isPost);
} catch (final Exception e) {
propagateExceptionAs(e);
return null; // no-op
private static NormalizedNodeContext readFrom(final InstanceIdentifierContext<?> path,
final InputStream entityStream, final boolean isPost)
throws IOException {
- if (entityStream.available() < 1) {
+ final Optional<InputStream> nonEmptyInputStreamOptional = RestUtil.isInputStreamEmpty(entityStream);
+ if (nonEmptyInputStreamOptional.isEmpty()) {
return new NormalizedNodeContext(path, null);
}
final NormalizedNodeResult resultHolder = new NormalizedNodeResult();
final NormalizedNodeStreamWriter writer = ImmutableNormalizedNodeStreamWriter.from(resultHolder);
- final SchemaNode parentSchema;
- if (isPost) {
- // FIXME: We need dispatch for RPC.
- parentSchema = path.getSchemaNode();
- } else if (path.getSchemaNode() instanceof SchemaContext) {
- parentSchema = path.getSchemaContext();
+ final SchemaInferenceStack stack;
+ if (path.getSchemaNode() instanceof RpcEffectiveStatement) {
+ stack = SchemaInferenceStack.of(path.getSchemaContext(), Absolute.of(path.getSchemaNode().getQName()));
} else {
- if (SchemaPath.ROOT.equals(path.getSchemaNode().getPath().getParent())) {
- parentSchema = path.getSchemaContext();
- } else {
- parentSchema = SchemaContextUtil
- .findDataSchemaNode(path.getSchemaContext(), path.getSchemaNode().getPath().getParent());
- }
+ stack = SchemaInferenceStack.of(path.getSchemaContext());
+ path.getInstanceIdentifier().getPathArguments().stream()
+ .filter(arg -> !(arg instanceof YangInstanceIdentifier.NodeIdentifierWithPredicates))
+ .filter(arg -> !(arg instanceof YangInstanceIdentifier.AugmentationIdentifier))
+ .forEach(p -> stack.enterSchemaTree(p.getNodeType()));
+ }
+
+ if (!isPost) {
+ stack.exit();
}
- final JsonParserStream jsonParser = JsonParserStream.create(writer, path.getSchemaContext(), parentSchema);
- final JsonReader reader = new JsonReader(new InputStreamReader(entityStream));
+ final JsonParserStream jsonParser = JsonParserStream.create(writer,
+ JSONCodecFactorySupplier.DRAFT_LHOTKA_NETMOD_YANG_JSON_02.getShared(path.getSchemaContext()),
+ stack.toInference());
+ final JsonReader reader = new JsonReader(new InputStreamReader(nonEmptyInputStreamOptional.get(),
+ StandardCharsets.UTF_8));
jsonParser.parse(reader);
- NormalizedNode<?, ?> result = resultHolder.getResult();
+ NormalizedNode result = resultHolder.getResult();
final List<YangInstanceIdentifier.PathArgument> iiToDataList = new ArrayList<>();
InstanceIdentifierContext<? extends SchemaNode> newIIContext;
while (result instanceof AugmentationNode || result instanceof ChoiceNode) {
- final Object childNode = ((DataContainerNode<?>) result).getValue().iterator().next();
+ final Object childNode = ((DataContainerNode) result).body().iterator().next();
if (isPost) {
iiToDataList.add(result.getIdentifier());
}
- result = (NormalizedNode<?, ?>) childNode;
+ result = (NormalizedNode) childNode;
}
if (isPost) {
if (result instanceof MapEntryNode) {
- iiToDataList.add(new YangInstanceIdentifier.NodeIdentifier(result.getNodeType()));
+ iiToDataList.add(new YangInstanceIdentifier.NodeIdentifier(result.getIdentifier().getNodeType()));
iiToDataList.add(result.getIdentifier());
} else {
iiToDataList.add(result.getIdentifier());
}
} else {
if (result instanceof MapNode) {
- result = Iterables.getOnlyElement(((MapNode) result).getValue());
+ result = Iterables.getOnlyElement(((MapNode) result).body());
}
}
}
private static void propagateExceptionAs(final Exception exception) throws RestconfDocumentedException {
- if (exception instanceof RestconfDocumentedException) {
- throw (RestconfDocumentedException)exception;
- }
+ Throwables.throwIfInstanceOf(exception, RestconfDocumentedException.class);
+ LOG.debug("Error parsing json input", exception);
if (exception instanceof ResultAlreadySetException) {
- LOG.debug("Error parsing json input:", exception);
-
throw new RestconfDocumentedException("Error parsing json input: Failed to create new parse result data. "
+ "Are you creating multiple resources/subresources in POST request?", exception);
}
- LOG.debug("Error parsing json input", exception);
-
+ RestconfDocumentedException.throwIfYangError(exception);
throw new RestconfDocumentedException("Error parsing input: " + exception.getMessage(), ErrorType.PROTOCOL,
ErrorTag.MALFORMED_MESSAGE, exception);
}