View Javadoc
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 }