Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 148 additions & 0 deletions src/main/java/org/hisp/dhis/Dhis2.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -3835,6 +3836,153 @@ public List<FileResource> 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.
*
* <p>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.
*
* <p>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.
*
* <p>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.
*
* <p>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
// -------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion src/test/java/org/hisp/dhis/BaseDhis2Test.java
Original file line number Diff line number Diff line change
Expand Up @@ -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\
Expand Down
45 changes: 45 additions & 0 deletions src/test/java/org/hisp/dhis/FileResourceApiTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -56,4 +57,48 @@ void testGetFileResources() {
assertNotNull(file.getContentLength());
assertNotBlank(file.getContentMd5());
}

@Test
void testGetFileResourceData() {
Dhis2 dhis2 = new Dhis2(TestFixture.DEFAULT_CONFIG);

List<FileResource> 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);
}
}
4 changes: 2 additions & 2 deletions src/test/java/org/hisp/dhis/TestFixture.java
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down
Loading