7
7
import java .util .Arrays ;
8
8
import java .util .List ;
9
9
import java .util .Objects ;
10
+ import java .util .Optional ;
10
11
12
+ import org .apache .commons .io .output .CountingOutputStream ;
13
+ import org .apache .commons .io .output .NullOutputStream ;
14
+ import org .hl7 .fhir .r4 .model .Base64BinaryType ;
11
15
import org .hl7 .fhir .r4 .model .Binary ;
12
16
import org .hl7 .fhir .r4 .model .Reference ;
13
17
import org .slf4j .Logger ;
14
18
import org .slf4j .LoggerFactory ;
15
19
16
20
import ca .uhn .fhir .rest .api .Constants ;
17
21
import dev .dsf .fhir .adapter .DeferredBase64BinaryType ;
22
+ import dev .dsf .fhir .adapter .FhirAdapter ;
18
23
import dev .dsf .fhir .help .ParameterConverter ;
19
24
import dev .dsf .fhir .help .ResponseGenerator ;
20
25
import dev .dsf .fhir .model .StreamableBase64BinaryType ;
@@ -72,12 +77,14 @@ public void write(OutputStream output) throws IOException, WebApplicationExcepti
72
77
}
73
78
74
79
private final ParameterConverter parameterConverter ;
80
+ private final FhirAdapter fhirAdapter ;
75
81
76
- public BinaryServiceJaxrs (BinaryService delegate , ParameterConverter parameterConverter )
82
+ public BinaryServiceJaxrs (BinaryService delegate , ParameterConverter parameterConverter , FhirAdapter fhirAdapter )
77
83
{
78
84
super (delegate );
79
85
80
86
this .parameterConverter = parameterConverter ;
87
+ this .fhirAdapter = fhirAdapter ;
81
88
}
82
89
83
90
@ Override
@@ -86,6 +93,7 @@ public void afterPropertiesSet() throws Exception
86
93
super .afterPropertiesSet ();
87
94
88
95
Objects .requireNonNull (parameterConverter , "parameterConverter" );
96
+ Objects .requireNonNull (fhirAdapter , "fhirAdapter" );
89
97
}
90
98
91
99
@ POST
@@ -231,7 +239,9 @@ public Response vreadHead(@PathParam("id") String id, @PathParam("version") long
231
239
232
240
private Response configureReadResponse (UriInfo uri , HttpHeaders headers , boolean head , Response read )
233
241
{
234
- if (read .getEntity () instanceof Binary binary && !isValidFhirRequest (uri , headers ))
242
+ Optional <MediaType > fhirMediaType = getValidFhirMediaType (uri , headers );
243
+
244
+ if (read .getEntity () instanceof Binary binary && fhirMediaType .isEmpty ())
235
245
{
236
246
if (mediaTypeMatches (headers , binary ))
237
247
{
@@ -276,25 +286,69 @@ private Response configureReadResponse(UriInfo uri, HttpHeaders headers, boolean
276
286
else
277
287
return Response .status (Status .NOT_ACCEPTABLE ).build ();
278
288
}
289
+ else if (read .getEntity () instanceof Binary binary && fhirMediaType .isPresent () && head )
290
+ {
291
+ ResponseBuilder b = Response .status (Status .OK );
292
+ b .type (fhirMediaType .get ());
293
+
294
+ if (binary .getMeta () != null && binary .getMeta ().getLastUpdated () != null
295
+ && binary .getMeta ().getVersionId () != null )
296
+ {
297
+ b .lastModified (binary .getMeta ().getLastUpdated ());
298
+ b .tag (new EntityTag (binary .getMeta ().getVersionId (), true ));
299
+ }
300
+
301
+ b .cacheControl (ResponseGenerator .PRIVATE_NO_CACHE_NO_TRANSFORM );
302
+
303
+ b .header (HttpHeaders .CONTENT_LENGTH , calculateFhirResponseSize (binary , fhirMediaType .get ()));
304
+
305
+ return b .build ();
306
+ }
279
307
else
280
308
return read ;
281
309
}
282
310
283
- private boolean isValidFhirRequest (UriInfo uri , HttpHeaders headers )
311
+ private long calculateFhirResponseSize (Binary binary , MediaType mediaType )
312
+ {
313
+ long dataSize = (long ) binary .getUserData (RangeRequest .USER_DATA_VALUE_DATA_SIZE );
314
+
315
+ // setting single byte to make sure data element is part of xml/json
316
+ binary .setDataElement (new Base64BinaryType (new byte [1 ]));
317
+
318
+ try (CountingOutputStream out = new CountingOutputStream (NullOutputStream .INSTANCE ))
319
+ {
320
+ fhirAdapter .writeTo (binary , Binary .class , null , null , mediaType , null , out );
321
+
322
+ // minus 4 to account for single byte in data element
323
+ return out .getByteCount () - 4 + calculateBase64EncodedLength (dataSize );
324
+ }
325
+ catch (IOException e )
326
+ {
327
+ throw new RuntimeException (e );
328
+ }
329
+ }
330
+
331
+ private long calculateBase64EncodedLength (long dataSize )
332
+ {
333
+ return dataSize < 0 ? 0 : 4 * ((dataSize + 2 ) / 3 );
334
+ }
335
+
336
+ private Optional <MediaType > getValidFhirMediaType (UriInfo uri , HttpHeaders headers )
284
337
{
285
338
// _format parameter override present and valid
286
339
if (uri .getQueryParameters ().containsKey (Constants .PARAM_FORMAT ))
287
340
{
288
- parameterConverter .getMediaTypeThrowIfNotSupported (uri , headers );
289
- return true ;
341
+ MediaType mediaType = parameterConverter .getMediaTypeThrowIfNotSupported (uri , headers );
342
+ return Optional . of ( mediaType ) ;
290
343
}
291
344
else
292
345
{
293
346
List <MediaType > types = headers .getAcceptableMediaTypes ();
294
347
MediaType accept = types == null ? null : types .get (0 );
295
348
296
349
// accept header is FHIR mime-type
297
- return Arrays .stream (FHIR_MEDIA_TYPES ).anyMatch (f -> f .equals (accept .toString ()));
350
+ return Arrays .stream (FHIR_MEDIA_TYPES ).filter (f -> f .equals (accept .toString ())).findFirst ()
351
+ .map (s -> accept );
298
352
}
299
353
}
300
354
@@ -308,13 +362,13 @@ private boolean mediaTypeMatches(HttpHeaders headers, Binary binary)
308
362
private ResponseBuilder toStreamResponse (Binary binary )
309
363
{
310
364
ResponseBuilder b = Response .status (Status .OK );
311
- b = b .type (binary .getContentType () != null ? binary .getContentType () : MediaType .APPLICATION_OCTET_STREAM );
365
+ b .type (binary .getContentType () != null ? binary .getContentType () : MediaType .APPLICATION_OCTET_STREAM );
312
366
313
367
if (binary .getMeta () != null && binary .getMeta ().getLastUpdated () != null
314
368
&& binary .getMeta ().getVersionId () != null )
315
369
{
316
- b = b .lastModified (binary .getMeta ().getLastUpdated ());
317
- b = b .tag (new EntityTag (binary .getMeta ().getVersionId (), true ));
370
+ b .lastModified (binary .getMeta ().getLastUpdated ());
371
+ b .tag (new EntityTag (binary .getMeta ().getVersionId (), true ));
318
372
}
319
373
320
374
if (binary .hasSecurityContext () && binary .getSecurityContext ().hasReference ())
@@ -323,9 +377,9 @@ private ResponseBuilder toStreamResponse(Binary binary)
323
377
b .header (Constants .HEADER_X_SECURITY_CONTEXT , binary .getSecurityContext ().getReference ());
324
378
}
325
379
326
- b = b .cacheControl (ResponseGenerator .PRIVATE_NO_CACHE_NO_TRANSFORM );
327
- b = b .header (RangeRequest .ACCEPT_RANGES_HEADER , RangeRequest .ACCEPT_RANGES_HEADER_VALUE );
328
- b = b .header (HttpHeaders .CONTENT_DISPOSITION , "attachment; filename=" + toFileName (binary ));
380
+ b .cacheControl (ResponseGenerator .PRIVATE_NO_CACHE_NO_TRANSFORM );
381
+ b .header (RangeRequest .ACCEPT_RANGES_HEADER , RangeRequest .ACCEPT_RANGES_HEADER_VALUE );
382
+ b .header (HttpHeaders .CONTENT_DISPOSITION , "attachment; filename=" + toFileName (binary ));
329
383
330
384
return b ;
331
385
}
0 commit comments