Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
ef39b06
add loading indicator
Hackerberg43 Jul 23, 2025
8340c44
add ui for selecting different csv format
Hackerberg43 Jul 23, 2025
89f89fe
add extra formatting option in api and datapoint service
Hackerberg43 Jul 23, 2025
6089eab
Merge remote-tracking branch 'upstream/master' into enhancement/dataE…
Hackerberg43 Jul 24, 2025
e8e18ec
add tanblefunc migration, fix typo
Hackerberg43 Jul 24, 2025
12c5dda
add translations, make format optional queryparam
Hackerberg43 Jul 24, 2025
88c6f2f
improve style
Hackerberg43 Jul 24, 2025
4405990
add aggregate option
Hackerberg43 Jul 24, 2025
288b331
fix potential resource leak using try-with-resources
Hackerberg43 Jul 24, 2025
6e428fa
convert queryparameter to a number in backend and keyed object in fro…
Hackerberg43 Jul 24, 2025
1a9870b
Update manager/src/main/java/org/openremote/manager/datapoint/AssetDa…
Hackerberg43 Jul 25, 2025
7bc414c
Update manager/src/main/java/org/openremote/manager/datapoint/AssetDa…
Hackerberg43 Jul 25, 2025
6b3ad70
Update manager/src/main/java/org/openremote/manager/datapoint/AssetDa…
Hackerberg43 Jul 25, 2025
1b6828f
Merge branch 'master' into enhancement/dataExportPage
Hackerberg43 Oct 17, 2025
041abe3
update migration script, change export format names, fix html typo
Hackerberg43 Oct 17, 2025
9d719b8
add overload for backwards compatibility - fixes failing test -added …
Hackerberg43 Oct 17, 2025
9246509
review comment - fix for non numeric data
Hackerberg43 Oct 17, 2025
ca4aa4d
Merge branch 'master' into enhancement/dataExportPage
Hackerberg43 Nov 3, 2025
82ff2e9
Merge branch 'master' into enhancement/dataExportPage
richturner Nov 12, 2025
2cc8857
Merge remote-tracking branch 'upstream/master' into enhancement/dataE…
Hackerberg43 Nov 27, 2025
332d3bb
fix enum review comments
Hackerberg43 Nov 27, 2025
496355b
add export frontend test
Hackerberg43 Dec 1, 2025
e693666
bypass camelCaseToSentenceCase
Hackerberg43 Dec 1, 2025
08fb8c2
adjust migration script date
Hackerberg43 Dec 1, 2025
92527d7
Merge branch 'master' into enhancement/dataExportPage
Hackerberg43 Dec 1, 2025
ec1f705
read http return status
Hackerberg43 Dec 3, 2025
6e9bad2
oops
Hackerberg43 Dec 3, 2025
d184d26
Use stdout for datapoint exports (#9)
Ekhorn Dec 24, 2025
ae7fb6f
Merge remote-tracking branch 'upstream/master' into enhancement/dataE…
Hackerberg43 Dec 24, 2025
e9c34df
revert dataexportlimit removal
Hackerberg43 Jan 14, 2026
b80ff38
multiple improvements
Hackerberg43 Jan 15, 2026
9173845
oops
Hackerberg43 Jan 15, 2026
e81ba72
adjust test to account for header now in sql query format
Hackerberg43 Jan 15, 2026
f3f6281
Merge branch 'master' into enhancement/dataExportPage
Hackerberg43 Jan 19, 2026
06a77ae
Merge branch 'master' into enhancement/dataExportPage
Ekhorn Jan 19, 2026
36e0c56
Merge branch 'master' into enhancement/dataExportPage
Ekhorn Jan 22, 2026
4699251
Merge branch 'master' into enhancement/dataExportPage
Ekhorn Jan 27, 2026
9f893fa
Merge branch 'master' into enhancement/dataExportPage
Ekhorn Jan 29, 2026
93f314e
Update manager/src/main/java/org/openremote/manager/datapoint/AssetDa…
Hackerberg43 Feb 18, 2026
74b4f8e
merge sql injection fix, requires readdition of tablefunc export logic
Hackerberg43 Feb 20, 2026
8c2a38c
adapt to sql injection fix
Hackerberg43 Feb 20, 2026
14a132d
Merge branch 'master' into enhancement/dataExportPage
Ekhorn Feb 24, 2026
6efcea6
Merge branch 'master' into enhancement/dataExportPage
Ekhorn Feb 24, 2026
932adb2
Merge branch 'master' into enhancement/dataExportPage
Ekhorn Feb 24, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,17 @@
import org.openremote.model.attribute.AttributeRef;
import org.openremote.model.datapoint.AssetDatapointResource;
import org.openremote.model.datapoint.DatapointPeriod;
import org.openremote.model.datapoint.DatapointExportFormat;
import org.openremote.model.datapoint.DatapointQueryTooLargeException;
import org.openremote.model.datapoint.ValueDatapoint;
import org.openremote.model.datapoint.query.AssetDatapointQuery;
import org.openremote.model.http.RequestParams;
import org.openremote.model.security.ClientRole;
import org.openremote.model.syslog.SyslogCategory;
import org.openremote.model.util.UniqueIdentifierGenerator;
import org.openremote.model.value.MetaItemType;

import java.io.File;
import java.io.FileInputStream;
import java.util.concurrent.ScheduledFuture;
import java.io.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
Expand Down Expand Up @@ -174,10 +174,18 @@ public DatapointPeriod getDatapointPeriod(RequestParams requestParams, String as
}

@Override
public void getDatapointExport(AsyncResponse asyncResponse, String attributeRefsString, long fromTimestamp, long toTimestamp) {
public void getDatapointExport(AsyncResponse asyncResponse, String attributeRefsString, long fromTimestamp, long toTimestamp, DatapointExportFormat format) {
try {
if (format == null) {
throw new WebApplicationException(Response.Status.BAD_REQUEST);
}

AttributeRef[] attributeRefs = JSON.readValue(attributeRefsString, AttributeRef[].class);

if (attributeRefs == null || attributeRefs.length == 0) {
throw new WebApplicationException(Response.Status.BAD_REQUEST);
}

for (AttributeRef attributeRef : attributeRefs) {
if (isRestrictedUser() && !assetStorageService.isUserAsset(getUserId(), attributeRef.getId())) {
throw new WebApplicationException(Response.Status.FORBIDDEN);
Expand All @@ -199,49 +207,45 @@ public void getDatapointExport(AsyncResponse asyncResponse, String attributeRefs
);
}

DATA_EXPORT_LOG.info("User '" + getUsername() + "' started data export for " + attributeRefsString + " from " + fromTimestamp + " to " + toTimestamp);
DATA_EXPORT_LOG.info("User '" + getUsername() + "' started data export for " + attributeRefsString + " from " + fromTimestamp + " to " + toTimestamp + " in format " + format);

ScheduledFuture<File> exportFuture = assetDatapointService.exportDatapoints(attributeRefs, fromTimestamp, toTimestamp);
PipedInputStream pipedInputStream = assetDatapointService.exportDatapoints(attributeRefs, fromTimestamp, toTimestamp, format);

asyncResponse.register((ConnectionCallback) disconnected -> exportFuture.cancel(true));

File exportFile = null;
asyncResponse.register((ConnectionCallback) disconnected -> {
try {
pipedInputStream.close();
} catch (IOException e) {
DATA_EXPORT_LOG.log(Level.SEVERE, "Could not close input stream: ", e);
throw new RuntimeException(e);
}
});

try {
exportFile = exportFuture.get();
try (InputStream fin = pipedInputStream;
ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {

ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream());
FileInputStream fin = new FileInputStream(exportFile);
ZipEntry zipEntry = new ZipEntry(exportFile.getName());
String fileName = UniqueIdentifierGenerator.generateId() + ".csv";
ZipEntry zipEntry = new ZipEntry(fileName);
zipOut.putNextEntry(zipEntry);
IOUtils.copy(fin, zipOut);
zipOut.closeEntry();
zipOut.close();
fin.close();

response.setContentType("application/zip");
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"dataexport.zip\"");

asyncResponse.resume(
response
);
} catch (Exception ex) {
exportFuture.cancel(true);
} catch (IOException ex) {
asyncResponse.resume(new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR));
DATA_EXPORT_LOG.log(Level.SEVERE, "Exception in ScheduledFuture: ", ex);
} finally {
if (exportFile != null && exportFile.exists()) {
try {
exportFile.delete();
} catch (Exception e) {
DATA_EXPORT_LOG.log(Level.SEVERE, "Failed to delete temporary export file: " + exportFile.getPath(), e);
}
}
DATA_EXPORT_LOG.log(Level.SEVERE, "Zip exception: ", ex);
}

response.setContentType("application/zip");
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"dataexport.zip\"");

asyncResponse.resume(
response
);
} catch (JsonProcessingException ex) {
asyncResponse.resume(new BadRequestException(ex));
} catch (DatapointQueryTooLargeException dqex) {
asyncResponse.resume(new WebApplicationException(dqex, Response.Status.REQUEST_ENTITY_TOO_LARGE));
} catch (IOException ex) {
asyncResponse.resume(new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR));
DATA_EXPORT_LOG.log(Level.SEVERE, "Failed to create piped output stream: ", ex);
}
}
}
Loading
Loading