Skip to content

Commit ae2c275

Browse files
author
Christian
committed
Add endpoints and DTOs for event and validation filter options
- Introduced `getFilterOptions` in `EventsResource` to fetch distinct batch IDs and channels. - Added `getJobFilterOptions` in `ValidationResource` to fetch distinct creators, test names, and IDs for dropdowns. - Created `EventFilterOptionsDTO` and `ValidationJobFilterOptionsDTO` to structure response data.
1 parent 9820484 commit ae2c275

5 files changed

Lines changed: 147 additions & 0 deletions

File tree

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/* (C)2026 */
2+
package com.ammann.entropy.dto;
3+
4+
import java.util.List;
5+
import org.eclipse.microprofile.openapi.annotations.media.Schema;
6+
7+
@Schema(description = "Available filter options for entropy events")
8+
public record EventFilterOptionsDTO(
9+
@Schema(description = "Distinct batch IDs present in the data") List<String> batchIds,
10+
@Schema(description = "Distinct hardware channels present in the data") List<Integer> channels) {}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/* (C)2026 */
2+
package com.ammann.entropy.dto;
3+
4+
import java.time.Instant;
5+
import java.util.List;
6+
import java.util.UUID;
7+
import org.eclipse.microprofile.openapi.annotations.media.Schema;
8+
9+
@Schema(description = "Available filter options for validation jobs and results")
10+
public record ValidationJobFilterOptionsDTO(
11+
@Schema(description = "Distinct job creators") List<String> createdByValues,
12+
@Schema(description = "Distinct NIST SP 800-22 test names") List<String> testNames,
13+
@Schema(description = "Available test suite run IDs with execution timestamps")
14+
List<RunIdOption> testSuiteRunIds,
15+
@Schema(description = "Available 800-90B assessment run IDs with execution timestamps")
16+
List<RunIdOption> assessmentRunIds) {
17+
18+
@Schema(description = "A run ID with its execution timestamp for display")
19+
public record RunIdOption(
20+
@Schema(description = "Run UUID") UUID id,
21+
@Schema(description = "Earliest execution timestamp of the run") Instant executedAt) {}
22+
}

src/main/java/com/ammann/entropy/properties/ApiProperties.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ private Events() {}
5252
public static final String QUALITY = BASE + "/quality";
5353
public static final String RATE = BASE + "/rate";
5454
public static final String INTERVAL_HISTOGRAM = BASE + "/interval-histogram";
55+
public static final String FILTER_OPTIONS = BASE + "/filter-options";
5556
}
5657

