diff --git a/integration/base/src/main/java/com/inrupt/client/integration/base/AccessGrantScenarios.java b/integration/base/src/main/java/com/inrupt/client/integration/base/AccessGrantScenarios.java
index 0b7c4b84992..4f580f62da3 100644
--- a/integration/base/src/main/java/com/inrupt/client/integration/base/AccessGrantScenarios.java
+++ b/integration/base/src/main/java/com/inrupt/client/integration/base/AccessGrantScenarios.java
@@ -36,10 +36,7 @@
import com.inrupt.client.auth.Session;
import com.inrupt.client.openid.OpenIdException;
import com.inrupt.client.openid.OpenIdSession;
-import com.inrupt.client.solid.SolidClientException;
-import com.inrupt.client.solid.SolidNonRDFSource;
-import com.inrupt.client.solid.SolidRDFSource;
-import com.inrupt.client.solid.SolidSyncClient;
+import com.inrupt.client.solid.*;
import com.inrupt.client.spi.RDFFactory;
import com.inrupt.client.util.URIBuilder;
import com.inrupt.client.vocabulary.ACL;
@@ -240,7 +237,7 @@ void accessGrantIssuanceLifecycleTest(final Session session) {
//unauthorized request test
final SolidSyncClient client = SolidSyncClient.getClientBuilder().build();
- final SolidClientException err = assertThrows(SolidClientException.class,
+ final var err = assertThrows(UnauthorizedException.class,
() -> client.read(sharedTextFileURI, SolidNonRDFSource.class));
assertEquals(Utils.UNAUTHORIZED, err.getStatusCode());
final Request reqRead =
diff --git a/integration/base/src/main/java/com/inrupt/client/integration/base/AuthenticationScenarios.java b/integration/base/src/main/java/com/inrupt/client/integration/base/AuthenticationScenarios.java
index 96b3d6bf34d..b6c15fc7a66 100644
--- a/integration/base/src/main/java/com/inrupt/client/integration/base/AuthenticationScenarios.java
+++ b/integration/base/src/main/java/com/inrupt/client/integration/base/AuthenticationScenarios.java
@@ -33,6 +33,7 @@
import com.inrupt.client.solid.SolidClientException;
import com.inrupt.client.solid.SolidRDFSource;
import com.inrupt.client.solid.SolidSyncClient;
+import com.inrupt.client.solid.UnauthorizedException;
import com.inrupt.client.util.URIBuilder;
import com.inrupt.client.webid.WebIdProfile;
@@ -190,7 +191,7 @@ void fetchPrivateResourceUnauthenticatedTest(final Session session) {
assertDoesNotThrow(() -> authClient.create(testResource));
final SolidSyncClient client = SolidSyncClient.getClient();
- final SolidClientException err = assertThrows(SolidClientException.class,
+ final var err = assertThrows(UnauthorizedException.class,
() -> client.read(privateResourceURL, SolidRDFSource.class));
assertEquals(Utils.UNAUTHORIZED, err.getStatusCode());
@@ -242,7 +243,7 @@ void fetchPrivateResourceUnauthAuthTest(final Session session) {
assertDoesNotThrow(() -> authClient.create(testResource));
final SolidSyncClient client = SolidSyncClient.getClient();
- final SolidClientException err = assertThrows(SolidClientException.class,
+ final var err = assertThrows(UnauthorizedException.class,
() -> client.read(privateResourceURL, SolidRDFSource.class));
assertEquals(Utils.UNAUTHORIZED, err.getStatusCode());
@@ -278,7 +279,7 @@ void multiSessionTest(final Session session) {
assertDoesNotThrow(() -> authClient2.read(privateResourceURL, SolidRDFSource.class));
final SolidSyncClient client = SolidSyncClient.getClient();
- final SolidClientException err = assertThrows(SolidClientException.class,
+ final var err = assertThrows(UnauthorizedException.class,
() -> client.read(privateResourceURL, SolidRDFSource.class));
assertEquals(Utils.UNAUTHORIZED, err.getStatusCode());
diff --git a/integration/base/src/main/java/com/inrupt/client/integration/base/DomainModulesResource.java b/integration/base/src/main/java/com/inrupt/client/integration/base/DomainModulesResource.java
index 2606409dbf1..fc7854c4ab1 100644
--- a/integration/base/src/main/java/com/inrupt/client/integration/base/DomainModulesResource.java
+++ b/integration/base/src/main/java/com/inrupt/client/integration/base/DomainModulesResource.java
@@ -26,11 +26,7 @@
import com.inrupt.client.Request;
import com.inrupt.client.Response;
import com.inrupt.client.auth.Session;
-import com.inrupt.client.solid.SolidClientException;
-import com.inrupt.client.solid.SolidContainer;
-import com.inrupt.client.solid.SolidRDFSource;
-import com.inrupt.client.solid.SolidResourceHandlers;
-import com.inrupt.client.solid.SolidSyncClient;
+import com.inrupt.client.solid.*;
import com.inrupt.client.spi.RDFFactory;
import com.inrupt.client.util.URIBuilder;
import com.inrupt.client.vocabulary.PIM;
@@ -261,7 +257,7 @@ void findStorageTest() {
}
final var missingWebId = URIBuilder.newBuilder(URI.create(webidUrl)).path(UUID.randomUUID().toString()).build();
- final var err = assertThrows(SolidClientException.class, () -> client.read(missingWebId, WebIdProfile.class));
+ final var err = assertThrows(NotFoundException.class, () -> client.read(missingWebId, WebIdProfile.class));
assertEquals(404, err.getStatusCode());
assertEquals(missingWebId, err.getUri());
}
diff --git a/solid/src/main/java/com/inrupt/client/solid/BadRequestException.java b/solid/src/main/java/com/inrupt/client/solid/BadRequestException.java
new file mode 100644
index 00000000000..4b11347dbb7
--- /dev/null
+++ b/solid/src/main/java/com/inrupt/client/solid/BadRequestException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2023 Inrupt Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
+ * Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+package com.inrupt.client.solid;
+
+import com.inrupt.client.Headers;
+
+import java.net.URI;
+
+/**
+ * A runtime exception that represents an HTTP bad request (400) response.
+ *
+ * @see RFC 9110 (15.5.1.) 400 Bad Request
+ */
+public class BadRequestException extends SolidClientException {
+ private static final long serialVersionUID = -3379457428921025570L;
+
+ public static final int STATUS_CODE = 400;
+
+ /**
+ * Create a BadRequestException exception.
+ *
+ * @param message the message
+ * @param uri the uri
+ * @param headers the response headers
+ * @param body the body
+ */
+ public BadRequestException(
+ final String message,
+ final URI uri,
+ final Headers headers,
+ final String body) {
+ super(message, uri, STATUS_CODE, headers, body);
+ }
+}
diff --git a/solid/src/main/java/com/inrupt/client/solid/ConflictException.java b/solid/src/main/java/com/inrupt/client/solid/ConflictException.java
new file mode 100644
index 00000000000..2cf1b689789
--- /dev/null
+++ b/solid/src/main/java/com/inrupt/client/solid/ConflictException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2023 Inrupt Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
+ * Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+package com.inrupt.client.solid;
+
+import com.inrupt.client.Headers;
+
+import java.net.URI;
+
+/**
+ * A runtime exception that represents an HTTP conflict (409) response..
+ *
+ * @see RFC 9110 (15.5.10.) 409 Conflict
+ */
+public class ConflictException extends SolidClientException {
+ private static final long serialVersionUID = -203198307847520748L;
+
+ public static final int STATUS_CODE = 409;
+
+ /**
+ * Create a ConflictException exception.
+ *
+ * @param message the message
+ * @param uri the uri
+ * @param headers the response headers
+ * @param body the body
+ */
+ public ConflictException(
+ final String message,
+ final URI uri,
+ final Headers headers,
+ final String body) {
+ super(message, uri, STATUS_CODE, headers, body);
+ }
+}
diff --git a/solid/src/main/java/com/inrupt/client/solid/ForbiddenException.java b/solid/src/main/java/com/inrupt/client/solid/ForbiddenException.java
new file mode 100644
index 00000000000..bc3e787c3f6
--- /dev/null
+++ b/solid/src/main/java/com/inrupt/client/solid/ForbiddenException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2023 Inrupt Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
+ * Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+package com.inrupt.client.solid;
+
+import com.inrupt.client.Headers;
+
+import java.net.URI;
+
+/**
+ * A runtime exception that represents an HTTP forbidden (403) response.
+ *
+ * @see RFC 9110 (15.5.4.) 403 Forbidden
+ */
+public class ForbiddenException extends SolidClientException {
+ private static final long serialVersionUID = 3299286274724874244L;
+
+ public static final int STATUS_CODE = 403;
+
+ /**
+ * Create a ForbiddenException exception.
+ *
+ * @param message the message
+ * @param uri the uri
+ * @param headers the response headers
+ * @param body the body
+ */
+ public ForbiddenException(
+ final String message,
+ final URI uri,
+ final Headers headers,
+ final String body) {
+ super(message, uri, STATUS_CODE, headers, body);
+ }
+}
diff --git a/solid/src/main/java/com/inrupt/client/solid/GoneException.java b/solid/src/main/java/com/inrupt/client/solid/GoneException.java
new file mode 100644
index 00000000000..a2a7b75f682
--- /dev/null
+++ b/solid/src/main/java/com/inrupt/client/solid/GoneException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2023 Inrupt Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
+ * Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+package com.inrupt.client.solid;
+
+import com.inrupt.client.Headers;
+
+import java.net.URI;
+
+/**
+ * A runtime exception that represents an HTTP gone (410) response.
+ *
+ * @see RFC 9110 (15.5.11.) 410 Gone
+ */
+public class GoneException extends SolidClientException {
+ private static final long serialVersionUID = -6892345582498100242L;
+
+ public static final int STATUS_CODE = 410;
+
+ /**
+ * Create a GoneException exception.
+ *
+ * @param message the message
+ * @param uri the uri
+ * @param headers the response headers
+ * @param body the body
+ */
+ public GoneException(
+ final String message,
+ final URI uri,
+ final Headers headers,
+ final String body) {
+ super(message, uri, STATUS_CODE, headers, body);
+ }
+}
diff --git a/solid/src/main/java/com/inrupt/client/solid/InternalServerErrorException.java b/solid/src/main/java/com/inrupt/client/solid/InternalServerErrorException.java
new file mode 100644
index 00000000000..55805b0af2a
--- /dev/null
+++ b/solid/src/main/java/com/inrupt/client/solid/InternalServerErrorException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2023 Inrupt Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
+ * Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+package com.inrupt.client.solid;
+
+import com.inrupt.client.Headers;
+
+import java.net.URI;
+
+/**
+ * A runtime exception that represents an HTTP internal server error (500) response.
+ *
+ * @see RFC 9110 (15.6.1.) 500 Internal Server Error
+ */
+public class InternalServerErrorException extends SolidClientException {
+ private static final long serialVersionUID = -6672490715281719330L;
+
+ public static final int STATUS_CODE = 500;
+
+ /**
+ * Create an InternalServerErrorException exception.
+ *
+ * @param message the message
+ * @param uri the uri
+ * @param headers the response headers
+ * @param body the body
+ */
+ public InternalServerErrorException(
+ final String message,
+ final URI uri,
+ final Headers headers,
+ final String body) {
+ super(message, uri, STATUS_CODE, headers, body);
+ }
+}
diff --git a/solid/src/main/java/com/inrupt/client/solid/MethodNotAllowedException.java b/solid/src/main/java/com/inrupt/client/solid/MethodNotAllowedException.java
new file mode 100644
index 00000000000..de8e6d1abd6
--- /dev/null
+++ b/solid/src/main/java/com/inrupt/client/solid/MethodNotAllowedException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2023 Inrupt Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
+ * Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+package com.inrupt.client.solid;
+
+import com.inrupt.client.Headers;
+
+import java.net.URI;
+
+/**
+ * A runtime exception that represents an HTTP method not allowed (405) response.
+ *
+ * @see RFC 9110 (15.5.6.) 405 Method Not Allowed
+ */
+public class MethodNotAllowedException extends SolidClientException {
+ private static final long serialVersionUID = -9125437562813923030L;
+
+ public static final int STATUS_CODE = 405;
+
+ /**
+ * Create a MethodNotAllowedException exception.
+ *
+ * @param message the message
+ * @param uri the uri
+ * @param headers the response headers
+ * @param body the body
+ */
+ public MethodNotAllowedException(
+ final String message,
+ final URI uri,
+ final Headers headers,
+ final String body) {
+ super(message, uri, STATUS_CODE, headers, body);
+ }
+}
diff --git a/solid/src/main/java/com/inrupt/client/solid/NotAcceptableException.java b/solid/src/main/java/com/inrupt/client/solid/NotAcceptableException.java
new file mode 100644
index 00000000000..afba65762fc
--- /dev/null
+++ b/solid/src/main/java/com/inrupt/client/solid/NotAcceptableException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2023 Inrupt Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
+ * Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+package com.inrupt.client.solid;
+
+import com.inrupt.client.Headers;
+
+import java.net.URI;
+
+/**
+ * A runtime exception that represents an HTTP not acceptable (406) response.
+ *
+ * @see RFC 9110 (15.5.7.) 406 Not Acceptable
+ */
+public class NotAcceptableException extends SolidClientException {
+ private static final long serialVersionUID = 6594993822477388733L;
+
+ public static final int STATUS_CODE = 406;
+
+ /**
+ * Create a NotAcceptableException exception.
+ *
+ * @param message the message
+ * @param uri the uri
+ * @param headers the response headers
+ * @param body the body
+ */
+ public NotAcceptableException(
+ final String message,
+ final URI uri,
+ final Headers headers,
+ final String body) {
+ super(message, uri, STATUS_CODE, headers, body);
+ }
+}
diff --git a/solid/src/main/java/com/inrupt/client/solid/NotFoundException.java b/solid/src/main/java/com/inrupt/client/solid/NotFoundException.java
new file mode 100644
index 00000000000..8ad955e226d
--- /dev/null
+++ b/solid/src/main/java/com/inrupt/client/solid/NotFoundException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2023 Inrupt Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
+ * Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+package com.inrupt.client.solid;
+
+import com.inrupt.client.Headers;
+
+import java.net.URI;
+
+/**
+ * A runtime exception that represents an HTTP not found (404) response.
+ *
+ * @see RFC 9110 (15.5.5.) 404 Not Found
+ */
+public class NotFoundException extends SolidClientException {
+ private static final long serialVersionUID = -2256628528500739683L;
+
+ public static final int STATUS_CODE = 404;
+
+ /**
+ * Create a NotFoundException exception.
+ *
+ * @param message the message
+ * @param uri the uri
+ * @param headers the response headers
+ * @param body the body
+ */
+ public NotFoundException(
+ final String message,
+ final URI uri,
+ final Headers headers,
+ final String body) {
+ super(message, uri, STATUS_CODE, headers, body);
+ }
+}
diff --git a/solid/src/main/java/com/inrupt/client/solid/PreconditionFailedException.java b/solid/src/main/java/com/inrupt/client/solid/PreconditionFailedException.java
new file mode 100644
index 00000000000..96650853456
--- /dev/null
+++ b/solid/src/main/java/com/inrupt/client/solid/PreconditionFailedException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2023 Inrupt Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
+ * Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+package com.inrupt.client.solid;
+
+import com.inrupt.client.Headers;
+
+import java.net.URI;
+
+/**
+ * A runtime exception that represents an HTTP precondition failed (412) response.
+ *
+ * @see RFC 9110 (15.5.13.) 412 Precondition Failed
+ */
+public class PreconditionFailedException extends SolidClientException {
+ private static final long serialVersionUID = 4205761003697773528L;
+
+ public static final int STATUS_CODE = 412;
+
+ /**
+ * Create a PreconditionFailedException exception.
+ *
+ * @param message the message
+ * @param uri the uri
+ * @param headers the response headers
+ * @param body the body
+ */
+ public PreconditionFailedException(
+ final String message,
+ final URI uri,
+ final Headers headers,
+ final String body) {
+ super(message, uri, STATUS_CODE, headers, body);
+ }
+}
diff --git a/solid/src/main/java/com/inrupt/client/solid/SolidClient.java b/solid/src/main/java/com/inrupt/client/solid/SolidClient.java
index 97eda0906bf..88ce28493f0 100644
--- a/solid/src/main/java/com/inrupt/client/solid/SolidClient.java
+++ b/solid/src/main/java/com/inrupt/client/solid/SolidClient.java
@@ -133,7 +133,7 @@ public CompletionStage read(final URI identifier, final
return client.send(builder.build(), Response.BodyHandlers.ofByteArray())
.thenApply(response -> {
if (response.statusCode() >= ERROR_STATUS) {
- throw new SolidClientException("Unable to read resource at " + identifier, identifier,
+ throw SolidClientException.handle("Unable to read resource at " + identifier, identifier,
response.statusCode(), response.headers(), new String(response.body()));
} else {
final String contentType = response.headers().firstValue(CONTENT_TYPE)
@@ -285,7 +285,7 @@ public CompletionStage delete(final T resource, final
if (isSuccess(res.statusCode())) {
return null;
} else {
- throw new SolidClientException("Unable to delete resource", resource.getIdentifier(),
+ throw SolidClientException.handle("Unable to delete resource", resource.getIdentifier(),
res.statusCode(), res.headers(), new String(res.body(), UTF_8));
}
});
@@ -369,7 +369,7 @@ Function, CompletionStage> handleRespon
final Headers headers, final String message) {
return res -> {
if (!isSuccess(res.statusCode())) {
- throw new SolidClientException(message, resource.getIdentifier(),
+ throw SolidClientException.handle(message, resource.getIdentifier(),
res.statusCode(), res.headers(), new String(res.body(), UTF_8));
}
diff --git a/solid/src/main/java/com/inrupt/client/solid/SolidClientException.java b/solid/src/main/java/com/inrupt/client/solid/SolidClientException.java
index 31e91925e29..a3887e6759e 100644
--- a/solid/src/main/java/com/inrupt/client/solid/SolidClientException.java
+++ b/solid/src/main/java/com/inrupt/client/solid/SolidClientException.java
@@ -90,5 +90,41 @@ public Headers getHeaders() {
public String getBody() {
return body;
}
+
+ public static SolidClientException handle(
+ final String message,
+ final URI uri,
+ final int statusCode,
+ final Headers headers,
+ final String body) {
+ switch (statusCode) {
+ case BadRequestException.STATUS_CODE:
+ return new BadRequestException(message, uri, headers, body);
+ case UnauthorizedException.STATUS_CODE:
+ return new UnauthorizedException(message, uri, headers, body);
+ case ForbiddenException.STATUS_CODE:
+ return new ForbiddenException(message, uri, headers, body);
+ case NotFoundException.STATUS_CODE:
+ return new NotFoundException(message, uri, headers, body);
+ case MethodNotAllowedException.STATUS_CODE:
+ return new MethodNotAllowedException(message, uri, headers, body);
+ case NotAcceptableException.STATUS_CODE:
+ return new NotAcceptableException(message, uri, headers, body);
+ case ConflictException.STATUS_CODE:
+ return new ConflictException(message, uri, headers, body);
+ case GoneException.STATUS_CODE:
+ return new GoneException(message, uri, headers, body);
+ case PreconditionFailedException.STATUS_CODE:
+ return new PreconditionFailedException(message, uri, headers, body);
+ case UnsupportedMediaTypeException.STATUS_CODE:
+ return new UnsupportedMediaTypeException(message, uri, headers, body);
+ case TooManyRequestsException.STATUS_CODE:
+ return new TooManyRequestsException(message, uri, headers, body);
+ case InternalServerErrorException.STATUS_CODE:
+ return new InternalServerErrorException(message, uri, headers, body);
+ default:
+ return new SolidClientException(message, uri, statusCode, headers, body);
+ }
+ }
}
diff --git a/solid/src/main/java/com/inrupt/client/solid/TooManyRequestsException.java b/solid/src/main/java/com/inrupt/client/solid/TooManyRequestsException.java
new file mode 100644
index 00000000000..de1e5c07215
--- /dev/null
+++ b/solid/src/main/java/com/inrupt/client/solid/TooManyRequestsException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2023 Inrupt Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
+ * Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+package com.inrupt.client.solid;
+
+import com.inrupt.client.Headers;
+
+import java.net.URI;
+
+/**
+ * A runtime exception that represents an HTTP too many requests (429) response.
+ *
+ * @see RFC 6585 (4.) 429 Too Many Requests
+ */
+public class TooManyRequestsException extends SolidClientException {
+ private static final long serialVersionUID = -1798491190232642824L;
+
+ public static final int STATUS_CODE = 429;
+
+ /**
+ * Create a TooManyRequestsException exception.
+ *
+ * @param message the message
+ * @param uri the uri
+ * @param headers the response headers
+ * @param body the body
+ */
+ public TooManyRequestsException(
+ final String message,
+ final URI uri,
+ final Headers headers,
+ final String body) {
+ super(message, uri, STATUS_CODE, headers, body);
+ }
+}
diff --git a/solid/src/main/java/com/inrupt/client/solid/UnauthorizedException.java b/solid/src/main/java/com/inrupt/client/solid/UnauthorizedException.java
new file mode 100644
index 00000000000..338df0f0386
--- /dev/null
+++ b/solid/src/main/java/com/inrupt/client/solid/UnauthorizedException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2023 Inrupt Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
+ * Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+package com.inrupt.client.solid;
+
+import com.inrupt.client.Headers;
+
+import java.net.URI;
+
+/**
+ * A runtime exception that represents an HTTP unauthorized (401) response.
+ *
+ * @see RFC 9110 (15.5.2.) 401 Unauthorized
+ */
+public class UnauthorizedException extends SolidClientException {
+ private static final long serialVersionUID = -3219668517323678497L;
+
+ public static final int STATUS_CODE = 401;
+
+ /**
+ * Create an UnauthorizedException exception.
+ *
+ * @param message the message
+ * @param uri the uri
+ * @param headers the response headers
+ * @param body the body
+ */
+ public UnauthorizedException(
+ final String message,
+ final URI uri,
+ final Headers headers,
+ final String body) {
+ super(message, uri, STATUS_CODE, headers, body);
+ }
+}
diff --git a/solid/src/main/java/com/inrupt/client/solid/UnsupportedMediaTypeException.java b/solid/src/main/java/com/inrupt/client/solid/UnsupportedMediaTypeException.java
new file mode 100644
index 00000000000..6500c9fcea9
--- /dev/null
+++ b/solid/src/main/java/com/inrupt/client/solid/UnsupportedMediaTypeException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2023 Inrupt Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
+ * Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+package com.inrupt.client.solid;
+
+import com.inrupt.client.Headers;
+
+import java.net.URI;
+
+/**
+ * A runtime exception that represents an HTTP unsupported media type (415) response.
+ *
+ * @see RFC 9110 (15.5.16.) 415 Unsupported Media Type
+ */
+public class UnsupportedMediaTypeException extends SolidClientException {
+ private static final long serialVersionUID = 1312856145838280673L;
+
+ public static final int STATUS_CODE = 415;
+
+ /**
+ * Create an UnsupportedMediaTypeException exception.
+ *
+ * @param message the message
+ * @param uri the uri
+ * @param headers the response headers
+ * @param body the body
+ */
+ public UnsupportedMediaTypeException(
+ final String message,
+ final URI uri,
+ final Headers headers,
+ final String body) {
+ super(message, uri, STATUS_CODE, headers, body);
+ }
+}
diff --git a/solid/src/test/java/com/inrupt/client/solid/SolidClientTest.java b/solid/src/test/java/com/inrupt/client/solid/SolidClientTest.java
index e1a5dd8ccdc..09aad4b244a 100644
--- a/solid/src/test/java/com/inrupt/client/solid/SolidClientTest.java
+++ b/solid/src/test/java/com/inrupt/client/solid/SolidClientTest.java
@@ -22,17 +22,15 @@
import static org.junit.jupiter.api.Assertions.*;
+import com.inrupt.client.ClientProvider;
import com.inrupt.client.Headers;
+import com.inrupt.client.Response;
import com.inrupt.client.auth.Session;
import com.inrupt.client.spi.RDFFactory;
import java.io.IOException;
import java.net.URI;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Optional;
+import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.stream.Stream;
@@ -243,7 +241,10 @@ void testGetRecipeType() {
@ParameterizedTest
@MethodSource
- void testExceptionalResources(final URI uri, final int expectedStatusCode) {
+ void testExceptionalResources(
+ final URI uri,
+ final int expectedStatusCode,
+ final Class clazz) {
final CompletableFuture future =
client.read(uri, Recipe.class)
@@ -251,6 +252,7 @@ void testExceptionalResources(final URI uri, final int expectedStatusCode) {
final CompletionException err = assertThrows(CompletionException.class, () ->
future.join());
assertTrue(err.getCause() instanceof SolidClientException);
+ assertInstanceOf(clazz, err.getCause());
final SolidClientException ex = (SolidClientException) err.getCause();
assertEquals(expectedStatusCode, ex.getStatusCode());
assertEquals(uri, ex.getUri());
@@ -261,10 +263,69 @@ void testExceptionalResources(final URI uri, final int expectedStatusCode) {
private static Stream testExceptionalResources() {
return Stream.of(
Arguments.of(
- URI.create(config.get("solid_resource_uri") + "/unauthorized"), 401),
+ URI.create(config.get("solid_resource_uri") + "/unauthorized"), 401,
+ UnauthorizedException.class),
Arguments.of(
- URI.create(config.get("solid_resource_uri") + "/forbidden"), 403),
+ URI.create(config.get("solid_resource_uri") + "/forbidden"), 403,
+ ForbiddenException.class),
Arguments.of(
- URI.create(config.get("solid_resource_uri") + "/missing"), 404));
+ URI.create(config.get("solid_resource_uri") + "/missing"), 404,
+ NotFoundException.class));
+ }
+
+ @ParameterizedTest
+ @MethodSource
+ void testSpecialisedExceptions(
+ final Class clazz,
+ final int statusCode
+ ) {
+ final Headers headers = Headers.of(Collections.singletonMap("x-key", Arrays.asList("value")));
+ final SolidClient solidClient = new SolidClient(ClientProvider.getClient(), headers, false);
+ final SolidContainer resource = new SolidContainer(URI.create("http://example.com"), null, null);
+
+ final SolidClientException exception = assertThrows(
+ clazz,
+ () -> solidClient.handleResponse(resource, headers, "message")
+ .apply(new Response() {
+ @Override
+ public byte[] body() {
+ return new byte[0];
+ }
+
+ @Override
+ public Headers headers() {
+ return null;
+ }
+
+ @Override
+ public URI uri() {
+ return null;
+ }
+
+ @Override
+ public int statusCode() {
+ return statusCode;
+ }
+ })
+ );
+ assertEquals(statusCode, exception.getStatusCode());
+ }
+
+ private static Stream testSpecialisedExceptions() {
+ return Stream.of(
+ Arguments.of(BadRequestException.class, 400),
+ Arguments.of(UnauthorizedException.class, 401),
+ Arguments.of(ForbiddenException.class, 403),
+ Arguments.of(NotFoundException.class, 404),
+ Arguments.of(MethodNotAllowedException.class, 405),
+ Arguments.of(NotAcceptableException.class, 406),
+ Arguments.of(ConflictException.class, 409),
+ Arguments.of(GoneException.class, 410),
+ Arguments.of(PreconditionFailedException.class, 412),
+ Arguments.of(UnsupportedMediaTypeException.class, 415),
+ Arguments.of(TooManyRequestsException.class, 429),
+ Arguments.of(InternalServerErrorException.class, 500),
+ Arguments.of(SolidClientException.class, 418)
+ );
}
}
diff --git a/solid/src/test/java/com/inrupt/client/solid/SolidSyncClientTest.java b/solid/src/test/java/com/inrupt/client/solid/SolidSyncClientTest.java
index a5e2dfd350a..53c2aeba1a9 100644
--- a/solid/src/test/java/com/inrupt/client/solid/SolidSyncClientTest.java
+++ b/solid/src/test/java/com/inrupt/client/solid/SolidSyncClientTest.java
@@ -179,8 +179,11 @@ void testGetRecipeType() {
@ParameterizedTest
@MethodSource
- void testExceptionalResources(final URI uri, final int expectedStatusCode) {
- final SolidClientException err = assertThrows(SolidClientException.class, () -> client.read(uri, Recipe.class));
+ void testExceptionalResources(
+ final URI uri,
+ final int expectedStatusCode,
+ final Class clazz) {
+ final SolidClientException err = assertThrows(clazz, () -> client.read(uri, Recipe.class));
assertEquals(expectedStatusCode, err.getStatusCode());
assertEquals(uri, err.getUri());
@@ -191,10 +194,13 @@ void testExceptionalResources(final URI uri, final int expectedStatusCode) {
private static Stream testExceptionalResources() {
return Stream.of(
Arguments.of(
- URI.create(config.get("solid_resource_uri") + "/unauthorized"), 401),
+ URI.create(config.get("solid_resource_uri") + "/unauthorized"), 401,
+ UnauthorizedException.class),
Arguments.of(
- URI.create(config.get("solid_resource_uri") + "/forbidden"), 403),
+ URI.create(config.get("solid_resource_uri") + "/forbidden"), 403,
+ ForbiddenException.class),
Arguments.of(
- URI.create(config.get("solid_resource_uri") + "/missing"), 404));
+ URI.create(config.get("solid_resource_uri") + "/missing"), 404,
+ NotFoundException.class));
}
}