13
13
import java .util .TimeZone ;
14
14
import java .util .concurrent .TimeUnit ;
15
15
import java .util .logging .Level ;
16
+ import java .util .regex .Matcher ;
17
+ import java .util .regex .Pattern ;
16
18
import java .util .stream .Collectors ;
17
19
import java .util .stream .Stream ;
18
20
42
44
import ca .uhn .fhir .context .FhirContext ;
43
45
import ca .uhn .fhir .model .api .annotation .ResourceDef ;
44
46
import ca .uhn .fhir .rest .api .Constants ;
47
+ import dev .dsf .bpe .v2 .client .dsf .BinaryInputStream .Range ;
45
48
import jakarta .ws .rs .ProcessingException ;
46
49
import jakarta .ws .rs .WebApplicationException ;
47
50
import jakarta .ws .rs .client .Client ;
@@ -72,6 +75,8 @@ public class DsfClientJersey implements DsfClient
72
75
private static final Map <String , Class <?>> RESOURCE_TYPES_BY_NAME = Stream .of (ResourceType .values ())
73
76
.filter (type -> !ResourceType .List .equals (type ))
74
77
.collect (Collectors .toMap (ResourceType ::name , DsfClientJersey ::getFhirClass ));
78
+ private static final String CONTENT_RANGE_PATTERN_TEXT = "bytes (?<start>\\ d+)-(?<end>\\ d+)\\ /(?<size>\\ d+)" ;
79
+ private static final Pattern CONTENT_RANGE_PATTERN = Pattern .compile (CONTENT_RANGE_PATTERN_TEXT );
75
80
76
81
private static Class <?> getFhirClass (ResourceType type )
77
82
{
@@ -570,7 +575,7 @@ else if (Status.NOT_FOUND.getStatusCode() == response.getStatus())
570
575
}
571
576
572
577
@ Override
573
- public InputStream readBinary (String id , MediaType mediaType )
578
+ public BinaryInputStream readBinary (String id , MediaType mediaType )
574
579
{
575
580
Objects .requireNonNull (id , "id" );
576
581
Objects .requireNonNull (mediaType , "mediaType" );
@@ -580,11 +585,108 @@ public InputStream readBinary(String id, MediaType mediaType)
580
585
logger .debug ("HTTP {}: {}" , response .getStatusInfo ().getStatusCode (),
581
586
response .getStatusInfo ().getReasonPhrase ());
582
587
if (Status .OK .getStatusCode () == response .getStatus ())
583
- return response . readEntity ( InputStream . class );
588
+ return toBinaryInputStream ( response );
584
589
else
585
590
throw handleError (response );
586
591
}
587
592
593
+ @ Override
594
+ public BinaryInputStream readBinary (String id , MediaType mediaType , Long rangeStart , Long rangeEndInclusive ,
595
+ Map <String , String > additionalHeaders )
596
+ {
597
+ Objects .requireNonNull (id , "id" );
598
+ Objects .requireNonNull (mediaType , "mediaType" );
599
+
600
+ Builder builder = getResource ().path ("Binary" ).path (id ).request ().accept (mediaType );
601
+
602
+ String range = getRangeHeader (rangeStart , rangeEndInclusive );
603
+ if (range != null )
604
+ builder = builder .header ("Range" , range );
605
+
606
+ if (additionalHeaders != null )
607
+ {
608
+ for (Entry <String , String > e : additionalHeaders .entrySet ())
609
+ builder = builder .header (e .getKey (), e .getValue ());
610
+ }
611
+
612
+ Response response = builder .get ();
613
+
614
+ logger .debug ("HTTP {}: {}" , response .getStatusInfo ().getStatusCode (),
615
+ response .getStatusInfo ().getReasonPhrase ());
616
+ if (Status .OK .getStatusCode () == response .getStatus ()
617
+ || Status .PARTIAL_CONTENT .getStatusCode () == response .getStatus ())
618
+ return toBinaryInputStream (response );
619
+ else
620
+ throw handleError (response );
621
+ }
622
+
623
+ private String getRangeHeader (Long rangeStart , Long rangeEndInclusive )
624
+ {
625
+ // from given start to end of file
626
+ if (rangeStart != null && rangeStart >= 0 && rangeEndInclusive == null )
627
+ {
628
+ return "bytes=" + rangeStart + "-" ;
629
+ }
630
+ // from given start to given end (inclusive)
631
+ else if (rangeStart != null && rangeStart >= 0 && rangeEndInclusive != null && rangeEndInclusive > rangeStart )
632
+ {
633
+ return "bytes=" + rangeStart + "-" + rangeEndInclusive ;
634
+ }
635
+ // from length + end to end of file
636
+ else if (rangeStart == null && rangeEndInclusive != null && rangeEndInclusive < 0 )
637
+ {
638
+ return "bytes=" + rangeEndInclusive ;
639
+ }
640
+ else
641
+ return null ;
642
+ }
643
+
644
+ private BinaryInputStream toBinaryInputStream (Response response )
645
+ {
646
+ long contentLength = getContentLength (response );
647
+ Range range = getRange (response );
648
+ InputStream input = response .readEntity (InputStream .class );
649
+
650
+ return new BinaryInputStream (input , contentLength , range );
651
+ }
652
+
653
+ private long getContentLength (Response response )
654
+ {
655
+ try
656
+ {
657
+ return Long .parseLong (response .getHeaderString ("Content-Length" ));
658
+ }
659
+ catch (NumberFormatException e )
660
+ {
661
+ return Long .MIN_VALUE ;
662
+ }
663
+ }
664
+
665
+ private Range getRange (Response response )
666
+ {
667
+ String contentRange = response .getHeaderString ("Content-Range" );
668
+ if (contentRange == null )
669
+ return null ;
670
+
671
+ Matcher matcher = CONTENT_RANGE_PATTERN .matcher (contentRange );
672
+ if (matcher .matches ())
673
+ {
674
+ try
675
+ {
676
+ long start = Long .parseLong (matcher .group ("start" ));
677
+ long end = Long .parseLong (matcher .group ("end" ));
678
+ long size = Long .parseLong (matcher .group ("size" ));
679
+
680
+ return new Range (size , start , end );
681
+ }
682
+ catch (NumberFormatException e )
683
+ {
684
+ }
685
+ }
686
+
687
+ return null ;
688
+ }
689
+
588
690
@ Override
589
691
public Resource read (String resourceTypeName , String id , String version )
590
692
{
@@ -644,7 +746,7 @@ else if (Status.NOT_FOUND.getStatusCode() == response.getStatus())
644
746
}
645
747
646
748
@ Override
647
- public InputStream readBinary (String id , String version , MediaType mediaType )
749
+ public BinaryInputStream readBinary (String id , String version , MediaType mediaType )
648
750
{
649
751
Objects .requireNonNull (id , "id" );
650
752
Objects .requireNonNull (version , "version" );
@@ -656,7 +758,39 @@ public InputStream readBinary(String id, String version, MediaType mediaType)
656
758
logger .debug ("HTTP {}: {}" , response .getStatusInfo ().getStatusCode (),
657
759
response .getStatusInfo ().getReasonPhrase ());
658
760
if (Status .OK .getStatusCode () == response .getStatus ())
659
- return response .readEntity (InputStream .class );
761
+ return toBinaryInputStream (response );
762
+ else
763
+ throw handleError (response );
764
+ }
765
+
766
+ @ Override
767
+ public BinaryInputStream readBinary (String id , String version , MediaType mediaType , Long rangeStart ,
768
+ Long rangeEndInclusive , Map <String , String > additionalHeaders )
769
+ {
770
+ Objects .requireNonNull (id , "id" );
771
+ Objects .requireNonNull (version , "version" );
772
+ Objects .requireNonNull (mediaType , "mediaType" );
773
+
774
+ Builder builder = getResource ().path ("Binary" ).path (id ).path ("_history" ).path (version ).request ()
775
+ .accept (mediaType );
776
+
777
+ String range = getRangeHeader (rangeStart , rangeEndInclusive );
778
+ if (range != null )
779
+ builder = builder .header ("Range" , range );
780
+
781
+ if (additionalHeaders != null )
782
+ {
783
+ for (Entry <String , String > e : additionalHeaders .entrySet ())
784
+ builder = builder .header (e .getKey (), e .getValue ());
785
+ }
786
+
787
+ Response response = builder .get ();
788
+
789
+ logger .debug ("HTTP {}: {}" , response .getStatusInfo ().getStatusCode (),
790
+ response .getStatusInfo ().getReasonPhrase ());
791
+ if (Status .OK .getStatusCode () == response .getStatus ()
792
+ || Status .PARTIAL_CONTENT .getStatusCode () == response .getStatus ())
793
+ return toBinaryInputStream (response );
660
794
else
661
795
throw handleError (response );
662
796
}
0 commit comments