use of org.opendaylight.restconf.common.errors.RestconfDocumentedException in project netconf by opendaylight.
the class RestconfImpl method updateConfigurationData.
@Override
public Response updateConfigurationData(final String identifier, final NormalizedNodeContext payload, final UriInfo uriInfo) {
boolean insertUsed = false;
boolean pointUsed = false;
String insert = null;
String point = null;
for (final Entry<String, List<String>> entry : uriInfo.getQueryParameters().entrySet()) {
switch(entry.getKey()) {
case "insert":
if (!insertUsed) {
insertUsed = true;
insert = entry.getValue().iterator().next();
} else {
throw new RestconfDocumentedException("Insert parameter can be used only once.");
}
break;
case "point":
if (!pointUsed) {
pointUsed = true;
point = entry.getValue().iterator().next();
} else {
throw new RestconfDocumentedException("Point parameter can be used only once.");
}
break;
default:
throw new RestconfDocumentedException("Bad parameter for post: " + entry.getKey());
}
}
if (pointUsed && !insertUsed) {
throw new RestconfDocumentedException("Point parameter can't be used without Insert parameter.");
}
if (pointUsed && (insert.equals("first") || insert.equals("last"))) {
throw new RestconfDocumentedException("Point parameter can be used only with 'after' or 'before' values of Insert parameter.");
}
requireNonNull(identifier);
final InstanceIdentifierContext<?> iiWithData = payload.getInstanceIdentifierContext();
validateInput(iiWithData.getSchemaNode(), payload);
validateTopLevelNodeName(payload, iiWithData.getInstanceIdentifier());
validateListKeysEqualityInPayloadAndUri(payload);
final DOMMountPoint mountPoint = iiWithData.getMountPoint();
final YangInstanceIdentifier normalizedII = iiWithData.getInstanceIdentifier();
/*
* There is a small window where another write transaction could be
* updating the same data simultaneously and we get an
* OptimisticLockFailedException. This error is likely transient and The
* WriteTransaction#submit API docs state that a retry will likely
* succeed. So we'll try again if that scenario occurs. If it fails a
* third time then it probably will never succeed so we'll fail in that
* case.
*
* By retrying we're attempting to hide the internal implementation of
* the data store and how it handles concurrent updates from the
* restconf client. The client has instructed us to put the data and we
* should make every effort to do so without pushing optimistic lock
* failures back to the client and forcing them to handle it via retry
* (and having to document the behavior).
*/
PutResult result = null;
int tries = 2;
while (true) {
if (mountPoint != null) {
result = broker.commitMountPointDataPut(mountPoint, normalizedII, payload.getData(), insert, point);
} else {
result = broker.commitConfigurationDataPut(controllerContext.getGlobalSchema(), normalizedII, payload.getData(), insert, point);
}
try {
result.getFutureOfPutData().get();
} catch (final InterruptedException e) {
LOG.debug("Update failed for {}", identifier, e);
throw new RestconfDocumentedException(e.getMessage(), e);
} catch (final ExecutionException e) {
final TransactionCommitFailedException failure = Throwables.getCauseAs(e, TransactionCommitFailedException.class);
if (failure instanceof OptimisticLockFailedException) {
if (--tries <= 0) {
LOG.debug("Got OptimisticLockFailedException on last try - failing {}", identifier);
throw new RestconfDocumentedException(e.getMessage(), e, failure.getErrorList());
}
LOG.debug("Got OptimisticLockFailedException - trying again {}", identifier);
continue;
}
LOG.debug("Update failed for {}", identifier, e);
throw RestconfDocumentedException.decodeAndThrow(e.getMessage(), failure);
}
return Response.status(result.getStatus()).build();
}
}
use of org.opendaylight.restconf.common.errors.RestconfDocumentedException in project netconf by opendaylight.
the class RestconfImpl method readConfigurationData.
@Override
public NormalizedNodeContext readConfigurationData(final String identifier, final UriInfo uriInfo) {
boolean withDefaUsed = false;
String withDefa = null;
for (final Entry<String, List<String>> entry : uriInfo.getQueryParameters().entrySet()) {
switch(entry.getKey()) {
case "with-defaults":
if (!withDefaUsed) {
withDefaUsed = true;
withDefa = entry.getValue().iterator().next();
} else {
throw new RestconfDocumentedException("With-defaults parameter can be used only once.");
}
break;
default:
LOG.info("Unknown key : {}.", entry.getKey());
break;
}
}
// TODO: this flag is always ignored
boolean tagged = false;
if (withDefaUsed) {
if ("report-all-tagged".equals(withDefa)) {
tagged = true;
withDefa = null;
}
if ("report-all".equals(withDefa)) {
withDefa = null;
}
}
final InstanceIdentifierContext<?> iiWithData = controllerContext.toInstanceIdentifier(identifier);
final DOMMountPoint mountPoint = iiWithData.getMountPoint();
NormalizedNode data = null;
final YangInstanceIdentifier normalizedII = iiWithData.getInstanceIdentifier();
if (mountPoint != null) {
data = broker.readConfigurationData(mountPoint, normalizedII, withDefa);
} else {
data = broker.readConfigurationData(normalizedII, withDefa);
}
if (data == null) {
throw dataMissing(identifier);
}
return new NormalizedNodeContext(iiWithData, data, QueryParametersParser.parseWriterParameters(uriInfo));
}
use of org.opendaylight.restconf.common.errors.RestconfDocumentedException in project netconf by opendaylight.
the class XmlToPatchBodyReader method readValueNodes.
/**
* Read value nodes.
*
* @param element Element of current edit operation
* @param operation Name of current operation
* @return List of value elements
*/
private static List<Element> readValueNodes(@NonNull final Element element, @NonNull final PatchEditOperation operation) {
final Node valueNode = element.getElementsByTagName("value").item(0);
if (operation.isWithValue() && valueNode == null) {
throw new RestconfDocumentedException("Error parsing input", ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE);
}
if (!operation.isWithValue() && valueNode != null) {
throw new RestconfDocumentedException("Error parsing input", ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE);
}
if (valueNode == null) {
return null;
}
final List<Element> result = new ArrayList<>();
final NodeList childNodes = valueNode.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
if (childNodes.item(i) instanceof Element) {
result.add((Element) childNodes.item(i));
}
}
return result;
}
use of org.opendaylight.restconf.common.errors.RestconfDocumentedException in project netconf by opendaylight.
the class RestconfDocumentedExceptionMapperTest method testToResponseWithAcceptHeader.
@Test
public void testToResponseWithAcceptHeader() throws Exception {
stageMockEx(new RestconfDocumentedException("mock error"));
final Response resp = target("/operational/foo").request().header("Accept", MediaType.APPLICATION_JSON).get();
final InputStream stream = verifyResponse(resp, MediaType.APPLICATION_JSON, Status.INTERNAL_SERVER_ERROR);
verifyJsonResponseBody(stream, ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, "mock error", null, null);
}
use of org.opendaylight.restconf.common.errors.RestconfDocumentedException in project netconf by opendaylight.
the class RestconfDocumentedExceptionMapperTest method testToJsonResponseWithExceptionCause.
@Test
public void testToJsonResponseWithExceptionCause() throws Exception {
final Exception cause = new Exception("mock exception cause");
testJsonResponse(new RestconfDocumentedException("mock error", cause), Status.INTERNAL_SERVER_ERROR, ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, "mock error", null, new SimpleErrorInfoVerifier(cause.getMessage()));
}
Aggregations