diff --git a/src/main/java/org/hisp/dhis/Dhis2.java b/src/main/java/org/hisp/dhis/Dhis2.java index 927d4095..3ff8aa99 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,153 @@ 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. + * + *

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. + * + *

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"); + } + + /** + * 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}. + * + * @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. + * + *

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 // ------------------------------------------------------------------------- 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\ 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); + } } 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";