1 package de.dlr.shepard.context.references.timeseriesreference.endpoints; 2 3 import de.dlr.shepard.common.filters.Subscribable; 4 import de.dlr.shepard.common.util.Constants; 5 import de.dlr.shepard.context.references.timeseriesreference.io.TimeseriesReferenceIO; 6 import de.dlr.shepard.context.references.timeseriesreference.services.TimeseriesReferenceService; 7 import de.dlr.shepard.data.timeseries.io.TimeseriesWithDataPoints; 8 import de.dlr.shepard.data.timeseries.model.enums.AggregateFunction; 9 import de.dlr.shepard.data.timeseries.model.enums.CsvFormat; 10 import de.dlr.shepard.data.timeseries.model.enums.FillOption; 11 import jakarta.enterprise.context.RequestScoped; 12 import jakarta.inject.Inject; 13 import jakarta.validation.Valid; 14 import jakarta.validation.constraints.NotNull; 15 import jakarta.validation.constraints.PositiveOrZero; 16 import jakarta.ws.rs.Consumes; 17 import jakarta.ws.rs.DELETE; 18 import jakarta.ws.rs.DefaultValue; 19 import jakarta.ws.rs.GET; 20 import jakarta.ws.rs.POST; 21 import jakarta.ws.rs.Path; 22 import jakarta.ws.rs.PathParam; 23 import jakarta.ws.rs.Produces; 24 import jakarta.ws.rs.QueryParam; 25 import jakarta.ws.rs.core.MediaType; 26 import jakarta.ws.rs.core.Response; 27 import jakarta.ws.rs.core.Response.Status; 28 import java.io.IOException; 29 import java.util.ArrayList; 30 import java.util.List; 31 import java.util.Set; 32 import java.util.UUID; 33 import org.eclipse.microprofile.openapi.annotations.Operation; 34 import org.eclipse.microprofile.openapi.annotations.enums.SchemaType; 35 import org.eclipse.microprofile.openapi.annotations.media.Content; 36 import org.eclipse.microprofile.openapi.annotations.media.Schema; 37 import org.eclipse.microprofile.openapi.annotations.parameters.Parameter; 38 import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody; 39 import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; 40 import org.eclipse.microprofile.openapi.annotations.tags.Tag; 41 42 @Consumes(MediaType.APPLICATION_JSON) 43 @Produces(MediaType.APPLICATION_JSON) 44 @Path( 45 Constants.COLLECTIONS + 46 "/{" + 47 Constants.COLLECTION_ID + 48 "}/" + 49 Constants.DATA_OBJECTS + 50 "/{" + 51 Constants.DATA_OBJECT_ID + 52 "}/" + 53 Constants.TIMESERIES_REFERENCES 54 ) 55 @RequestScoped 56 public class TimeseriesReferenceRest { 57 58 @Inject 59 TimeseriesReferenceService timeseriesReferenceService; 60 61 @GET 62 @Tag(name = Constants.TIMESERIES_REFERENCE) 63 @Operation(description = "Get all timeseries references") 64 @APIResponse( 65 description = "ok", 66 responseCode = "200", 67 content = @Content(schema = @Schema(type = SchemaType.ARRAY, implementation = TimeseriesReferenceIO.class)) 68 ) 69 @APIResponse(responseCode = "400", description = "bad request") 70 @APIResponse(responseCode = "401", description = "not authorized") 71 @APIResponse(responseCode = "403", description = "forbidden") 72 @APIResponse(responseCode = "404", description = "not found") 73 @Parameter(name = Constants.COLLECTION_ID) 74 @Parameter(name = Constants.DATA_OBJECT_ID) 75 @Parameter(name = Constants.VERSION_UID) 76 public Response getAllTimeseriesReferences( 77 @PathParam(Constants.COLLECTION_ID) @NotNull @PositiveOrZero Long collectionId, 78 @PathParam(Constants.DATA_OBJECT_ID) @NotNull @PositiveOrZero Long dataObjectId, 79 @QueryParam(Constants.VERSION_UID) @org.hibernate.validator.constraints.UUID String versionUID 80 ) { 81 UUID versionUUID = null; 82 if (versionUID != null) { 83 versionUUID = UUID.fromString(versionUID); 84 } 85 var references = timeseriesReferenceService.getAllReferencesByDataObjectId(collectionId, dataObjectId, versionUUID); 86 var result = new ArrayList<TimeseriesReferenceIO>(references.size()); 87 for (var reference : references) { 88 result.add(new TimeseriesReferenceIO(reference)); 89 } 90 91 return Response.ok(result).build(); 92 } 93 94 @GET 95 @Path("/{" + Constants.TIMESERIES_REFERENCE_ID + "}") 96 @Tag(name = Constants.TIMESERIES_REFERENCE) 97 @Operation(description = "Get timeseries reference") 98 @APIResponse( 99 description = "ok", 100 responseCode = "200", 101 content = @Content(schema = @Schema(implementation = TimeseriesReferenceIO.class)) 102 ) 103 @APIResponse(responseCode = "400", description = "bad request") 104 @APIResponse(responseCode = "401", description = "not authorized") 105 @APIResponse(responseCode = "403", description = "forbidden") 106 @APIResponse(responseCode = "404", description = "not found") 107 @Parameter(name = Constants.COLLECTION_ID) 108 @Parameter(name = Constants.DATA_OBJECT_ID) 109 @Parameter(name = Constants.TIMESERIES_REFERENCE_ID) 110 @Parameter(name = Constants.VERSION_UID) 111 public Response getTimeseriesReference( 112 @PathParam(Constants.COLLECTION_ID) @NotNull @PositiveOrZero Long collectionId, 113 @PathParam(Constants.DATA_OBJECT_ID) @NotNull @PositiveOrZero Long dataObjectId, 114 @PathParam(Constants.TIMESERIES_REFERENCE_ID) @NotNull @PositiveOrZero Long timeseriesId, 115 @QueryParam(Constants.VERSION_UID) @org.hibernate.validator.constraints.UUID String versionUID 116 ) { 117 UUID versionUUID = null; 118 if (versionUID != null) { 119 versionUUID = UUID.fromString(versionUID); 120 } 121 var result = timeseriesReferenceService.getReference(collectionId, dataObjectId, timeseriesId, versionUUID); 122 123 return Response.ok(new TimeseriesReferenceIO(result)).build(); 124 } 125 126 @POST 127 @Subscribable 128 @Tag(name = Constants.TIMESERIES_REFERENCE) 129 @Operation(description = "Create a new timeseries reference") 130 @APIResponse( 131 description = "created", 132 responseCode = "201", 133 content = @Content(schema = @Schema(implementation = TimeseriesReferenceIO.class)) 134 ) 135 @APIResponse(responseCode = "400", description = "bad request") 136 @APIResponse(responseCode = "401", description = "not authorized") 137 @APIResponse(responseCode = "403", description = "forbidden") 138 @APIResponse(responseCode = "404", description = "not found") 139 @Parameter(name = Constants.COLLECTION_ID) 140 @Parameter(name = Constants.DATA_OBJECT_ID) 141 public Response createTimeseriesReference( 142 @PathParam(Constants.COLLECTION_ID) @NotNull @PositiveOrZero Long collectionId, 143 @PathParam(Constants.DATA_OBJECT_ID) @NotNull @PositiveOrZero Long dataObjectId, 144 @RequestBody( 145 required = true, 146 content = @Content(schema = @Schema(implementation = TimeseriesReferenceIO.class)) 147 ) @Valid TimeseriesReferenceIO timeseriesReference 148 ) { 149 var result = timeseriesReferenceService.createReference(collectionId, dataObjectId, timeseriesReference); 150 151 return Response.ok(new TimeseriesReferenceIO(result)).status(Status.CREATED).build(); 152 } 153 154 @DELETE 155 @Path("/{" + Constants.TIMESERIES_REFERENCE_ID + "}") 156 @Subscribable 157 @Tag(name = Constants.TIMESERIES_REFERENCE) 158 @Operation(description = "Delete timeseries reference") 159 @APIResponse(description = "deleted", responseCode = "204") 160 @APIResponse(responseCode = "400", description = "bad request") 161 @APIResponse(responseCode = "401", description = "not authorized") 162 @APIResponse(responseCode = "403", description = "forbidden") 163 @APIResponse(responseCode = "404", description = "not found") 164 @Parameter(name = Constants.COLLECTION_ID) 165 @Parameter(name = Constants.DATA_OBJECT_ID) 166 @Parameter(name = Constants.TIMESERIES_REFERENCE_ID) 167 public Response deleteTimeseriesReference( 168 @PathParam(Constants.COLLECTION_ID) @NotNull @PositiveOrZero Long collectionId, 169 @PathParam(Constants.DATA_OBJECT_ID) @NotNull @PositiveOrZero Long dataObjectId, 170 @PathParam(Constants.TIMESERIES_REFERENCE_ID) @NotNull @PositiveOrZero Long timeseriesId 171 ) { 172 timeseriesReferenceService.deleteReference(collectionId, dataObjectId, timeseriesId); 173 return Response.status(Status.NO_CONTENT).build(); 174 } 175 176 @GET 177 @Path("/{" + Constants.TIMESERIES_REFERENCE_ID + "}/" + Constants.PAYLOAD) 178 @Tag(name = Constants.TIMESERIES_REFERENCE) 179 @Operation(description = "Get timeseries reference payload") 180 @APIResponse( 181 description = "ok", 182 responseCode = "200", 183 content = @Content(schema = @Schema(type = SchemaType.ARRAY, implementation = TimeseriesWithDataPoints.class)) 184 ) 185 @APIResponse(responseCode = "400", description = "bad request") 186 @APIResponse(responseCode = "401", description = "not authorized") 187 @APIResponse(responseCode = "403", description = "forbidden") 188 @APIResponse(responseCode = "404", description = "not found") 189 @Parameter(name = Constants.COLLECTION_ID) 190 @Parameter(name = Constants.DATA_OBJECT_ID) 191 @Parameter(name = Constants.TIMESERIES_REFERENCE_ID) 192 @Parameter(name = Constants.FUNCTION, deprecated = true, description = "A function providing metrics.") 193 @Parameter( 194 name = Constants.GROUP_BY, 195 deprecated = true, 196 description = "Nanoseconds describing a bucket size over which a metric should be calculated." 197 ) 198 @Parameter(name = Constants.FILLOPTION, deprecated = true) 199 @Parameter(name = Constants.DEVICE) 200 @Parameter(name = Constants.LOCATION) 201 @Parameter(name = Constants.SYMBOLICNAME) 202 @Parameter(name = Constants.MEASUREMENT) 203 @Parameter(name = Constants.FIELD) 204 public Response getTimeseriesPayload( 205 @PathParam(Constants.COLLECTION_ID) @NotNull @PositiveOrZero Long collectionId, 206 @PathParam(Constants.DATA_OBJECT_ID) @NotNull @PositiveOrZero Long dataObjectId, 207 @PathParam(Constants.TIMESERIES_REFERENCE_ID) @NotNull @PositiveOrZero Long timeseriesReferenceId, 208 @QueryParam(Constants.FUNCTION) AggregateFunction function, 209 @QueryParam(Constants.GROUP_BY) Long groupBy, 210 @QueryParam(Constants.FILLOPTION) FillOption fillOption, 211 @QueryParam(Constants.DEVICE) Set<String> deviceFilterTag, 212 @QueryParam(Constants.LOCATION) Set<String> locationFilterTag, 213 @QueryParam(Constants.SYMBOLICNAME) Set<String> symbolicNameFilterTag, 214 @QueryParam(Constants.MEASUREMENT) Set<String> measurementFilterTag, 215 @QueryParam(Constants.FIELD) Set<String> fieldFilterTag 216 ) { 217 List<TimeseriesWithDataPoints> timeseriesWithDataPointsList = 218 timeseriesReferenceService.getReferencedTimeseriesWithDataPointsList( 219 collectionId, 220 dataObjectId, 221 timeseriesReferenceId, 222 function, 223 groupBy, 224 fillOption, 225 deviceFilterTag, 226 locationFilterTag, 227 symbolicNameFilterTag, 228 measurementFilterTag, 229 fieldFilterTag 230 ); 231 return Response.ok(timeseriesWithDataPointsList).build(); 232 } 233 234 @GET 235 @Path("/{" + Constants.TIMESERIES_REFERENCE_ID + "}/" + Constants.EXPORT) 236 @Produces({ MediaType.APPLICATION_OCTET_STREAM, MediaType.APPLICATION_JSON }) 237 @Tag(name = Constants.TIMESERIES_REFERENCE) 238 @Operation(description = "Export timeseries reference payload") 239 @APIResponse( 240 description = "ok", 241 responseCode = "200", 242 content = @Content( 243 mediaType = MediaType.APPLICATION_OCTET_STREAM, 244 schema = @Schema(type = SchemaType.STRING, format = "binary") 245 ) 246 ) 247 @APIResponse(responseCode = "400", description = "bad request") 248 @APIResponse(responseCode = "401", description = "not authorized") 249 @APIResponse(responseCode = "403", description = "forbidden") 250 @APIResponse(responseCode = "404", description = "not found") 251 @Parameter(name = Constants.COLLECTION_ID) 252 @Parameter(name = Constants.DATA_OBJECT_ID) 253 @Parameter(name = Constants.TIMESERIES_REFERENCE_ID) 254 @Parameter(name = Constants.FUNCTION) 255 @Parameter(name = Constants.GROUP_BY) 256 @Parameter(name = Constants.FILLOPTION) 257 @Parameter(name = Constants.DEVICE) 258 @Parameter(name = Constants.LOCATION) 259 @Parameter(name = Constants.SYMBOLICNAME) 260 @Parameter(name = Constants.MEASUREMENT) 261 @Parameter(name = Constants.FIELD) 262 @Parameter(name = Constants.CSVFORMAT) 263 public Response exportTimeseriesPayload( 264 @PathParam(Constants.COLLECTION_ID) @NotNull @PositiveOrZero Long collectionId, 265 @PathParam(Constants.DATA_OBJECT_ID) @NotNull @PositiveOrZero Long dataObjectId, 266 @PathParam(Constants.TIMESERIES_REFERENCE_ID) @NotNull @PositiveOrZero Long timeseriesReferenceId, 267 @QueryParam(Constants.FUNCTION) AggregateFunction function, 268 @QueryParam(Constants.GROUP_BY) Long groupBy, 269 @QueryParam(Constants.FILLOPTION) FillOption fillOption, 270 @QueryParam(Constants.DEVICE) Set<String> deviceFilterTag, 271 @QueryParam(Constants.LOCATION) Set<String> locationFilterTag, 272 @QueryParam(Constants.SYMBOLICNAME) Set<String> symbolicNameFilterTag, 273 @QueryParam(Constants.MEASUREMENT) Set<String> measurementFilterTag, 274 @QueryParam(Constants.FIELD) Set<String> fieldFilterTag, 275 @QueryParam(Constants.CSVFORMAT) @DefaultValue(value = "ROW") CsvFormat csvFormat 276 ) throws IOException { 277 var stream = timeseriesReferenceService.exportReferencedTimeseriesByShepardId( 278 collectionId, 279 dataObjectId, 280 timeseriesReferenceId, 281 function, 282 groupBy, 283 fillOption, 284 deviceFilterTag, 285 locationFilterTag, 286 symbolicNameFilterTag, 287 measurementFilterTag, 288 fieldFilterTag, 289 csvFormat 290 ); 291 if (stream == null) return Response.status(Status.NOT_FOUND).build(); 292 return Response.ok(stream, MediaType.APPLICATION_OCTET_STREAM).build(); 293 } 294 }