2020 */
2121package com .inrupt .client .jena ;
2222
23+ import com .inrupt .client .ClientHttpException ;
24+ import com .inrupt .client .ProblemDetails ;
2325import com .inrupt .client .Response ;
26+ import com .inrupt .client .spi .JsonService ;
27+ import com .inrupt .client .spi .ServiceProvider ;
2428
2529import java .io .ByteArrayInputStream ;
2630import java .io .IOException ;
4347public final class JenaBodyHandlers {
4448
4549 private static final String CONTENT_TYPE = "Content-Type" ;
50+ private static JsonService jsonService ;
51+ private static boolean isJsonServiceInitialized = false ;
4652
47- /**
48- * Populate a Jena {@link Model} with an HTTP response body.
49- *
50- * @return an HTTP body handler
51- */
52- public static Response .BodyHandler <Model > ofModel () {
53- return responseInfo -> responseInfo .headers ().firstValue (CONTENT_TYPE )
53+ private static JsonService getJsonService () {
54+ if (JenaBodyHandlers .isJsonServiceInitialized ) {
55+ return JenaBodyHandlers .jsonService ;
56+ }
57+ // It is acceptable for a JenaBodyHandlers instance to be in a classpath without any implementation for
58+ // JsonService, in which case the ProblemDetails exceptions will fallback to default and not be parsed.
59+ JsonService js ;
60+ try {
61+ js = ServiceProvider .getJsonService ();
62+ } catch (IllegalStateException e ) {
63+ js = null ;
64+ }
65+ JenaBodyHandlers .jsonService = js ;
66+ JenaBodyHandlers .isJsonServiceInitialized = true ;
67+ return JenaBodyHandlers .jsonService ;
68+ }
69+
70+ private static Model responseToModel (final Response .ResponseInfo responseInfo ) {
71+ return responseInfo .headers ().firstValue (CONTENT_TYPE )
5472 .map (JenaBodyHandlers ::toJenaLang ).map (lang -> {
5573 try (final var input = new ByteArrayInputStream (responseInfo .body ().array ())) {
5674 final var model = ModelFactory .createDefaultModel ();
@@ -65,12 +83,39 @@ public static Response.BodyHandler<Model> ofModel() {
6583 }
6684
6785 /**
68- * Populate a Jena {@link Graph } with an HTTP response.
86+ * Populate a Jena {@link Model } with an HTTP response body .
6987 *
7088 * @return an HTTP body handler
89+ * @deprecated Use ofJenaModel instead for consistent HTTP error handling.
7190 */
72- public static Response .BodyHandler <Graph > ofGraph () {
73- return responseInfo -> responseInfo .headers ().firstValue (CONTENT_TYPE )
91+ public static Response .BodyHandler <Model > ofModel () {
92+ return JenaBodyHandlers ::responseToModel ;
93+ }
94+
95+ /**
96+ * Populate a Jena {@link Model} with an HTTP response body.
97+ *
98+ * @return an HTTP body handler
99+ */
100+ public static Response .BodyHandler <Model > ofJenaModel () {
101+ return responseInfo -> {
102+ if (responseInfo .statusCode () >= 300 ) {
103+ throw new ClientHttpException (
104+ ProblemDetails .fromErrorResponse (
105+ responseInfo .statusCode (),
106+ responseInfo .headers (),
107+ responseInfo .body ().array (),
108+ getJsonService ()
109+ ),
110+ "Deserializing the RDF from " + responseInfo .uri () + " failed"
111+ );
112+ }
113+ return responseToModel (responseInfo );
114+ };
115+ }
116+
117+ private static Graph responseToGraph (final Response .ResponseInfo responseInfo ) {
118+ return responseInfo .headers ().firstValue (CONTENT_TYPE )
74119 .map (JenaBodyHandlers ::toJenaLang ).map (lang -> {
75120 try (final var input = new ByteArrayInputStream (responseInfo .body ().array ())) {
76121 final var graph = GraphMemFactory .createDefaultGraph ();
@@ -84,24 +129,83 @@ public static Response.BodyHandler<Graph> ofGraph() {
84129 .orElseGet (GraphMemFactory ::createDefaultGraph );
85130 }
86131
132+ /**
133+ * Populate a Jena {@link Graph} with an HTTP response.
134+ *
135+ * @return an HTTP body handler
136+ * @deprecated Use ofJenaGraph instead for consistent HTTP error handling.
137+ */
138+ public static Response .BodyHandler <Graph > ofGraph () {
139+ return JenaBodyHandlers ::responseToGraph ;
140+ }
141+
142+ /**
143+ * Populate a Jena {@link Graph} with an HTTP response.
144+ *
145+ * @return an HTTP body handler
146+ */
147+ public static Response .BodyHandler <Graph > ofJenaGraph () {
148+ return responseInfo -> {
149+ if (responseInfo .statusCode () > 300 ) {
150+ throw new ClientHttpException (
151+ ProblemDetails .fromErrorResponse (
152+ responseInfo .statusCode (),
153+ responseInfo .headers (),
154+ responseInfo .body ().array (),
155+ getJsonService ()
156+ ),
157+ "Deserializing the RDF from " + responseInfo .uri () + " failed"
158+ );
159+ }
160+ return JenaBodyHandlers .responseToGraph (responseInfo );
161+ };
162+ }
163+
164+ private static Dataset responseToDataset (final Response .ResponseInfo responseInfo ) {
165+ return responseInfo .headers ().firstValue (CONTENT_TYPE )
166+ .map (JenaBodyHandlers ::toJenaLang ).map (lang -> {
167+ try (final var input = new ByteArrayInputStream (responseInfo .body ().array ())) {
168+ final var dataset = DatasetFactory .create ();
169+ RDFDataMgr .read (dataset , input , responseInfo .uri ().toString (), lang );
170+ return dataset ;
171+ } catch (final IOException ex ) {
172+ throw new UncheckedIOException (
173+ "An I/O error occurred while data was read from the InputStream into a Dataset" , ex );
174+ }
175+ })
176+ .orElseGet (DatasetFactory ::create );
177+ }
178+
87179 /**
88180 * Populate a Jena {@link Dataset} with an HTTP response.
89181 *
90182 * @return an HTTP body handler
183+ * @deprecated Use ofJenaDataset instead for consistent HTTP error handling.
91184 */
92185 public static Response .BodyHandler <Dataset > ofDataset () {
93- return responseInfo -> responseInfo .headers ().firstValue (CONTENT_TYPE )
94- .map (JenaBodyHandlers ::toJenaLang ).map (lang -> {
95- try (final var input = new ByteArrayInputStream (responseInfo .body ().array ())) {
96- final var dataset = DatasetFactory .create ();
97- RDFDataMgr .read (dataset , input , responseInfo .uri ().toString (), lang );
98- return dataset ;
99- } catch (final IOException ex ) {
100- throw new UncheckedIOException (
101- "An I/O error occurred while data was read from the InputStream into a Dataset" , ex );
102- }
103- })
104- .orElseGet (DatasetFactory ::create );
186+ return JenaBodyHandlers ::responseToDataset ;
187+ }
188+
189+ /**
190+ * Populate a Jena {@link Dataset} with an HTTP response.
191+ *
192+ * @return an HTTP body handler
193+ */
194+ public static Response .BodyHandler <Dataset > ofJenaDataset () {
195+ return responseInfo -> {
196+ if (responseInfo .statusCode () > 300 ) {
197+ throw new ClientHttpException (
198+ ProblemDetails .fromErrorResponse (
199+ responseInfo .statusCode (),
200+ responseInfo .headers (),
201+ responseInfo .body ().array (),
202+ getJsonService ()
203+ ),
204+ "Deserializing the RDF from " + responseInfo .uri () + " failed"
205+ );
206+ }
207+ return JenaBodyHandlers .responseToDataset (responseInfo );
208+ };
105209 }
106210
107211 static Lang toJenaLang (final String mediaType ) {
0 commit comments