From 610671ec5871213d3e60e818fe171a7840ebf65d Mon Sep 17 00:00:00 2001 From: Babatunde Adeyemi Date: Wed, 26 Nov 2025 18:38:23 +0100 Subject: [PATCH 1/5] chore: update server urls --- src/test/java/org/hisp/dhis/TestFixture.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/hisp/dhis/TestFixture.java b/src/test/java/org/hisp/dhis/TestFixture.java index d36c84d0..e38c0e6a 100644 --- a/src/test/java/org/hisp/dhis/TestFixture.java +++ b/src/test/java/org/hisp/dhis/TestFixture.java @@ -38,9 +38,9 @@ public final class TestFixture { public static final String DEV_URL = "https://play.im.dhis2.org/dev"; - public static final String V41_URL = "https://play.im.dhis2.org/stable-2-41-6"; + public static final String V41_URL = "https://play.im.dhis2.org/stable-2-41-6-1"; - public static final String V42_URL = "https://play.im.dhis2.org/stable-2-42-3"; + public static final String V42_URL = "https://play.im.dhis2.org/stable-2-42-3-1"; public static final String LOCAL_URL = "http://localhost/dhis"; From 5099ad9dfc7a9f4f194304d9f2f22aeae3533c46 Mon Sep 17 00:00:00 2001 From: Babatunde Adeyemi Date: Wed, 26 Nov 2025 18:45:17 +0100 Subject: [PATCH 2/5] chore: add convenience methods for downloading files --- src/main/java/org/hisp/dhis/Dhis2.java | 96 +++++++++++++++++++ .../org/hisp/dhis/FileResourceApiTest.java | 45 +++++++++ 2 files changed, 141 insertions(+) diff --git a/src/main/java/org/hisp/dhis/Dhis2.java b/src/main/java/org/hisp/dhis/Dhis2.java index 927d4095..84b26ea8 100644 --- a/src/main/java/org/hisp/dhis/Dhis2.java +++ b/src/main/java/org/hisp/dhis/Dhis2.java @@ -58,6 +58,7 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; +import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.Validate; import org.apache.hc.client5.http.HttpResponseException; import org.apache.hc.client5.http.classic.methods.HttpGet; @@ -3835,6 +3836,101 @@ public List getFileResources(Query query) { .getFileResources(); } + /** + * Downloads file content from the given URL. + * + * @param url the URL to download from. + * @param errorMessage the error message to use if download fails. + * @return the file content as a byte array. + * @throws Dhis2ClientException if the download fails. + */ + public byte[] downloadFile(URI url, String errorMessage) { + HttpGet request = withAuth(new HttpGet(url)); + + try { + return httpClient.execute( + request, + response -> { + try (InputStream in = response.getEntity().getContent()) { + return IOUtils.toByteArray(in); + } + }); + } catch (IOException ex) { + throw new Dhis2ClientException(errorMessage, ex); + } + } + + /** + * Retrieves the file content for a {@link FileResource}. + * + * @param id the object identifier. + * @return the file content as a byte array. + * @throws Dhis2ClientException if the file resource does not exist or download fails. + */ + public byte[] getFileResourceData(String id) { + URI uri = + HttpUtils.build( + config + .getResolvedUriBuilder() + .appendPath("fileResources") + .appendPath(id) + .appendPath("data")); + + return downloadFile(uri, "Failed to download file resource data"); + } + + /** + * Retrieves the file data for an aggregate data value with FILE_RESOURCE or IMAGE value type. + * + *

It allows for downloading of files attached to aggregate data values (DATA_VALUE domain). + * The standard {@link #getFileResourceData(String)} does not work for data value files as they + * have different access control rules. + * + * @param dataElement the data element UID. + * @param period the period in ISO format. (e.g., 202511, 2025Q3) + * @param orgUnit the organisation unit UID. + * @return the file content as a byte array. + * @throws Dhis2ClientException if the file resource does not exist or download fails. + */ + public byte[] getDataValueFile(String dataElement, String period, String orgUnit) { + URI uri = + HttpUtils.build( + config + .getResolvedUriBuilder() + .appendPath("dataValues") + .appendPath("files") + .addParameter("de", dataElement) + .addParameter("pe", period) + .addParameter("ou", orgUnit)); + + return downloadFile(uri, "Failed to download data value file"); + } + + /** + * Retrieves the file data for event/tracker data value with FILE_RESOURCE or IMAGE value type. + * + *

It allows for downloading of files attached to aggregate data values (DATA_VALUE domain). + * The standard {@link #getFileResourceData(String)} does not work for event files as they have + * different access control rules. + * + * @param eventUid the event UID. + * @param dataElementUid the data element UID. + * @return the file content as a byte array. + * @throws Dhis2ClientException if the file resource does not exist or download fails. + */ + public byte[] getEventFile(String eventUid, String dataElementUid) { + URI uri = + HttpUtils.build( + config + .getResolvedUriBuilder() + .appendPath("events") + .appendPath("files") + .addParameter("eventUid", eventUid) + .addParameter("dataElementUid", dataElementUid)); + + return downloadFile(uri, "Failed to download event file"); + } + // ------------------------------------------------------------------------- // System settings // ------------------------------------------------------------------------- diff --git a/src/test/java/org/hisp/dhis/FileResourceApiTest.java b/src/test/java/org/hisp/dhis/FileResourceApiTest.java index 208a77df..8277197c 100644 --- a/src/test/java/org/hisp/dhis/FileResourceApiTest.java +++ b/src/test/java/org/hisp/dhis/FileResourceApiTest.java @@ -30,6 +30,7 @@ import static org.hisp.dhis.support.Assertions.assertNotBlank; import static org.hisp.dhis.support.Assertions.assertNotEmpty; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.List; import org.hisp.dhis.model.FileResource; @@ -56,4 +57,48 @@ void testGetFileResources() { assertNotNull(file.getContentLength()); assertNotBlank(file.getContentMd5()); } + + @Test + void testGetFileResourceData() { + Dhis2 dhis2 = new Dhis2(TestFixture.DEFAULT_CONFIG); + + List resources = dhis2.getFileResources(Query.instance()); + + assertNotEmpty(resources); + + FileResource file = resources.get(0); + byte[] data = dhis2.getFileResourceData(file.getId()); + + assertNotNull(data); + assertTrue(data.length > 0); + } + + /** Tests downloading a file from an aggregate data value. */ + @Test + void testGetDataValueFile() { + Dhis2 dhis2 = new Dhis2(TestFixture.DEFAULT_CONFIG); + + String dataElement = "xk0krAO2KfJ"; + String period = "2025Q3"; + String orgUnit = "DiszpKrYNg8"; + + byte[] data = dhis2.getDataValueFile(dataElement, period, orgUnit); + + assertNotNull(data); + assertTrue(data.length > 0); + } + + /** Tests downloading a file from an event data value. */ + @Test + void testGetEventFile() { + Dhis2 dhis2 = new Dhis2(TestFixture.DEFAULT_CONFIG); + + String eventUid = "xk0krAO2KfJ"; + String dataElementUid = "DiszpKrYNg8"; + + byte[] data = dhis2.getEventFile(eventUid, dataElementUid); + + assertNotNull(data); + assertTrue(data.length > 0); + } } From 626ab75f4ae6840bfb38d66d460d43687dfde133 Mon Sep 17 00:00:00 2001 From: Babatunde Adeyemi Date: Thu, 27 Nov 2025 16:51:01 +0100 Subject: [PATCH 3/5] chore: update url --- src/test/java/org/hisp/dhis/BaseDhis2Test.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/hisp/dhis/BaseDhis2Test.java b/src/test/java/org/hisp/dhis/BaseDhis2Test.java index 28263d2d..1bd2e0ef 100644 --- a/src/test/java/org/hisp/dhis/BaseDhis2Test.java +++ b/src/test/java/org/hisp/dhis/BaseDhis2Test.java @@ -138,7 +138,7 @@ void testWithAnalyticsQueryParams() { String expected = """ - https://play.im.dhis2.org/stable-2-41-6/api/analytics\ + https://play.im.dhis2.org/stable-2-41-6-1/api/analytics\ ?dimension=dx:fbfJHSPpUQD;cYeuwXTCPkU;Jtf34kNZhzP\ &dimension=pe:202501;202502;202503\ &filter=ou:ImspTQPwCqd\ From 0f370b0dde19aa08d307b2388dcd1ca54c942762 Mon Sep 17 00:00:00 2001 From: Babatunde Adeyemi Date: Thu, 27 Nov 2025 16:51:47 +0100 Subject: [PATCH 4/5] chore: add support for downloading tracker event and TEA files --- src/main/java/org/hisp/dhis/Dhis2.java | 52 ++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/main/java/org/hisp/dhis/Dhis2.java b/src/main/java/org/hisp/dhis/Dhis2.java index 84b26ea8..398e3e85 100644 --- a/src/main/java/org/hisp/dhis/Dhis2.java +++ b/src/main/java/org/hisp/dhis/Dhis2.java @@ -3931,6 +3931,58 @@ public byte[] getEventFile(String eventUid, String dataElementUid) { return downloadFile(uri, "Failed to download event file"); } + /** + * Retrieves the file data for event/tracker data value with FILE_RESOURCE or IMAGE value type. + * + *

It uses the new Tracker API endpoint (DHIS2 2.40+). The endpoint path is: {@code + * /api/tracker/events/{eventUid}/dataValues/{dataElementUid}/file}. + * + * @param eventUid the event UID. + * @param dataElementUid the data element UID. + * @return the file content as a byte array. + * @throws Dhis2ClientException if the file resource does not exist or download fails. + */ + public byte[] getTrackerEventFile(String eventUid, String dataElementUid) { + URI uri = + HttpUtils.build( + config + .getResolvedUriBuilder() + .appendPath("tracker") + .appendPath("events") + .appendPath(eventUid) + .appendPath("dataValues") + .appendPath(dataElementUid) + .appendPath("file")); + + return downloadFile(uri, "Failed to download tracker event file"); + } + + /** + * Retrieves the file data for tracked entity attribute with FILE_RESOURCE or IMAGE value type. + * + *

It uses the new Tracker API endpoint (DHIS2 2.40+). The endpoint path is: {@code + * /api/tracker/trackedEntities/{trackedEntityUid}/attributes/{attributeUid}/file}. + * + * @param trackedEntityUid the tracked entity UID. + * @param attributeUid the tracked entity attribute UID. + * @return the file content as a byte array. + * @throws Dhis2ClientException if the file resource does not exist or download fails. + */ + public byte[] getTrackedEntityAttributeFile(String trackedEntityUid, String attributeUid) { + URI uri = + HttpUtils.build( + config + .getResolvedUriBuilder() + .appendPath("tracker") + .appendPath("trackedEntities") + .appendPath(trackedEntityUid) + .appendPath("attributes") + .appendPath(attributeUid) + .appendPath("file")); + + return downloadFile(uri, "Failed to download tracked entity attribute file"); + } + // ------------------------------------------------------------------------- // System settings // ------------------------------------------------------------------------- From accb84ca5f9752c59ca8c21fe4e8902bbad519a4 Mon Sep 17 00:00:00 2001 From: Babatunde Adeyemi Date: Tue, 2 Dec 2025 12:26:38 +0100 Subject: [PATCH 5/5] chore: update description --- src/main/java/org/hisp/dhis/Dhis2.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/hisp/dhis/Dhis2.java b/src/main/java/org/hisp/dhis/Dhis2.java index 398e3e85..3ff8aa99 100644 --- a/src/main/java/org/hisp/dhis/Dhis2.java +++ b/src/main/java/org/hisp/dhis/Dhis2.java @@ -3880,7 +3880,7 @@ public byte[] getFileResourceData(String id) { } /** - * Retrieves the file data for an aggregate data value with FILE_RESOURCE or IMAGE value type. + * Retrieves the file data for an aggregate data value. * *

It allows for downloading of files attached to aggregate data values (DATA_VALUE domain). * The standard {@link #getFileResourceData(String)} does not work for data value files as they @@ -3907,7 +3907,7 @@ public byte[] getDataValueFile(String dataElement, String period, String orgUnit } /** - * Retrieves the file data for event/tracker data value with FILE_RESOURCE or IMAGE value type. + * Retrieves the file data for event/tracker data value. * *

It allows for downloading of files attached to aggregate data values (DATA_VALUE domain). * The standard {@link #getFileResourceData(String)} does not work for event files as they have @@ -3932,7 +3932,7 @@ public byte[] getEventFile(String eventUid, String dataElementUid) { } /** - * Retrieves the file data for event/tracker data value with FILE_RESOURCE or IMAGE value type. + * Retrieves the file data for event/tracker data value. * *

It uses the new Tracker API endpoint (DHIS2 2.40+). The endpoint path is: {@code * /api/tracker/events/{eventUid}/dataValues/{dataElementUid}/file}. @@ -3958,7 +3958,7 @@ public byte[] getTrackerEventFile(String eventUid, String dataElementUid) { } /** - * Retrieves the file data for tracked entity attribute with FILE_RESOURCE or IMAGE value type. + * Retrieves the file data for tracked entity attribute. * *

It uses the new Tracker API endpoint (DHIS2 2.40+). The endpoint path is: {@code * /api/tracker/trackedEntities/{trackedEntityUid}/attributes/{attributeUid}/file}.