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.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 }