import org.opendaylight.restconf.common.errors.RestconfError.ErrorType;
import org.opendaylight.yangtools.yang.common.OperationFailedException;
import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.YangError;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.codec.YangInvalidValueException;
/**
* Unchecked exception to communicate error information, as defined in the ietf restcong draft, to be sent to the
return obj;
}
+ /**
+ * Throw an instance of this exception if the specified exception has a {@link YangError} attachment.
+ *
+ * @param cause Proposed cause of a RestconfDocumented exception
+ */
+ public static void throwIfYangError(final Throwable cause) {
+ if (cause instanceof YangError) {
+ final YangError error = (YangError) cause;
+ throw new RestconfDocumentedException(cause, new RestconfError(ErrorType.valueOf(error.getErrorType()),
+ // FIXME: this is a special-case until we have YangError.getTag()
+ cause instanceof YangInvalidValueException ? ErrorTag.INVALID_VALUE : ErrorTag.MALFORMED_MESSAGE,
+ error.getErrorMessage().orElse(null), error.getErrorAppTag().orElse(null)));
+ }
+ }
+
private static List<RestconfError> convertToRestconfErrors(final Collection<? extends RpcError> rpcErrors) {
final List<RestconfError> errorList = new ArrayList<>();
if (rpcErrors != null) {
import java.io.Serializable;
import java.util.Locale;
+import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.yangtools.yang.common.RpcError;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.slf4j.Logger;
private static final Logger LOG = LoggerFactory.getLogger(RestconfError.class);
private static final long serialVersionUID = 1L;
+ // FIXME: remove this enum in favor of RpcError.ErrorType (or its equivalent)
public enum ErrorType {
/**
* Errors relating to the transport layer.
return APPLICATION;
}
}
+
+ public static @NonNull ErrorType valueOf(final RpcError.ErrorType errorType) {
+ switch (errorType) {
+ case PROTOCOL:
+ return PROTOCOL;
+ case RPC:
+ return RPC;
+ case TRANSPORT:
+ return TRANSPORT;
+ case APPLICATION:
+ default:
+ return APPLICATION;
+ }
+ }
}
public enum ErrorTag {
*/
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;
}
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);
}
*/
package org.opendaylight.netconf.sal.rest.impl;
+import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
private static final Logger LOG = LoggerFactory.getLogger(JsonToPatchBodyReader.class);
- public JsonToPatchBodyReader(ControllerContext controllerContext) {
+ public JsonToPatchBodyReader(final ControllerContext controllerContext) {
super(controllerContext);
}
}
private static RuntimeException 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. ");
}
+ RestconfDocumentedException.throwIfYangError(exception);
throw new RestconfDocumentedException("Error parsing json input: " + exception.getMessage(), ErrorType.PROTOCOL,
ErrorTag.MALFORMED_MESSAGE, exception);
}
throw e;
} catch (final Exception e) {
LOG.debug("Error parsing xml input", e);
-
+ RestconfDocumentedException.throwIfYangError(e);
throw new RestconfDocumentedException("Error parsing input: " + e.getMessage(), ErrorType.PROTOCOL,
ErrorTag.MALFORMED_MESSAGE, e);
}
throw e;
} catch (final Exception e) {
LOG.debug("Error parsing xml input", e);
-
+ RestconfDocumentedException.throwIfYangError(e);
throw new RestconfDocumentedException("Error parsing input: " + e.getMessage(), ErrorType.PROTOCOL,
ErrorTag.MALFORMED_MESSAGE, e);
}
*/
package org.opendaylight.restconf.nb.rfc8040.jersey.providers;
+import com.google.common.base.Throwables;
import com.google.common.collect.Iterables;
import com.google.gson.stream.JsonReader;
import java.io.InputStream;
}
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);
}
throw e;
} catch (final Exception e) {
LOG.debug("Error parsing xml input", e);
-
+ RestconfDocumentedException.throwIfYangError(e);
throw new RestconfDocumentedException("Error parsing input: " + e.getMessage(), ErrorType.PROTOCOL,
ErrorTag.MALFORMED_MESSAGE, e);
}
import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;
+import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
}
private static RuntimeException 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. ");
}
+ RestconfDocumentedException.throwIfYangError(exception);
throw new RestconfDocumentedException("Error parsing json input: " + exception.getMessage(), ErrorType.PROTOCOL,
ErrorTag.MALFORMED_MESSAGE, exception);
}
*/
package org.opendaylight.restconf.nb.rfc8040.jersey.providers.test;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.Collections;
+import java.util.List;
import java.util.Optional;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Request;
+import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;
+import org.junit.function.ThrowingRunnable;
import org.opendaylight.mdsal.dom.api.DOMMountPoint;
import org.opendaylight.mdsal.dom.api.DOMMountPointService;
import org.opendaylight.mdsal.dom.api.DOMSchemaService;
import org.opendaylight.mdsal.dom.spi.FixedDOMSchemaService;
import org.opendaylight.restconf.common.context.NormalizedNodeContext;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.errors.RestconfError;
+import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
+import org.opendaylight.restconf.common.errors.RestconfError.ErrorType;
import org.opendaylight.restconf.common.patch.PatchContext;
import org.opendaylight.restconf.nb.rfc8040.TestRestconfUtils;
import org.opendaylight.restconf.nb.rfc8040.TestUtils;
.orElse(null);
}
+ protected static void assertRangeViolation(final ThrowingRunnable runnable) {
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class, runnable);
+ assertEquals(Status.BAD_REQUEST, ex.getResponse().getStatusInfo());
+
+ final List<RestconfError> errors = ex.getErrors();
+ assertEquals(1, errors.size());
+
+ final RestconfError error = errors.get(0);
+ assertEquals(ErrorType.PROTOCOL, error.getErrorType());
+ assertEquals(ErrorTag.INVALID_VALUE, error.getErrorTag());
+ assertEquals("bar error app tag", error.getErrorAppTag());
+ assertEquals("bar error message", error.getErrorMessage());
+ }
}
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-
package org.opendaylight.restconf.nb.rfc8040.jersey.providers.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import com.google.common.collect.Sets;
+import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.net.URI;
+import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Optional;
import javax.ws.rs.core.MediaType;
checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue, dataII);
}
+ @Test
+ public void testRangeViolation() throws Exception {
+ mockBodyReader("netconf786:foo", this.jsonBodyReader, false);
+
+ final InputStream inputStream = new ByteArrayInputStream(("{\n"
+ + " \"netconf786:foo\": {\n"
+ + " \"bar\": 100\n"
+ + " }\n"
+ + "}").getBytes(StandardCharsets.UTF_8));
+
+ assertRangeViolation(() -> jsonBodyReader.readFrom(null, null, null, this.mediaType, null, inputStream));
+ }
+
private static void checkExpectValueNormalizeNodeContext(final DataSchemaNode dataSchemaNode,
final NormalizedNodeContext nnContext, final YangInstanceIdentifier dataNodeIdent) {
assertEquals(dataSchemaNode, nnContext.getInstanceIdentifierContext().getSchemaNode());
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-
package org.opendaylight.restconf.nb.rfc8040.jersey.providers.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import com.google.common.collect.Sets;
+import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.net.URI;
+import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Optional;
import javax.ws.rs.core.MediaType;
}
}
+ @Test
+ public void testRangeViolation() throws Exception {
+ mockBodyReader("netconf786:foo", this.xmlBodyReader, false);
+
+ final InputStream inputStream = new ByteArrayInputStream(
+ "<foo xmlns=\"netconf786\"><bar>100</bar></foo>".getBytes(StandardCharsets.UTF_8));
+
+ assertRangeViolation(() -> xmlBodyReader.readFrom(null, null, null, this.mediaType, null, inputStream));
+ }
}
--- /dev/null
+module netconf786 {
+ namespace netconf786;
+ prefix netconf786;
+
+ container foo {
+ leaf bar {
+ type uint32 {
+ range 1000..2000 {
+ error-message "bar error message";
+ error-app-tag "bar error app tag";
+ }
+ }
+ }
+ }
+}