import org.opendaylight.restconf.api.query.InsertParam;
import org.opendaylight.restconf.api.query.PointParam;
import org.opendaylight.restconf.server.api.DatabindContext;
+import org.opendaylight.restconf.server.api.ServerException;
import org.opendaylight.restconf.server.spi.ApiPathNormalizer;
import org.opendaylight.yangtools.concepts.Immutable;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
@FunctionalInterface
public interface PointNormalizer {
- PathArgument normalizePoint(ApiPath value);
+ PathArgument normalizePoint(ApiPath value) throws ServerException;
}
private final @NonNull InsertParam insert;
}
private static PathArgument parsePoint(final PointNormalizer pointParser, final String value) {
- final ApiPath pointPath;
try {
- pointPath = ApiPath.parse(value);
- } catch (ParseException e) {
+ return pointParser.normalizePoint(ApiPath.parse(value));
+ } catch (ParseException | ServerException e) {
throw new IllegalArgumentException("Malformed point parameter '" + value + "': " + e.getMessage(), e);
}
- return pointParser.normalizePoint(pointPath);
}
private static IllegalArgumentException invalidPointIAE() {
import org.opendaylight.restconf.server.api.ServerError;
import org.opendaylight.restconf.server.api.ServerErrorInfo;
import org.opendaylight.restconf.server.api.ServerErrorPath;
+import org.opendaylight.restconf.server.api.ServerException;
import org.opendaylight.restconf.server.api.ServerRequest;
import org.opendaylight.restconf.server.spi.ApiPathCanonizer;
import org.opendaylight.restconf.server.spi.ApiPathNormalizer;
operations = new OperationsResource(pathNormalizer);
}
- public final @NonNull StrategyAndPath resolveStrategyPath(final ApiPath path) {
+ public final @NonNull StrategyAndPath resolveStrategyPath(final ApiPath path) throws ServerException {
final var andTail = resolveStrategy(path);
final var strategy = andTail.strategy();
return new StrategyAndPath(strategy, strategy.pathNormalizer.normalizeDataPath(andTail.tail()));
* @param path {@link ApiPath} to resolve
* @return A strategy and the remaining path
* @throws NullPointerException if {@code path} is {@code null}
+ * @throws ServerException if an error occurs
*/
- public final @NonNull StrategyAndTail resolveStrategy(final ApiPath path) {
+ public final @NonNull StrategyAndTail resolveStrategy(final ApiPath path) throws ServerException {
var mount = path.indexOf("yang-ext", "mount");
if (mount == -1) {
return new StrategyAndTail(this, path);
}
if (mountPointService == null) {
- throw new RestconfDocumentedException("Mount point service is not available",
- ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED);
+ throw new ServerException(ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED,
+ "Mount point service is not available");
}
final var mountPath = path.subPath(0, mount);
final var dataPath = pathNormalizer.normalizeDataPath(path.subPath(0, mount));
final var mountPoint = mountPointService.getMountPoint(dataPath.instance())
- .orElseThrow(() -> new RestconfDocumentedException("Mount point '" + mountPath + "' does not exist",
- ErrorType.PROTOCOL, ErrorTags.RESOURCE_DENIED_TRANSPORT));
+ .orElseThrow(() -> new ServerException(ErrorType.PROTOCOL, ErrorTags.RESOURCE_DENIED_TRANSPORT,
+ "Mount point '%s' does not exist", mountPath));
- return createStrategy(mountPath, mountPoint).resolveStrategy(path.subPath(mount + 1));
+ return createStrategy(databind, mountPath, mountPoint).resolveStrategy(path.subPath(mount + 1));
}
- private static @NonNull RestconfStrategy createStrategy(final ApiPath mountPath, final DOMMountPoint mountPoint) {
+ private static @NonNull RestconfStrategy createStrategy(final DatabindContext databind, final ApiPath mountPath,
+ final DOMMountPoint mountPoint) throws ServerException {
final var mountSchemaService = mountPoint.getService(DOMSchemaService.class)
- .orElseThrow(() -> new RestconfDocumentedException(
- "Mount point '" + mountPath + "' does not expose DOMSchemaService",
- ErrorType.PROTOCOL, ErrorTags.RESOURCE_DENIED_TRANSPORT));
+ .orElseThrow(() -> new ServerException(ErrorType.PROTOCOL, ErrorTags.RESOURCE_DENIED_TRANSPORT,
+ "Mount point '%s' does not expose DOMSchemaService", mountPath));
final var mountModelContext = mountSchemaService.getGlobalContext();
if (mountModelContext == null) {
- throw new RestconfDocumentedException("Mount point '" + mountPath + "' does not have any models",
- ErrorType.PROTOCOL, ErrorTags.RESOURCE_DENIED_TRANSPORT);
+ throw new ServerException(ErrorType.PROTOCOL, ErrorTags.RESOURCE_DENIED_TRANSPORT,
+ "Mount point '%s' does not have any models", mountPath);
}
final var mountDatabind = DatabindContext.ofModel(mountModelContext);
final var mountPointService = mountPoint.getService(DOMMountPointService.class).orElse(null);
actionService, sourceProvider, mountPointService);
}
LOG.warn("Mount point {} does not expose a suitable access interface", mountPath);
- throw new RestconfDocumentedException("Could not find a supported access interface in mount point",
- ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, mountPoint.getIdentifier());
+ throw new ServerException(ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED,
+ new ServerErrorPath(databind, mountPoint.getIdentifier()),
+ "Could not find a supported access interface in mount point");
}
@Override
final Data path;
try {
path = pathNormalizer.normalizeDataPath(apiPath);
- } catch (RestconfDocumentedException e) {
- return RestconfFuture.failed(e);
+ } catch (ServerException e) {
+ return RestconfFuture.failed(e.toLegacy());
}
final Insert insert;
final Data path;
try {
path = pathNormalizer.normalizeDataPath(apiPath);
- } catch (RestconfDocumentedException e) {
- return RestconfFuture.failed(e);
+ } catch (ServerException e) {
+ return RestconfFuture.failed(e.toLegacy());
}
final NormalizedNode data;
final Data path;
try {
path = pathNormalizer.normalizeDataPath(apiPath);
- } catch (RestconfDocumentedException e) {
- return RestconfFuture.failed(e);
+ } catch (ServerException e) {
+ return RestconfFuture.failed(e.toLegacy());
}
final PatchContext patch;
final Data path;
try {
path = pathNormalizer.normalizeDataPath(apiPath);
- } catch (RestconfDocumentedException e) {
- return RestconfFuture.failed(e);
+ } catch (ServerException e) {
+ return RestconfFuture.failed(e.toLegacy());
}
// FIXME: reject empty YangInstanceIdentifier, as datastores may not be deleted
final Data path;
try {
path = pathNormalizer.normalizeDataPath(apiPath);
- } catch (RestconfDocumentedException e) {
- return RestconfFuture.failed(e);
+ } catch (ServerException e) {
+ return RestconfFuture.failed(e.toLegacy());
}
final DataGetParams getParams;
final Rpc path;
try {
path = pathNormalizer.normalizeRpcPath(apiPath);
- } catch (RestconfDocumentedException e) {
- return RestconfFuture.failed(e);
+ } catch (ServerException e) {
+ return RestconfFuture.failed(e.toLegacy());
}
final ContainerNode data;
final InstanceReference path;
try {
path = pathNormalizer.normalizeDataOrActionPath(apiPath);
- } catch (RestconfDocumentedException e) {
- return RestconfFuture.failed(e);
+ } catch (ServerException e) {
+ return RestconfFuture.failed(e.toLegacy());
}
if (path instanceof Data dataPath) {
try (var resourceBody = body.toResource()) {
*
* @param apiPath sub-resource
* @return A {@link ResourceContext}
- * @throws RestconfDocumentedException if the sub-resource cannot be resolved
+ * @throws ServerException if the sub-resource cannot be resolved
*/
- protected abstract ResourceContext resolveRelative(ApiPath apiPath);
+ protected abstract ResourceContext resolveRelative(ApiPath apiPath) throws ServerException;
}
PatchBody(final InputStream inputStream) {
final Data result;
try {
result = resource.resolveRelative(targetPath).path;
- } catch (RestconfDocumentedException e) {
+ } catch (ServerException e) {
throw new RestconfDocumentedException("Invalid edit target '" + targetPath + "'",
ErrorType.RPC, ErrorTag.MALFORMED_MESSAGE, e);
}
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.opendaylight.restconf.api.ErrorMessage;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.errors.RestconfError;
import org.opendaylight.yangtools.yang.common.ErrorTag;
import org.opendaylight.yangtools.yang.common.ErrorType;
public ServerException(final ErrorType type, final ErrorTag tag, final String message,
final @Nullable Throwable cause) {
- this(requireNonNull(message), new ServerError(type, tag, message), cause);
+ this(requireNonNull(message),
+ new ServerError(type, tag, new ErrorMessage(message), null, null, errorInfoOf(cause)), cause);
}
public ServerException(final ErrorType type, final ErrorTag tag, final String format,
this(type, tag, format.formatted(args));
}
+ public ServerException(final ErrorType type, final ErrorTag tag, final ServerErrorPath path, final String message) {
+ this(message, new ServerError(type, tag, new ErrorMessage(message), null, requireNonNull(path), null), null);
+ }
+
/**
* Return the reported {@link ServerError}.
*
return error;
}
+ @Deprecated
+ public RestconfDocumentedException toLegacy() {
+ final var message = error.message();
+ final var info = error.info();
+ final var path = error.path();
+ if (path != null) {
+ return new RestconfDocumentedException(this,
+ new RestconfError(error.type(), error.tag(), message != null ? message.elementBody() : null,
+ error.appTag(), info != null ? info.elementBody() : null, path.path()),
+ path.databind().modelContext());
+ } else {
+ return new RestconfDocumentedException(this,
+ new RestconfError(error.type(), error.tag(), message != null ? message.elementBody() : null,
+ error.appTag(), info != null ? info.elementBody() : null, null));
+ }
+ }
+
@java.io.Serial
private void readObjectNoData() throws ObjectStreamException {
throw new NotSerializableException();
throw new NotSerializableException();
}
+ private static @Nullable ServerErrorInfo errorInfoOf(final @Nullable Throwable cause) {
+ if (cause != null) {
+ final var message = cause.getMessage();
+ if (message != null) {
+ return new ServerErrorInfo(message);
+ }
+ }
+ return null;
+ }
+
private static ErrorTag errorTagOf(final @Nullable Throwable cause) {
if (cause instanceof UnsupportedOperationException) {
return ErrorTag.OPERATION_NOT_SUPPORTED;
import org.opendaylight.restconf.server.api.PatchBody;
import org.opendaylight.restconf.server.api.ResourceBody;
import org.opendaylight.restconf.server.api.RestconfServer;
+import org.opendaylight.restconf.server.api.ServerException;
import org.opendaylight.restconf.server.api.ServerRequest;
import org.opendaylight.restconf.server.spi.RpcImplementation;
import org.opendaylight.yangtools.yang.common.Empty;
final StrategyAndTail stratAndTail;
try {
stratAndTail = localStrategy().resolveStrategy(identifier);
- } catch (RestconfDocumentedException e) {
- return RestconfFuture.failed(e);
+ } catch (ServerException e) {
+ return RestconfFuture.failed(e.toLegacy());
}
return stratAndTail.strategy().dataDELETE(request, stratAndTail.tail());
}
final StrategyAndTail stratAndTail;
try {
stratAndTail = localStrategy().resolveStrategy(identifier);
- } catch (RestconfDocumentedException e) {
- return RestconfFuture.failed(e);
+ } catch (ServerException e) {
+ return RestconfFuture.failed(e.toLegacy());
}
return stratAndTail.strategy().dataGET(request, stratAndTail.tail());
}
final StrategyAndTail strategyAndTail;
try {
strategyAndTail = localStrategy().resolveStrategy(identifier);
- } catch (RestconfDocumentedException e) {
- return RestconfFuture.failed(e);
+ } catch (ServerException e) {
+ return RestconfFuture.failed(e.toLegacy());
}
return strategyAndTail.strategy().dataPATCH(strategyAndTail.tail(), body);
}
final StrategyAndTail strategyAndTail;
try {
strategyAndTail = localStrategy().resolveStrategy(identifier);
- } catch (RestconfDocumentedException e) {
- return RestconfFuture.failed(e);
+ } catch (ServerException e) {
+ return RestconfFuture.failed(e.toLegacy());
}
return strategyAndTail.strategy().dataPATCH(strategyAndTail.tail(), body);
}
final StrategyAndTail strategyAndTail;
try {
strategyAndTail = localStrategy().resolveStrategy(identifier);
- } catch (RestconfDocumentedException e) {
- return RestconfFuture.failed(e);
+ } catch (ServerException e) {
+ return RestconfFuture.failed(e.toLegacy());
}
return strategyAndTail.strategy().dataPOST(request, strategyAndTail.tail(), body);
}
final StrategyAndTail strategyAndTail;
try {
strategyAndTail = localStrategy().resolveStrategy(identifier);
- } catch (RestconfDocumentedException e) {
- return RestconfFuture.failed(e);
+ } catch (ServerException e) {
+ return RestconfFuture.failed(e.toLegacy());
}
return strategyAndTail.strategy().dataPUT(request, strategyAndTail.tail(), body);
}
final StrategyAndTail stratAndTail;
try {
stratAndTail = localStrategy().resolveStrategy(mountPath);
- } catch (RestconfDocumentedException e) {
- return RestconfFuture.failed(e);
+ } catch (ServerException e) {
+ return RestconfFuture.failed(e.toLegacy());
}
// FIXME: require remnant to be empty
return modulesGET(stratAndTail.strategy(), fileName, revision, representation);
final StrategyAndTail strategyAndTail;
try {
strategyAndTail = localStrategy().resolveStrategy(operation);
- } catch (RestconfDocumentedException e) {
- return RestconfFuture.failed(e);
+ } catch (ServerException e) {
+ return RestconfFuture.failed(e.toLegacy());
}
final var strategy = strategyAndTail.strategy();
final StrategyAndTail strategyAndTail;
try {
strategyAndTail = localStrategy().resolveStrategy(apiPath);
- } catch (RestconfDocumentedException e) {
- return RestconfFuture.failed(e);
+ } catch (ServerException e) {
+ return RestconfFuture.failed(e.toLegacy());
}
final var strategy = strategyAndTail.strategy();
return strategy.operationsPOST(request, restconfURI, strategyAndTail.tail(), body);
import org.opendaylight.restconf.api.ApiPath;
import org.opendaylight.restconf.api.ApiPath.ListInstance;
import org.opendaylight.restconf.api.ApiPath.Step;
-import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
import org.opendaylight.restconf.nb.rfc8040.Insert.PointNormalizer;
import org.opendaylight.restconf.server.api.DatabindAware;
import org.opendaylight.restconf.server.api.DatabindContext;
import org.opendaylight.restconf.server.api.DatabindPath.Data;
import org.opendaylight.restconf.server.api.DatabindPath.InstanceReference;
import org.opendaylight.restconf.server.api.DatabindPath.Rpc;
+import org.opendaylight.restconf.server.api.ServerException;
import org.opendaylight.yangtools.yang.common.ErrorTag;
import org.opendaylight.yangtools.yang.common.ErrorType;
import org.opendaylight.yangtools.yang.common.QName;
return databind;
}
- public @NonNull DatabindPath normalizePath(final ApiPath apiPath) {
+ public @NonNull DatabindPath normalizePath(final ApiPath apiPath) throws ServerException {
final var it = apiPath.steps().iterator();
if (!it.hasNext()) {
return new Data(databind);
final var firstStep = it.next();
final var firstModule = firstStep.module();
if (firstModule == null) {
- throw new RestconfDocumentedException(
- "First member must use namespace-qualified form, '" + firstStep.identifier() + "' does not",
- ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE);
+ throw new ServerException(ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE,
+ "First member must use namespace-qualified form, '%s' does not", firstStep.identifier());
}
var namespace = resolveNamespace(firstModule);
// We have found an RPC match,
if (it.hasNext()) {
- throw new RestconfDocumentedException("First step in the path resolves to RPC '" + qname + "' and "
- + "therefore it must be the only step present", ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE);
+ throw new ServerException(ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE,
+ "First step in the path resolves to RPC '%s' and therefore it must be the only step present",
+ qname);
}
if (step instanceof ListInstance) {
- throw new RestconfDocumentedException("First step in the path resolves to RPC '" + qname + "' and "
- + "therefore it must not contain key values", ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE);
+ throw new ServerException(ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE,
+ "First step in the path resolves to RPC '%s' and therefore it must not contain key values", qname);
}
final var stack = SchemaInferenceStack.of(modelContext);
@NonNull DatabindPath normalizeSteps(final SchemaInferenceStack stack, final @NonNull DataSchemaContext rootNode,
final @NonNull List<PathArgument> pathPrefix, final @NonNull QNameModule firstNamespace,
- final @NonNull Step firstStep, final Iterator<@NonNull Step> it) {
+ final @NonNull Step firstStep, final Iterator<@NonNull Step> it) throws ServerException {
var parentNode = rootNode;
var namespace = firstNamespace;
var step = firstStep;
final var action = optAction.orElseThrow();
if (it.hasNext()) {
- throw new RestconfDocumentedException("Request path resolves to action '" + qname + "' and "
- + "therefore it must not continue past it", ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE);
+ throw new ServerException(ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE,
+ "Request path resolves to action '%s' and therefore it must not continue past it", qname);
}
if (step instanceof ListInstance) {
- throw new RestconfDocumentedException("Request path resolves to action '" + qname + "' and "
- + "therefore it must not contain key values",
- ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE);
+ throw new ServerException(ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE,
+ "Request path resolves to action '%s' and therefore it must not contain key values", qname);
}
final var stmt = stack.enterSchemaTree(qname);
final var found = parentNode instanceof DataSchemaContext.Composite composite
? composite.enterChild(stack, qname) : null;
if (found == null) {
- throw new RestconfDocumentedException("Schema for '" + qname + "' not found",
- ErrorType.PROTOCOL, ErrorTag.DATA_MISSING);
+ throw new ServerException(ErrorType.PROTOCOL, ErrorTag.DATA_MISSING, "Schema for '%s' not found",
+ qname);
}
// Now add all mixins encountered to the path
pathArg = prepareNodeWithPredicates(stack, qname, listSchema, values);
} else if (schema instanceof LeafListSchemaNode leafListSchema) {
if (values.size() != 1) {
- throw new RestconfDocumentedException("Entry '" + qname + "' requires one value predicate.",
- ErrorType.PROTOCOL, ErrorTag.BAD_ATTRIBUTE);
+ throw new ServerException(ErrorType.PROTOCOL, ErrorTag.BAD_ATTRIBUTE,
+ "Entry '%s' requires one value predicate.", qname);
}
pathArg = new NodeWithValue<>(qname, parserJsonValue(stack, leafListSchema, values.get(0)));
} else {
- throw new RestconfDocumentedException(
- "Entry '" + qname + "' does not take a key or value predicate.",
- ErrorType.PROTOCOL, ErrorTag.MISSING_ATTRIBUTE);
+ throw new ServerException(ErrorType.PROTOCOL, ErrorTag.MISSING_ATTRIBUTE,
+ "Entry '%s' does not take a key or value predicate.", qname);
}
} else {
if (childNode.dataSchemaNode() instanceof ListSchemaNode list && !list.getKeyDefinition().isEmpty()) {
- throw new RestconfDocumentedException(
- "Entry '" + qname + "' requires key or value predicate to be present.",
- ErrorType.PROTOCOL, ErrorTag.MISSING_ATTRIBUTE);
+ throw new ServerException(ErrorType.PROTOCOL, ErrorTag.MISSING_ATTRIBUTE,
+ "Entry '%s' requires key or value predicate to be present.", qname);
}
pathArg = childNode.getPathStep();
}
}
}
- public @NonNull Data normalizeDataPath(final ApiPath apiPath) {
+ public @NonNull Data normalizeDataPath(final ApiPath apiPath) throws ServerException {
final var path = normalizePath(apiPath);
if (path instanceof Data dataPath) {
return dataPath;
}
- throw new RestconfDocumentedException("Point '" + apiPath + "' resolves to non-data " + path,
- ErrorType.PROTOCOL, ErrorTag.DATA_MISSING);
+ throw new ServerException(ErrorType.PROTOCOL, ErrorTag.DATA_MISSING, "Point '%s' resolves to non-data %s",
+ apiPath, path);
}
@Override
- public PathArgument normalizePoint(final ApiPath value) {
+ public PathArgument normalizePoint(final ApiPath value) throws ServerException {
final var path = normalizePath(value);
if (path instanceof Data dataPath) {
final var lastArg = dataPath.instance().getLastPathArgument();
if (lastArg != null) {
return lastArg;
}
- throw new IllegalArgumentException("Point '" + value + "' resolves to an empty path");
+ throw new ServerException(ErrorType.PROTOCOL, ErrorTag.DATA_MISSING,
+ "Point '%s' resolves to an empty path", value);
}
- throw new IllegalArgumentException("Point '" + value + "' resolves to non-data " + path);
+ throw new ServerException(ErrorType.PROTOCOL, ErrorTag.DATA_MISSING, "Point '%s' resolves to non-data %s",
+ value, path);
}
- public @NonNull Rpc normalizeRpcPath(final ApiPath apiPath) {
+ public @NonNull Rpc normalizeRpcPath(final ApiPath apiPath) throws ServerException {
final var steps = apiPath.steps();
return switch (steps.size()) {
- case 0 -> throw new RestconfDocumentedException("RPC name must be present", ErrorType.PROTOCOL,
- ErrorTag.DATA_MISSING);
+ case 0 -> throw new ServerException(ErrorType.PROTOCOL, ErrorTag.DATA_MISSING, "RPC name must be present");
case 1 -> normalizeRpcPath(steps.get(0));
- default -> throw new RestconfDocumentedException(apiPath + " does not refer to an RPC", ErrorType.PROTOCOL,
- ErrorTag.DATA_MISSING);
+ default -> throw new ServerException(ErrorType.PROTOCOL, ErrorTag.DATA_MISSING,
+ "%s does not refer to an RPC", apiPath);
};
}
- public @NonNull Rpc normalizeRpcPath(final ApiPath.Step step) {
+ public @NonNull Rpc normalizeRpcPath(final ApiPath.Step step) throws ServerException {
final var firstModule = step.module();
if (firstModule == null) {
- throw new RestconfDocumentedException(
- "First member must use namespace-qualified form, '" + step.identifier() + "' does not",
- ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE);
+ throw new ServerException(ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE,
+ "First member must use namespace-qualified form, '%s' does not", step.identifier());
}
final var namespace = resolveNamespace(firstModule);
try {
stmt = stack.enterSchemaTree(qname);
} catch (IllegalArgumentException e) {
- throw new RestconfDocumentedException(qname + " does not refer to an RPC", ErrorType.PROTOCOL,
- ErrorTag.DATA_MISSING, e);
+ throw new ServerException(ErrorType.PROTOCOL, ErrorTag.DATA_MISSING, qname + " does not refer to an RPC",
+ e);
}
if (stmt instanceof RpcEffectiveStatement rpc) {
return new Rpc(databind, stack.toInference(), rpc);
}
- throw new RestconfDocumentedException(qname + " does not refer to an RPC", ErrorType.PROTOCOL,
- ErrorTag.DATA_MISSING);
+ throw new ServerException(ErrorType.PROTOCOL, ErrorTag.DATA_MISSING, "%s does not refer to an RPC", qname);
}
- public @NonNull InstanceReference normalizeDataOrActionPath(final ApiPath apiPath) {
+ public @NonNull InstanceReference normalizeDataOrActionPath(final ApiPath apiPath) throws ServerException {
// FIXME: optimize this
final var path = normalizePath(apiPath);
if (path instanceof Data dataPath) {
if (path instanceof Action actionPath) {
return actionPath;
}
- throw new RestconfDocumentedException("Unexpected path " + path, ErrorType.PROTOCOL, ErrorTag.DATA_MISSING);
+ throw new ServerException(ErrorType.PROTOCOL, ErrorTag.DATA_MISSING, "Unexpected path %s", path);
}
private NodeIdentifierWithPredicates prepareNodeWithPredicates(final SchemaInferenceStack stack, final QName qname,
- final @NonNull ListSchemaNode schema, final List<@NonNull String> keyValues) {
+ final @NonNull ListSchemaNode schema, final List<@NonNull String> keyValues) throws ServerException {
final var keyDef = schema.getKeyDefinition();
final var keySize = keyDef.size();
final var varSize = keyValues.size();
if (keySize != varSize) {
- throw new RestconfDocumentedException(
- "Schema for " + qname + " requires " + keySize + " key values, " + varSize + " supplied",
- ErrorType.PROTOCOL, keySize > varSize ? ErrorTag.MISSING_ATTRIBUTE : ErrorTag.UNKNOWN_ATTRIBUTE);
+ throw new ServerException(ErrorType.PROTOCOL,
+ keySize > varSize ? ErrorTag.MISSING_ATTRIBUTE : ErrorTag.UNKNOWN_ATTRIBUTE,
+ "Schema for %s requires %s key values, %s supplied", qname, keySize, varSize);
}
final var values = ImmutableMap.<QName, Object>builderWithExpectedSize(keySize);
}
private Object prepareValueByType(final SchemaInferenceStack stack, final DataSchemaNode schemaNode,
- final @NonNull String value) {
+ final @NonNull String value) throws ServerException {
if (schemaNode instanceof TypedDataSchemaNode typedSchema) {
return parserJsonValue(stack, typedSchema, value);
}
}
private Object parserJsonValue(final SchemaInferenceStack stack, final TypedDataSchemaNode schemaNode,
- final String value) {
+ final String value) throws ServerException {
// As per https://www.rfc-editor.org/rfc/rfc8040#page-29:
// The syntax for
// "api-identifier" and "key-value" MUST conform to the JSON identifier
try {
return databind.jsonCodecs().codecFor(schemaNode, stack).parseValue(value);
} catch (IllegalArgumentException e) {
- throw new RestconfDocumentedException("Invalid value '" + value + "' for " + schemaNode.getQName(),
- ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE, e);
+ throw new ServerException(ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE,
+ "Invalid value '" + value + "' for " + schemaNode.getQName(), e);
}
}
- private @NonNull QNameModule resolveNamespace(final String moduleName) {
+ private @NonNull QNameModule resolveNamespace(final String moduleName) throws ServerException {
final var it = databind.modelContext().findModuleStatements(moduleName).iterator();
if (it.hasNext()) {
return it.next().localQNameModule();
}
- throw new RestconfDocumentedException("Failed to lookup for module with name '" + moduleName + "'.",
- ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT);
+ throw new ServerException(ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT,
+ "Failed to lookup for module with name '%s'.", moduleName);
}
}
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.opendaylight.restconf.api.ApiPath;
-import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
import org.opendaylight.restconf.server.api.DatabindPath.Data;
import org.opendaylight.restconf.server.api.PatchBody.ResourceContext;
+import org.opendaylight.restconf.server.api.ServerException;
import org.opendaylight.yangtools.yang.common.ErrorTag;
import org.opendaylight.yangtools.yang.common.ErrorType;
}
@Override
- protected ResourceContext resolveRelative(final ApiPath apiPath) {
+ protected ResourceContext resolveRelative(final ApiPath apiPath) throws ServerException {
// If subResource is empty just return this resource
if (apiPath.isEmpty()) {
return this;
if (resolved instanceof Data dataPath) {
return new DefaultResourceContext(dataPath);
}
- throw new RestconfDocumentedException("Sub-resource '" + apiPath + "' resolves to non-data " + resolved,
- ErrorType.PROTOCOL, ErrorTag.DATA_MISSING);
+ throw new ServerException(ErrorType.PROTOCOL, ErrorTag.DATA_MISSING,
+ "Sub-resource '%s' resolves to non-data %s", apiPath, resolved);
}
}
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.opendaylight.restconf.api.ApiPath;
import org.opendaylight.restconf.api.FormattableBody;
-import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
import org.opendaylight.restconf.common.errors.RestconfFuture;
import org.opendaylight.restconf.server.api.DatabindPath.Rpc;
+import org.opendaylight.restconf.server.api.ServerException;
import org.opendaylight.restconf.server.api.ServerRequest;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.QNameModule;
final Rpc path;
try {
path = pathNormalizer.normalizeRpcPath(apiPath);
- } catch (RestconfDocumentedException e) {
- return RestconfFuture.failed(e);
+ } catch (ServerException e) {
+ return RestconfFuture.failed(e.toLegacy());
}
return RestconfFuture.of(new OneOperation(path.inference().modelContext(), path.rpc().argument()));
}
import org.opendaylight.restconf.common.patch.PatchContext;
import org.opendaylight.restconf.nb.rfc8040.AbstractInstanceIdentifierTest;
import org.opendaylight.restconf.nb.rfc8040.rests.transactions.MdsalRestconfStrategy;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy.StrategyAndPath;
import org.opendaylight.restconf.server.api.PatchBody;
+import org.opendaylight.restconf.server.api.ServerException;
import org.opendaylight.restconf.server.spi.DefaultResourceContext;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
final var strategy = new MdsalRestconfStrategy(IID_DATABIND, dataBroker, ImmutableMap.of(), null, null, null,
mountPointService);
- final var stratAndPath = strategy.resolveStrategyPath(apiPath);
+ final StrategyAndPath stratAndPath;
+ try {
+ stratAndPath = strategy.resolveStrategyPath(apiPath);
+ } catch (ServerException e) {
+ throw new AssertionError(e);
+ }
try (var body = bodyConstructor.apply(stringInputStream(patchBody))) {
return body.toPatchContext(new DefaultResourceContext(stratAndPath.path()));
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
import org.opendaylight.restconf.common.errors.RestconfError;
import org.opendaylight.restconf.nb.rfc8040.rests.transactions.MdsalRestconfStrategy;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy.StrategyAndPath;
import org.opendaylight.restconf.server.api.DatabindContext;
import org.opendaylight.restconf.server.api.ResourceBody;
+import org.opendaylight.restconf.server.api.ServerException;
import org.opendaylight.yangtools.yang.common.ErrorTag;
import org.opendaylight.yangtools.yang.common.ErrorType;
import org.opendaylight.yangtools.yang.common.QName;
final var strategy = new MdsalRestconfStrategy(DATABIND, dataBroker, ImmutableMap.of(), null, null, null,
mountPointService);
- final var stratAndPath = strategy.resolveStrategyPath(apiPath);
+ final StrategyAndPath stratAndPath;
+ try {
+ stratAndPath = strategy.resolveStrategyPath(apiPath);
+ } catch (ServerException e) {
+ throw new AssertionError(e);
+ }
try (var body = bodyConstructor.apply(stringInputStream(patchBody))) {
return body.toNormalizedNode(stratAndPath.path());
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNotSame;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.opendaylight.restconf.api.ErrorMessage;
import org.opendaylight.restconf.api.query.ContentParam;
import org.opendaylight.restconf.api.query.WithDefaultsParam;
-import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy.StrategyAndTail;
import org.opendaylight.restconf.server.api.DatabindContext;
import org.opendaylight.restconf.server.api.PatchStatusContext;
import org.opendaylight.restconf.server.api.PatchStatusEntity;
+import org.opendaylight.restconf.server.api.ServerException;
import org.opendaylight.yangtools.yang.common.ErrorTag;
import org.opendaylight.yangtools.yang.common.ErrorType;
import org.opendaylight.yangtools.yang.common.QName;
}
@Test
- public void testGetRestconfStrategyLocal() {
+ public void testGetRestconfStrategyLocal() throws Exception {
final var strategy = jukeboxStrategy();
assertEquals(new StrategyAndTail(strategy, ApiPath.empty()), strategy.resolveStrategy(ApiPath.empty()));
}
final var strategy = jukeboxStrategy();
final var mountPath = ApiPath.parse("yang-ext:mount");
- final var ex = assertThrows(RestconfDocumentedException.class, () -> strategy.resolveStrategy(mountPath));
- final var errors = ex.getErrors();
- assertEquals(1, errors.size());
- final var error = errors.get(0);
- assertEquals(ErrorType.APPLICATION, error.getErrorType());
- assertEquals(ErrorTag.OPERATION_FAILED, error.getErrorTag());
- assertEquals("Could not find a supported access interface in mount point", error.getErrorMessage());
- assertEquals(JUKEBOX_IID, error.getErrorPath());
+ final var error = assertThrows(ServerException.class, () -> strategy.resolveStrategy(mountPath)).error();
+ assertEquals(ErrorType.APPLICATION, error.type());
+ assertEquals(ErrorTag.OPERATION_FAILED, error.tag());
+ assertEquals(new ErrorMessage("Could not find a supported access interface in mount point"), error.message());
+ final var path = error.path();
+ assertNotNull(path);
+ assertEquals(JUKEBOX_IID, path.path());
}
}
import static org.junit.jupiter.api.Assertions.assertNull;
import org.junit.jupiter.api.Test;
+import org.opendaylight.restconf.api.ErrorMessage;
import org.opendaylight.yangtools.yang.common.ErrorTag;
import org.opendaylight.yangtools.yang.common.ErrorType;
final var ex = new ServerException("some message", cause);
assertEquals("some message", ex.getMessage());
assertSame(cause, ex.getCause());
- assertEquals(new ServerError(ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, "some message"), ex.error());
+ assertEquals(
+ new ServerError(ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, new ErrorMessage("some message"), null,
+ null, new ServerErrorInfo("cause message")),
+ ex.error());
}
@Test
final var ex = new ServerException("some message", cause);
assertEquals("some message", ex.getMessage());
assertSame(cause, ex.getCause());
- assertEquals(new ServerError(ErrorType.APPLICATION, ErrorTag.INVALID_VALUE, "some message"), ex.error());
+ assertEquals(new ServerError(ErrorType.APPLICATION, ErrorTag.INVALID_VALUE, new ErrorMessage("some message"),
+ null, null, new ServerErrorInfo("cause message")), ex.error());
}
@Test
final var ex = new ServerException("some message", cause);
assertEquals("some message", ex.getMessage());
assertSame(cause, ex.getCause());
- assertEquals(new ServerError(ErrorType.APPLICATION, ErrorTag.OPERATION_NOT_SUPPORTED, "some message"),
+ assertEquals(
+ new ServerError(ErrorType.APPLICATION, ErrorTag.OPERATION_NOT_SUPPORTED, new ErrorMessage("some message"),
+ null, null, new ServerErrorInfo("cause message")),
ex.error());
}
import org.opendaylight.restconf.common.errors.RestconfError;
import org.opendaylight.restconf.server.api.DatabindContext;
import org.opendaylight.restconf.server.api.DatabindPath.Data;
+import org.opendaylight.restconf.server.api.ServerException;
import org.opendaylight.yangtools.yang.common.ErrorTag;
import org.opendaylight.yangtools.yang.common.ErrorType;
import org.opendaylight.yangtools.yang.common.QName;
}
private static YangInstanceIdentifier assertNormalized(final String str) {
- return assertInstanceOf(Data.class, NORMALIZER.normalizePath(newApiPath(str))).instance();
+ try {
+ return assertInstanceOf(Data.class, NORMALIZER.normalizePath(newApiPath(str))).instance();
+ } catch (ServerException e) {
+ throw new AssertionError(e);
+ }
}
private static RestconfError assertError(final YangInstanceIdentifier path) {
import java.text.ParseException;
import org.junit.jupiter.api.Test;
import org.opendaylight.restconf.api.ApiPath;
-import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
-import org.opendaylight.restconf.common.errors.RestconfError;
+import org.opendaylight.restconf.api.ErrorMessage;
import org.opendaylight.restconf.server.api.DatabindContext;
import org.opendaylight.restconf.server.api.DatabindPath.Action;
import org.opendaylight.restconf.server.api.DatabindPath.Data;
+import org.opendaylight.restconf.server.api.ServerError;
+import org.opendaylight.restconf.server.api.ServerErrorInfo;
+import org.opendaylight.restconf.server.api.ServerException;
import org.opendaylight.yangtools.yang.common.ErrorTag;
import org.opendaylight.yangtools.yang.common.ErrorType;
import org.opendaylight.yangtools.yang.common.QName;
@Test
void prepareQnameNotExistingPrefixNegativeTest() {
final var error = assertErrorPath("not-existing:contA");
- assertEquals("Failed to lookup for module with name 'not-existing'.", error.getErrorMessage());
- assertEquals(ErrorType.PROTOCOL, error.getErrorType());
- assertEquals(ErrorTag.UNKNOWN_ELEMENT, error.getErrorTag());
+ assertEquals(new ErrorMessage("Failed to lookup for module with name 'not-existing'."), error.message());
+ assertEquals(ErrorType.PROTOCOL, error.type());
+ assertEquals(ErrorTag.UNKNOWN_ELEMENT, error.tag());
}
/**
@Test
public void prepareQnameNotValidContainerNameNegativeTest() {
final var error = assertErrorPath("deserializer-test:contA/leafB");
- assertEquals("Schema for '(deserializer:test?revision=2016-06-06)leafB' not found", error.getErrorMessage());
- assertEquals(ErrorType.PROTOCOL, error.getErrorType());
- assertEquals(ErrorTag.DATA_MISSING, error.getErrorTag());
+ assertEquals(new ErrorMessage("Schema for '(deserializer:test?revision=2016-06-06)leafB' not found"),
+ error.message());
+ assertEquals(ErrorType.PROTOCOL, error.type());
+ assertEquals(ErrorTag.DATA_MISSING, error.tag());
}
/**
@Test
void prepareQnameNotValidListNameNegativeTest() {
final var error = assertErrorPath("deserializer-test:list-no-key/disabled=false");
- assertEquals("Schema for '(deserializer:test?revision=2016-06-06)disabled' not found", error.getErrorMessage());
- assertEquals(ErrorType.PROTOCOL, error.getErrorType());
- assertEquals(ErrorTag.DATA_MISSING, error.getErrorTag());
+ assertEquals(new ErrorMessage("Schema for '(deserializer:test?revision=2016-06-06)disabled' not found"),
+ error.message());
+ assertEquals(ErrorType.PROTOCOL, error.type());
+ assertEquals(ErrorTag.DATA_MISSING, error.tag());
}
/**
@Test
void prepareIdentifierNotKeyedEntryNegativeTest() {
final var error = assertErrorPath("deserializer-test:list-one-key");
- assertEquals("""
+ assertEquals(new ErrorMessage("""
Entry '(deserializer:test?revision=2016-06-06)list-one-key' requires key or value predicate to be \
- present.""", error.getErrorMessage());
- assertEquals(ErrorType.PROTOCOL, error.getErrorType());
- assertEquals(ErrorTag.MISSING_ATTRIBUTE, error.getErrorTag());
+ present."""), error.message());
+ assertEquals(ErrorType.PROTOCOL, error.type());
+ assertEquals(ErrorTag.MISSING_ATTRIBUTE, error.tag());
}
/**
@Test
void deserializeKeysEndsWithCommaTooManyNegativeTest() {
final var error = assertErrorPath("deserializer-test:list-multiple-keys=value,100,false,");
- assertEquals("""
- Schema for (deserializer:test?revision=2016-06-06)list-multiple-keys requires 3 key values, 4 supplied""",
- error.getErrorMessage());
- assertEquals(ErrorType.PROTOCOL, error.getErrorType());
- assertEquals(ErrorTag.UNKNOWN_ATTRIBUTE, error.getErrorTag());
+ assertEquals(new ErrorMessage("""
+ Schema for (deserializer:test?revision=2016-06-06)list-multiple-keys requires 3 key values, 4 supplied"""),
+ error.message());
+ assertEquals(ErrorType.PROTOCOL, error.type());
+ assertEquals(ErrorTag.UNKNOWN_ATTRIBUTE, error.tag());
}
/**
@Test
void deserializeKeysEndsWithCommaIllegalNegativeTest() {
final var error = assertErrorPath("deserializer-test:list-multiple-keys=value,100,");
- assertEquals("Invalid value '' for (deserializer:test?revision=2016-06-06)enabled", error.getErrorMessage());
- assertEquals(ErrorType.PROTOCOL, error.getErrorType());
- assertEquals(ErrorTag.INVALID_VALUE, error.getErrorTag());
- assertEquals("Invalid value '' for boolean type. Allowed values are 'true' and 'false'", error.getErrorInfo());
+ assertEquals(new ErrorMessage("Invalid value '' for (deserializer:test?revision=2016-06-06)enabled"),
+ error.message());
+ assertEquals(ErrorType.PROTOCOL, error.type());
+ assertEquals(ErrorTag.INVALID_VALUE, error.tag());
+ assertEquals(new ServerErrorInfo("Invalid value '' for boolean type. Allowed values are 'true' and 'false'"),
+ error.info());
}
/**
@Test
void notAllListKeysEncodedNegativeTest() {
final var error = assertErrorPath("deserializer-test:list-multiple-keys=%3Afoo/string-value");
- assertEquals("""
- Schema for (deserializer:test?revision=2016-06-06)list-multiple-keys requires 3 key values, 1 supplied""",
- error.getErrorMessage());
- assertEquals(ErrorType.PROTOCOL, error.getErrorType());
- assertEquals(ErrorTag.MISSING_ATTRIBUTE, error.getErrorTag());
+ assertEquals(new ErrorMessage("""
+ Schema for (deserializer:test?revision=2016-06-06)list-multiple-keys requires 3 key values, 1 supplied"""),
+ error.message());
+ assertEquals(ErrorType.PROTOCOL, error.type());
+ assertEquals(ErrorTag.MISSING_ATTRIBUTE, error.tag());
}
/**
@Test
void leafListMissingKeyNegativeTest() {
final var error = assertErrorPath("deserializer-test:leaf-list-0=");
- assertEquals("Invalid value '' for (deserializer:test?revision=2016-06-06)leaf-list-0",
- error.getErrorMessage());
- assertEquals(ErrorType.PROTOCOL, error.getErrorType());
- assertEquals(ErrorTag.INVALID_VALUE, error.getErrorTag());
+ assertEquals(new ErrorMessage("Invalid value '' for (deserializer:test?revision=2016-06-06)leaf-list-0"),
+ error.message());
+ assertEquals(ErrorType.PROTOCOL, error.type());
+ assertEquals(ErrorTag.INVALID_VALUE, error.tag());
}
/**
"deserializer-test-included:refs/list-with-identityref=deserializer-test:derived-identity/foo");
}
- private static RestconfError assertErrorPath(final String path) {
+ private static ServerError assertErrorPath(final String path) {
final var apiPath = assertApiPath(path);
- final var ex = assertThrows(RestconfDocumentedException.class, () -> NORMALIZER.normalizePath(apiPath));
- final var errors = ex.getErrors();
- assertEquals(1, errors.size());
- return errors.get(0);
+ return assertThrows(ServerException.class, () -> NORMALIZER.normalizePath(apiPath)).error();
}
private static Action assertNormalizedAction(final String path) {
- return assertInstanceOf(Action.class, NORMALIZER.normalizePath(assertApiPath(path)));
+ try {
+ return assertInstanceOf(Action.class, NORMALIZER.normalizePath(assertApiPath(path)));
+ } catch (ServerException e) {
+ throw new AssertionError(e);
+ }
}
private static YangInstanceIdentifier assertNormalizedPath(final String path) {
- return assertInstanceOf(Data.class, NORMALIZER.normalizePath(assertApiPath(path))).instance();
+ try {
+ return assertInstanceOf(Data.class, NORMALIZER.normalizePath(assertApiPath(path))).instance();
+ } catch (ServerException e) {
+ throw new AssertionError(e);
+ }
}
private static ApiPath assertApiPath(final String path) {
import java.text.ParseException;
import org.junit.jupiter.api.Test;
import org.opendaylight.restconf.api.ApiPath;
-import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
-import org.opendaylight.restconf.common.errors.RestconfError;
+import org.opendaylight.restconf.api.ErrorMessage;
import org.opendaylight.restconf.server.api.DatabindContext;
+import org.opendaylight.restconf.server.api.ServerError;
+import org.opendaylight.restconf.server.api.ServerErrorInfo;
+import org.opendaylight.restconf.server.api.ServerException;
import org.opendaylight.yangtools.yang.common.ErrorTag;
import org.opendaylight.yangtools.yang.common.ErrorType;
import org.opendaylight.yangtools.yang.common.QName;
@Test
void noslashInstanceIdentifierKey() {
final var error = assertRestconfError("nc1265:bar=nc1265:baz=123");
- assertEquals(ErrorType.PROTOCOL, error.getErrorType());
- assertEquals(ErrorTag.INVALID_VALUE, error.getErrorTag());
- assertEquals("Invalid value 'nc1265:baz=123' for (nc1265)key", error.getErrorMessage());
- assertEquals("""
+ assertEquals(ErrorType.PROTOCOL, error.type());
+ assertEquals(ErrorTag.INVALID_VALUE, error.tag());
+ assertEquals(new ErrorMessage("Invalid value 'nc1265:baz=123' for (nc1265)key"), error.message());
+ assertEquals(new ServerErrorInfo("""
Could not parse Instance Identifier 'nc1265:baz=123'. Offset: 0 : Reason: Identifier must start with '/'.\
- """, error.getErrorInfo());
+ """), error.info());
}
@Test
void malformedInstanceIdentifierKey() {
final var error = assertRestconfError("nc1265:bar=%2Fnc1265:baz[key='abc']");
- assertEquals(ErrorType.PROTOCOL, error.getErrorType());
- assertEquals(ErrorTag.INVALID_VALUE, error.getErrorTag());
- assertEquals("Invalid value '/nc1265:baz[key='abc']' for (nc1265)key", error.getErrorMessage());
- assertEquals("""
+ assertEquals(ErrorType.PROTOCOL, error.type());
+ assertEquals(ErrorTag.INVALID_VALUE, error.tag());
+ assertEquals(new ErrorMessage("Invalid value '/nc1265:baz[key='abc']' for (nc1265)key"), error.message());
+ assertEquals(new ServerErrorInfo("""
Incorrect lexical representation of integer value: abc.
An integer value can be defined as:
- a decimal number,
- a hexadecimal number (prefix 0x),%n - an octal number (prefix 0).
- Signed values are allowed. Spaces between digits are NOT allowed.""", error.getErrorInfo());
+ Signed values are allowed. Spaces between digits are NOT allowed."""), error.info());
}
private static void assertNormalized(final YangInstanceIdentifier expected, final String apiPath) {
- assertEquals(expected, NORMALIZER.normalizeDataPath(assertApiPath(apiPath)).instance());
+ try {
+ assertEquals(expected, NORMALIZER.normalizeDataPath(assertApiPath(apiPath)).instance());
+ } catch (ServerException e) {
+ throw new AssertionError(e);
+ }
}
- private static RestconfError assertRestconfError(final String apiPath) {
+ private static ServerError assertRestconfError(final String apiPath) {
final var parsed = assertApiPath(apiPath);
-
- final var ex = assertThrows(RestconfDocumentedException.class, () -> NORMALIZER.normalizeDataPath(parsed));
- final var errors = ex.getErrors();
- assertEquals(1, errors.size());
- return errors.get(0);
+ return assertThrows(ServerException.class, () -> NORMALIZER.normalizeDataPath(parsed)).error();
}
private static ApiPath assertApiPath(final String apiPath) {