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