22
33import static io .github .jpmorganchase .fusion .filter .DatasetFilter .filterDatasets ;
44
5+ import com .google .gson .JsonArray ;
6+ import com .google .gson .JsonParser ;
57import io .github .jpmorganchase .fusion .api .APIManager ;
68import io .github .jpmorganchase .fusion .api .FusionAPIManager ;
79import io .github .jpmorganchase .fusion .api .exception .APICallException ;
2426import io .github .jpmorganchase .fusion .parsing .DefaultGsonConfig ;
2527import io .github .jpmorganchase .fusion .parsing .GsonAPIResponseParser ;
2628import io .github .jpmorganchase .fusion .parsing .ParsingException ;
27- import java .io .IOException ;
2829import java .io .InputStream ;
30+ import java .io .UnsupportedEncodingException ;
31+ import java .net .URLEncoder ;
2932import java .nio .file .Files ;
30- import java .nio .file .InvalidPathException ;
3133import java .nio .file .Paths ;
3234import java .time .LocalDate ;
3335import java .time .format .DateTimeFormatter ;
36+ import java .util .ArrayList ;
37+ import java .util .Collections ;
3438import java .util .HashMap ;
3539import java .util .List ;
3640import java .util .Map ;
@@ -281,6 +285,46 @@ public Map<String, Dataset> listDatasets(String catalogName, String contains, bo
281285 return filterDatasets (responseParser .parseDatasetResponse (json , catalogName ), contains , idContains );
282286 }
283287
288+ /**
289+ * List distribution file names for a given dataset series and format.
290+ * <p>
291+ * This calls the Fusion API, parses the JSON response, and returns a list of
292+ * file names.
293+ * </p>
294+ *
295+ * @param dataset dataset identifier
296+ * @param series series member identifier
297+ * @param fileFormat file format / distribution identifier
298+ * @param catalog catalog identifier
299+ * @param maxResults maximum number of file names to return; if = 0, all are returned
300+ * @return list of file names
301+ * @throws APICallException if the call to the Fusion API fails
302+ * @throws ParsingException if the response cannot be parsed
303+ * @throws OAuthException if a token could not be retrieved for authentication
304+ */
305+ public List <String > listDistributionFiles (
306+ String dataset , String series , String fileFormat , String catalog , int maxResults ) {
307+
308+ String url = String .format (
309+ "%scatalogs/%s/datasets/%s/datasetseries/%s/distributions/%s/files" ,
310+ this .rootURL , catalog , dataset , series , fileFormat );
311+
312+ String json = this .api .callAPI (url );
313+
314+ if (json == null || json .trim ().isEmpty ()) {
315+ return Collections .emptyList ();
316+ }
317+
318+ JsonArray arr = JsonParser .parseString (json ).getAsJsonArray ();
319+ List <String > files = new ArrayList <>();
320+
321+ for (int i = 0 ; i < arr .size () && (maxResults <= 0 || i < maxResults ); i ++) {
322+ files .add (arr .get (i ).getAsString ());
323+ }
324+
325+ return files ;
326+ }
327+
284328 /**
285329 * Get a list of the datasets in the specified catalog
286330 *
@@ -498,7 +542,7 @@ public Map<String, Distribution> listDistributions(String dataset, String series
498542 * @throws OAuthException if a token could not be retrieved for authentication
499543 */
500544 public void download (String catalogName , String dataset , String seriesMember , String distribution , String path ) {
501- download (catalogName , dataset , seriesMember , distribution , path , new HashMap <>() );
545+ download (catalogName , dataset , seriesMember , distribution , path , ( List < String >) null );
502546 }
503547
504548 /**
@@ -509,31 +553,82 @@ public void download(String catalogName, String dataset, String seriesMember, St
509553 * @param seriesMember a String representing the series member identifier.
510554 * @param distribution a String representing the distribution identifier, this is the file extension.
511555 * @param path the absolute file path where the file should be written.
512- * @param headers http headers to be provided in the request. For headers with multiple instances, the value should be a csv list
556+ * @param fileNames a list of file names to download.
513557 * @throws APICallException if the call to the Fusion API fails
514558 * @throws FileDownloadException if there is an issue handling the response from Fusion API
515559 * @throws OAuthException if a token could not be retrieved for authentication
516560 */
561+ public void download (
562+ String catalogName ,
563+ String dataset ,
564+ String seriesMember ,
565+ String distribution ,
566+ String path ,
567+ List <String > fileNames ) {
568+ download (catalogName , dataset , seriesMember , distribution , path , new HashMap <>(), fileNames );
569+ }
570+
517571 public void download (
518572 String catalogName ,
519573 String dataset ,
520574 String seriesMember ,
521575 String distribution ,
522576 String path ,
523577 Map <String , String > headers ) {
578+ download (catalogName , dataset , seriesMember , distribution , path , headers , null );
579+ }
580+
581+ public void download (
582+ String catalogName ,
583+ String dataset ,
584+ String seriesMember ,
585+ String distribution ,
586+ String path ,
587+ Map <String , String > headers ,
588+ List <String > fileNames ) {
589+
590+ if (fileNames == null || fileNames .isEmpty ()) {
591+ fileNames = listDistributionFiles (dataset , seriesMember , distribution , catalogName , 0 );
592+ }
593+
594+ if (fileNames == null || fileNames .isEmpty ()) {
595+ throw new FusionException (String .format (
596+ "No files found to download for catalog=%s, dataset=%s, series=%s, distribution=%s" ,
597+ catalogName , dataset , seriesMember , distribution ));
598+ }
524599
525- String url = String .format (
526- "%scatalogs/%s/datasets/%s/datasetseries/%s/distributions/%s" ,
527- this .rootURL , catalogName , dataset , seriesMember , distribution );
528600 try {
529601 Files .createDirectories (Paths .get (path ));
530- } catch (InvalidPathException | IOException e ) {
531- throw new FusionException (String .format ("Unable to save to target path %s" , path ), e );
602+ } catch (Exception e ) {
603+ throw new FusionException ("Unable to save to " + path , e );
604+ }
605+
606+ for (String fileName : fileNames ) {
607+
608+ // String safeFileName = (fileName.equalsIgnoreCase(distribution)
609+ // ? String.format("%s_%s_%s", catalogName, dataset, seriesMember)
610+ // : fileName)
611+ // .replaceAll("[^a-zA-Z0-9_.\\-]", "_");
612+ String safeFileName = fileName .replaceAll ("[^a-zA-Z0-9_.\\ -]" , "_" );
613+ String fullPath = path + "/" + safeFileName + "." + distribution ;
614+
615+ String url = null ;
616+ try {
617+ url = String .format (
618+ "%scatalogs/%s/datasets/%s/datasetseries/%s/distributions/%s?file=%s" ,
619+ this .rootURL ,
620+ catalogName ,
621+ dataset ,
622+ seriesMember ,
623+ distribution ,
624+ URLEncoder .encode (fileName , "UTF-8" ));
625+
626+ } catch (UnsupportedEncodingException e ) {
627+ throw new RuntimeException (e );
628+ }
629+
630+ this .api .callAPIFileDownload (url , fullPath , catalogName , dataset , headers );
532631 }
533- String fileName =
534- String .format ("%s_%s_%s" , catalogName , dataset , seriesMember ).replaceAll ("[^a-zA-Z0-9_\\ -]" , "_" );
535- String filepath = String .format ("%s/%s.%s" , path , fileName , distribution );
536- this .api .callAPIFileDownload (url , filepath , catalogName , dataset , headers );
537632 }
538633
539634 /**
@@ -548,7 +643,24 @@ public void download(
548643 * @throws OAuthException if a token could not be retrieved for authentication
549644 */
550645 public void download (String catalogName , String dataset , String seriesMember , String distribution ) {
551- this .download (catalogName , dataset , seriesMember , distribution , getDefaultPath (), new HashMap <>());
646+ this .download (catalogName , dataset , seriesMember , distribution , getDefaultPath (), new HashMap <>(), null );
647+ }
648+
649+ /**
650+ * Download a single distribution to the local filesystem. By default, this will write to downloads folder.
651+ *
652+ * @param catalogName identifier of the catalog to be queried
653+ * @param dataset a String representing the dataset identifier to download.
654+ * @param seriesMember a String representing the series member identifier.
655+ * @param distribution a String representing the distribution identifier, this is the file extension.
656+ * @param fileNames a list of file names to download.
657+ * @throws APICallException if the call to the Fusion API fails
658+ * @throws FileDownloadException if there is an issue handling the response from Fusion API
659+ * @throws OAuthException if a token could not be retrieved for authentication
660+ */
661+ public void download (
662+ String catalogName , String dataset , String seriesMember , String distribution , List <String > fileNames ) {
663+ this .download (catalogName , dataset , seriesMember , distribution , getDefaultPath (), new HashMap <>(), fileNames );
552664 }
553665
554666 /**
@@ -565,7 +677,30 @@ public void download(String catalogName, String dataset, String seriesMember, St
565677 */
566678 public void download (
567679 String catalogName , String dataset , String seriesMember , String distribution , Map <String , String > headers ) {
568- this .download (catalogName , dataset , seriesMember , distribution , getDefaultPath ());
680+ download (catalogName , dataset , seriesMember , distribution , headers , null );
681+ }
682+
683+ /**
684+ * Download a single distribution to the local filesystem. By default, this will write to downloads folder.
685+ *
686+ * @param catalogName identifier of the catalog to be queried
687+ * @param dataset a String representing the dataset identifier to download.
688+ * @param seriesMember a String representing the series member identifier.
689+ * @param distribution a String representing the distribution identifier, this is the file extension.
690+ * @param headers http headers to be provided in the request. For headers with multiple instances, the value should be a csv list
691+ * @param fileNames a list of file names to download.
692+ * @throws APICallException if the call to the Fusion API fails
693+ * @throws FileDownloadException if there is an issue handling the response from Fusion API
694+ * @throws OAuthException if a token could not be retrieved for authentication
695+ */
696+ public void download (
697+ String catalogName ,
698+ String dataset ,
699+ String seriesMember ,
700+ String distribution ,
701+ Map <String , String > headers ,
702+ List <String > fileNames ) {
703+ this .download (catalogName , dataset , seriesMember , distribution , getDefaultPath (), fileNames );
569704 }
570705
571706 /**
@@ -597,11 +732,9 @@ public void download(String catalogName, String dataset, List<String> seriesMemb
597732 * @throws FileDownloadException if there is an issue handling the response from Fusion API
598733 * @throws OAuthException if a token could not be retrieved for authentication
599734 */
600- public InputStream downloadStream (String catalogName , String dataset , String seriesMember , String distribution ) {
601- String url = String .format (
602- "%scatalogs/%s/datasets/%s/datasetseries/%s/distributions/%s" ,
603- this .rootURL , catalogName , dataset , seriesMember , distribution );
604- return downloadStream (catalogName , dataset , seriesMember , distribution , new HashMap <>());
735+ public Map <String , InputStream > downloadStream (
736+ String catalogName , String dataset , String seriesMember , String distribution ) {
737+ return downloadStream (catalogName , dataset , seriesMember , distribution , (List <String >) null );
605738 }
606739
607740 /**
@@ -613,17 +746,72 @@ public InputStream downloadStream(String catalogName, String dataset, String ser
613746 * @param dataset a String representing the dataset identifier to download.
614747 * @param seriesMember a String representing the series member identifier.
615748 * @param distribution a String representing the distribution identifier, this is the file extension.
616- * @param headers http headers to be provided in the request. For headers with multiple instances, the value should be a csv list
749+ * @param fileNames a list of file names to download.
617750 * @throws APICallException if the call to the Fusion API fails
618751 * @throws FileDownloadException if there is an issue handling the response from Fusion API
619752 * @throws OAuthException if a token could not be retrieved for authentication
620753 */
621- public InputStream downloadStream (
622- String catalogName , String dataset , String seriesMember , String distribution , Map <String , String > headers ) {
754+ public Map < String , InputStream > downloadStream (
755+ String catalogName , String dataset , String seriesMember , String distribution , List <String > fileNames ) {
623756 String url = String .format (
624757 "%scatalogs/%s/datasets/%s/datasetseries/%s/distributions/%s" ,
625758 this .rootURL , catalogName , dataset , seriesMember , distribution );
626- return this .api .callAPIFileDownload (url , catalogName , dataset , headers );
759+
760+ return downloadStream (catalogName , dataset , seriesMember , distribution , new HashMap <>(), fileNames );
761+ }
762+
763+ public Map <String , InputStream > downloadStream (
764+ String catalogName , String dataset , String seriesMember , String distribution , Map <String , String > headers ) {
765+ return downloadStream (catalogName , dataset , seriesMember , distribution , headers , null );
766+ }
767+
768+ public Map <String , InputStream > downloadStream (
769+ String catalogName ,
770+ String dataset ,
771+ String seriesMember ,
772+ String distribution ,
773+ Map <String , String > headers ,
774+ List <String > fileNames ) {
775+
776+ if (fileNames == null || fileNames .isEmpty ()) {
777+ fileNames = listDistributionFiles (dataset , seriesMember , distribution , catalogName , 0 );
778+ }
779+
780+ if (fileNames == null || fileNames .isEmpty ()) {
781+ throw new FusionException (String .format (
782+ "No files found to download for catalog=%s, dataset=%s, series=%s, distribution=%s" ,
783+ catalogName , dataset , seriesMember , distribution ));
784+ }
785+
786+ Map <String , InputStream > result = new HashMap <>();
787+
788+ for (String rawName : fileNames ) {
789+
790+ if (rawName == null || rawName .trim ().isEmpty ()) {
791+ continue ;
792+ }
793+
794+ String cleaned = rawName .replaceAll ("[/\\ \\ ]+$" , "" );
795+
796+ String url = null ;
797+ try {
798+ url = String .format (
799+ "%scatalogs/%s/datasets/%s/datasetseries/%s/distributions/%s/files/operationType/download?file=%s" ,
800+ this .rootURL ,
801+ catalogName ,
802+ dataset ,
803+ seriesMember ,
804+ distribution ,
805+ URLEncoder .encode (cleaned , "UTF-8" ));
806+ } catch (UnsupportedEncodingException e ) {
807+ throw new RuntimeException (e );
808+ }
809+
810+ InputStream stream = this .api .callAPIFileDownload (url , catalogName , dataset , headers );
811+ result .put (cleaned , stream );
812+ }
813+
814+ return result ;
627815 }
628816
629817 /**
0 commit comments