5758
/**

src/main/java/com/ammann/entropy/resource/EventsResource.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,4 +516,39 @@ private TimeWindow parseTimeWindow(String from, String to) {
516516
}
517517

518518
private record TimeWindow(Instant start, Instant end) {}
519+
520+
@GET
521+
@Path(ApiProperties.Events.FILTER_OPTIONS)
522+
@Operation(
523+
summary = "Get Event Filter Options",
524+
description =
525+
"Returns distinct values for event filters (batch IDs, channels) to populate"
526+
+ " filter dropdowns in the UI")
527+
@APIResponses({
528+
@APIResponse(
529+
responseCode = "200",
530+
description = "Filter options retrieved successfully",
531+
content =
532+
@Content(schema = @Schema(implementation = EventFilterOptionsDTO.class)))
533+
})
534+
public Response getFilterOptions() {
535+
List<String> batchIds =
536+
EntropyData.getEntityManager()
537+
.createQuery(
538+
"SELECT DISTINCT e.batchId FROM EntropyData e"
539+
+ " WHERE e.batchId IS NOT NULL ORDER BY e.batchId",
540+
String.class)
541+
.setMaxResults(200)
542+
.getResultList();
543+
544+
List<Integer> channels =
545+
EntropyData.getEntityManager()
546+
.createQuery(
547+
"SELECT DISTINCT e.channel FROM EntropyData e"
548+
+ " WHERE e.channel IS NOT NULL ORDER BY e.channel",
549+
Integer.class)
550+
.getResultList();
551+
552+
return Response.ok(new EventFilterOptionsDTO(batchIds, channels)).build();
553+
}
519554
}

src/main/java/com/ammann/entropy/resource/ValidationResource.java

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,85 @@ public Response list90BResults(
221221
return Response.ok(response).build();
222222
}
223223

224+
@GET
225+
@Path("/jobs/filter-options")
226+
@Operation(
227+
summary = "Get Validation Filter Options",
228+
description =
229+
"Returns distinct values for validation filters (creators, test names, run IDs)"
230+
+ " to populate filter dropdowns in the UI")
231+
@APIResponses({
232+
@APIResponse(
233+
responseCode = "200",
234+
description = "Filter options retrieved successfully",
235+
content =
236+
@Content(
237+
schema =
238+
@Schema(
239+
implementation =
240+
ValidationJobFilterOptionsDTO.class)))
241+
})
242+
public Response getJobFilterOptions() {
243+
List<String> createdByValues =
244+
NistValidationJob.getEntityManager()
245+
.createQuery(
246+
"SELECT DISTINCT j.createdBy FROM NistValidationJob j"
247+
+ " WHERE j.createdBy IS NOT NULL ORDER BY j.createdBy",
248+
String.class)
249+
.getResultList();
250+
251+
List<String> testNames =
252+
NistTestResult.getEntityManager()
253+
.createQuery(
254+
"SELECT DISTINCT r.testName FROM NistTestResult r"
255+
+ " WHERE r.testName IS NOT NULL ORDER BY r.testName",
256+
String.class)
257+
.getResultList();
258+
259+
@SuppressWarnings("unchecked")
260+
List<Object[]> testSuiteRows =
261+
NistTestResult.getEntityManager()
262+
.createQuery(
263+
"SELECT r.testSuiteRunId, MIN(r.executedAt)"
264+
+ " FROM NistTestResult r"
265+
+ " WHERE r.testSuiteRunId IS NOT NULL"
266+
+ " GROUP BY r.testSuiteRunId"
267+
+ " ORDER BY MIN(r.executedAt) DESC")
268+
.setMaxResults(100)
269+
.getResultList();
270+
List<ValidationJobFilterOptionsDTO.RunIdOption> testSuiteRunIds =
271+
testSuiteRows.stream()
272+
.map(
273+
r ->
274+
new ValidationJobFilterOptionsDTO.RunIdOption(
275+
(UUID) r[0], (java.time.Instant) r[1]))
276+
.toList();
277+
278+
@SuppressWarnings("unchecked")
279+
List<Object[]> assessmentRows =
280+
Nist90BResult.getEntityManager()
281+
.createQuery(
282+
"SELECT r.assessmentRunId, MIN(r.executedAt)"
283+
+ " FROM Nist90BResult r"
284+
+ " WHERE r.assessmentRunId IS NOT NULL"
285+
+ " GROUP BY r.assessmentRunId"
286+
+ " ORDER BY MIN(r.executedAt) DESC")
287+
.setMaxResults(100)
288+
.getResultList();
289+
List<ValidationJobFilterOptionsDTO.RunIdOption> assessmentRunIds =
290+
assessmentRows.stream()
291+
.map(
292+
r ->
293+
new ValidationJobFilterOptionsDTO.RunIdOption(
294+
(UUID) r[0], (java.time.Instant) r[1]))
295+
.toList();
296+
297+
return Response.ok(
298+
new ValidationJobFilterOptionsDTO(
299+
createdByValues, testNames, testSuiteRunIds, assessmentRunIds))
300+
.build();
301+
}
302+
224303
@GET
225304
@Path("/90b-results/{assessmentRunId}/estimators")
226305
@Operation(

0 commit comments

Comments
 (0)