View Javadoc
1   package de.dlr.shepard.endpoints;
2   
3   import java.io.IOException;
4   import java.io.InputStream;
5   import java.util.ArrayList;
6   
7   import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
8   import org.glassfish.jersey.media.multipart.FormDataParam;
9   
10  import de.dlr.shepard.exceptions.InvalidRequestException;
11  import de.dlr.shepard.filters.Subscribable;
12  import de.dlr.shepard.influxDB.FillOption;
13  import de.dlr.shepard.influxDB.SingleValuedUnaryFunction;
14  import de.dlr.shepard.influxDB.Timeseries;
15  import de.dlr.shepard.influxDB.TimeseriesPayload;
16  import de.dlr.shepard.neo4Core.io.PermissionsIO;
17  import de.dlr.shepard.neo4Core.io.TimeseriesContainerIO;
18  import de.dlr.shepard.neo4Core.orderBy.ContainerAttributes;
19  import de.dlr.shepard.neo4Core.services.PermissionsService;
20  import de.dlr.shepard.neo4Core.services.TimeseriesContainerService;
21  import de.dlr.shepard.security.PermissionsUtil;
22  import de.dlr.shepard.util.Constants;
23  import de.dlr.shepard.util.QueryParamHelper;
24  import io.swagger.v3.oas.annotations.Parameter;
25  import jakarta.validation.Valid;
26  import jakarta.ws.rs.Consumes;
27  import jakarta.ws.rs.DELETE;
28  import jakarta.ws.rs.GET;
29  import jakarta.ws.rs.POST;
30  import jakarta.ws.rs.PUT;
31  import jakarta.ws.rs.Path;
32  import jakarta.ws.rs.PathParam;
33  import jakarta.ws.rs.Produces;
34  import jakarta.ws.rs.QueryParam;
35  import jakarta.ws.rs.core.Context;
36  import jakarta.ws.rs.core.MediaType;
37  import jakarta.ws.rs.core.Response;
38  import jakarta.ws.rs.core.Response.Status;
39  import jakarta.ws.rs.core.SecurityContext;
40  
41  @Consumes(MediaType.APPLICATION_JSON)
42  @Produces(MediaType.APPLICATION_JSON)
43  @Path(Constants.TIMESERIES)
44  public class TimeseriesRestImpl implements TimeseriesRest {
45  	private TimeseriesContainerService timeseriesContainerService = new TimeseriesContainerService();
46  	private PermissionsService permissionsService = new PermissionsService();
47  
48  	@Context
49  	private SecurityContext securityContext;
50  
51  	@GET
52  	@Override
53  	public Response getAllTimeseriesContainers(@QueryParam(Constants.QP_NAME) String name,
54  			@QueryParam(Constants.QP_PAGE) Integer page, @QueryParam(Constants.QP_SIZE) Integer size,
55  			@QueryParam(Constants.QP_ORDER_BY_ATTRIBUTE) ContainerAttributes orderBy,
56  			@QueryParam(Constants.QP_ORDER_DESC) Boolean orderDesc) {
57  		var params = new QueryParamHelper();
58  		if (name != null)
59  			params = params.withName(name);
60  		if (page != null && size != null)
61  			params = params.withPageAndSize(page, size);
62  		if (orderBy != null)
63  			params = params.withOrderByAttribute(orderBy, orderDesc);
64  		var containers = timeseriesContainerService.getAllContainers(params,
65  				securityContext.getUserPrincipal().getName());
66  		var result = new ArrayList<TimeseriesContainerIO>(containers.size());
67  		for (var container : containers) {
68  			result.add(new TimeseriesContainerIO(container));
69  		}
70  		return Response.ok(result).build();
71  	}
72  
73  	@GET
74  	@Path("/{" + Constants.TIMESERIES_CONTAINER_ID + "}")
75  	@Override
76  	public Response getTimeseriesContainer(@PathParam(Constants.TIMESERIES_CONTAINER_ID) long timeseriesId) {
77  		var result = timeseriesContainerService.getContainer(timeseriesId);
78  		return Response.ok(new TimeseriesContainerIO(result)).build();
79  	}
80  
81  	@POST
82  	@Override
83  	public Response createTimeseriesContainer(TimeseriesContainerIO timeseriesContainer) {
84  		var result = timeseriesContainerService.createContainer(timeseriesContainer,
85  				securityContext.getUserPrincipal().getName());
86  
87  		return Response.ok(new TimeseriesContainerIO(result)).status(Status.CREATED).build();
88  	}
89  
90  	@DELETE
91  	@Path("/{" + Constants.TIMESERIES_CONTAINER_ID + "}")
92  	@Subscribable
93  	@Override
94  	public Response deleteTimeseriesContainer(@PathParam(Constants.TIMESERIES_CONTAINER_ID) long timeseriesId) {
95  		var result = timeseriesContainerService.deleteContainer(timeseriesId,
96  				securityContext.getUserPrincipal().getName());
97  
98  		return result ? Response.status(Status.NO_CONTENT).build()
99  				: Response.status(Status.INTERNAL_SERVER_ERROR).build();
100 	}
101 
102 	@POST
103 	@Path("/{" + Constants.TIMESERIES_CONTAINER_ID + "}/" + Constants.PAYLOAD)
104 	@Subscribable
105 	@Override
106 	public Response createTimeseries(@PathParam(Constants.TIMESERIES_CONTAINER_ID) long timeseriesId,
107 			TimeseriesPayload payload) {
108 		var result = timeseriesContainerService.createTimeseries(timeseriesId, payload);
109 		return result != null ? Response.status(Status.CREATED).entity(result).build()
110 				: Response.status(Status.INTERNAL_SERVER_ERROR).build();
111 	}
112 
113 	@GET
114 	@Path("/{" + Constants.TIMESERIES_CONTAINER_ID + "}/" + Constants.AVAILABLE)
115 	@Override
116 	public Response getTimeseriesAvailable(@PathParam(Constants.TIMESERIES_CONTAINER_ID) long timeseriesContainerId) {
117 		return Response.ok(timeseriesContainerService.getTimeseriesAvailable(timeseriesContainerId)).build();
118 	}
119 
120 	@GET
121 	@Path("/{" + Constants.TIMESERIES_CONTAINER_ID + "}/" + Constants.PAYLOAD)
122 	@Override
123 	public Response getTimeseries(@PathParam(Constants.TIMESERIES_CONTAINER_ID) long timeseriesContainerId,
124 			@QueryParam(Constants.MEASUREMENT) @Parameter(required = true) String measurement,
125 			@QueryParam(Constants.LOCATION) @Parameter(required = true) String location,
126 			@QueryParam(Constants.DEVICE) @Parameter(required = true) String device,
127 			@QueryParam(Constants.SYMBOLICNAME) @Parameter(required = true) String symbolicName,
128 			@QueryParam(Constants.FIELD) @Parameter(required = true) String field,
129 			@QueryParam(Constants.START) @Parameter(required = true) long start,
130 			@QueryParam(Constants.END) @Parameter(required = true) long end,
131 			@QueryParam(Constants.FUNCTION) SingleValuedUnaryFunction function,
132 			@QueryParam(Constants.GROUP_BY) Long groupBy, @QueryParam(Constants.FILLOPTION) FillOption fillOption) {
133 		if (measurement == null || location == null || device == null || symbolicName == null || field == null) {
134 			throw new InvalidRequestException("Some query params are missing");
135 		}
136 
137 		var timeseries = new Timeseries(measurement, device, location, symbolicName, field);
138 		var result = timeseriesContainerService.getTimeseriesPayload(timeseriesContainerId, timeseries, start, end,
139 				function, groupBy, fillOption);
140 
141 		return result != null ? Response.ok(result).build() : Response.status(Status.NOT_FOUND).build();
142 	}
143 
144 	@GET
145 	@Produces({ MediaType.APPLICATION_OCTET_STREAM, MediaType.APPLICATION_JSON })
146 	@Path("/{" + Constants.TIMESERIES_CONTAINER_ID + "}/" + Constants.EXPORT)
147 	@Override
148 	public Response exportTimeseries(@PathParam(Constants.TIMESERIES_CONTAINER_ID) long timeseriesContainerId,
149 			@QueryParam(Constants.MEASUREMENT) @Parameter(required = true) String measurement,
150 			@QueryParam(Constants.LOCATION) @Parameter(required = true) String location,
151 			@QueryParam(Constants.DEVICE) @Parameter(required = true) String device,
152 			@QueryParam(Constants.SYMBOLICNAME) @Parameter(required = true) String symbolicName,
153 			@QueryParam(Constants.FIELD) @Parameter(required = true) String field,
154 			@QueryParam(Constants.START) @Parameter(required = true) long start,
155 			@QueryParam(Constants.END) @Parameter(required = true) long end,
156 			@QueryParam(Constants.FUNCTION) SingleValuedUnaryFunction function,
157 			@QueryParam(Constants.GROUP_BY) Long groupBy, @QueryParam(Constants.FILLOPTION) FillOption fillOption)
158 			throws IOException {
159 
160 		if (measurement == null || location == null || device == null || symbolicName == null || field == null) {
161 			throw new InvalidRequestException("Some query params are missing");
162 		}
163 
164 		var timeseries = new Timeseries(measurement, device, location, symbolicName, field);
165 		var result = timeseriesContainerService.exportTimeseriesPayload(timeseriesContainerId, timeseries, start, end,
166 				function, groupBy, fillOption);
167 		return result != null
168 				? Response.ok(result, MediaType.APPLICATION_OCTET_STREAM)
169 						.header("Content-Disposition", "attachment; filename=\"timeseries-export.csv\"").build()
170 				: Response.status(Status.NOT_FOUND).build();
171 	}
172 
173 	@POST
174 	@Consumes(MediaType.MULTIPART_FORM_DATA)
175 	@Path("/{" + Constants.TIMESERIES_CONTAINER_ID + "}/" + Constants.IMPORT)
176 	@Subscribable
177 	@Override
178 	public Response importTimeseries(@PathParam(Constants.TIMESERIES_CONTAINER_ID) long timeseriesId,
179 			@FormDataParam(Constants.FILE) InputStream fileInputStream,
180 			@FormDataParam(Constants.FILE) FormDataContentDisposition fileMetaData) throws IOException {
181 		var result = timeseriesContainerService.importTimeseries(timeseriesId, fileInputStream);
182 
183 		return result ? Response.ok().build() : Response.status(Status.INTERNAL_SERVER_ERROR).build();
184 	}
185 
186 	@GET
187 	@Path("/{" + Constants.TIMESERIES_CONTAINER_ID + "}/" + Constants.PERMISSIONS)
188 	@Override
189 	public Response getTimeseriesPermissions(@PathParam(Constants.TIMESERIES_CONTAINER_ID) long timeseriesContainerId) {
190 		var perms = permissionsService.getPermissionsByNeo4jId(timeseriesContainerId);
191 		return perms != null ? Response.ok(new PermissionsIO(perms)).build()
192 				: Response.status(Status.NOT_FOUND).build();
193 	}
194 
195 	@PUT
196 	@Path("/{" + Constants.TIMESERIES_CONTAINER_ID + "}/" + Constants.PERMISSIONS)
197 	@Override
198 	public Response editTimeseriesPermissions(@PathParam(Constants.TIMESERIES_CONTAINER_ID) long timeseriesContainerId,
199 			@Valid PermissionsIO permissions) {
200 		var perms = permissionsService.updatePermissionsByNeo4jId(permissions, timeseriesContainerId);
201 		return perms != null ? Response.ok(new PermissionsIO(perms)).build()
202 				: Response.status(Status.NOT_FOUND).build();
203 	}
204 
205 	@GET
206 	@Path("/{" + Constants.TIMESERIES_CONTAINER_ID + "}/" + Constants.ROLES)
207 	@Override
208 	public Response getTimeseriesRoles(@PathParam(Constants.TIMESERIES_CONTAINER_ID) long timeseriesContainerId) {
209 		var roles = new PermissionsUtil().getRolesByNeo4jId(timeseriesContainerId,
210 				securityContext.getUserPrincipal().getName());
211 		return roles != null ? Response.ok(roles).build() : Response.status(Status.NOT_FOUND).build();
212 	}
213 }