package com.griddynamics.jagger.jaas.rest;
import com.griddynamics.jagger.dbapi.dto.DecisionPerSessionDto;
import com.griddynamics.jagger.engine.e1.services.DataService;
import com.griddynamics.jagger.engine.e1.services.data.service.MetricEntity;
import com.griddynamics.jagger.engine.e1.services.data.service.MetricPlotPointEntity;
import com.griddynamics.jagger.engine.e1.services.data.service.MetricSummaryValueEntity;
import com.griddynamics.jagger.engine.e1.services.data.service.SessionEntity;
import com.griddynamics.jagger.engine.e1.services.data.service.TestEntity;
import com.griddynamics.jagger.jaas.service.DynamicDataService;
import com.griddynamics.jagger.jaas.storage.model.DbConfigEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
/**
* JaaS REST API controller based on Spring MVC which exposes db backed resources.
*/
@RequestMapping(value = "/dbs")
@RestController
@ConditionalOnProperty(name = "jaas.hide.db.access.via.api", havingValue = "false")
public class DynamicDataServiceRestController extends AbstractController {
private static final Logger LOGGER = LoggerFactory.getLogger(DynamicDataServiceRestController.class);
private final DynamicDataService dynamicDataService;
@Autowired
public DynamicDataServiceRestController(DynamicDataService dynamicDataService) {
this.dynamicDataService = dynamicDataService;
}
private DataService getDataService(Long id) {
return dynamicDataService.getDataServiceFor(id);
}
private <R> ResponseEntity<R> produceDsResponse(Long dbId, Function<DataService, R> responseFunction) {
ResponseEntity<R> responseEntity = HttpGetResponseProducer.produce(getDataService(dbId), responseFunction);
LOGGER.debug("Produced response: {}", responseEntity);
return responseEntity;
}
@GetMapping(value = "", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<DbConfigEntity>> getDbConfigs() {
return produceGetResponse(dynamicDataService, t -> dynamicDataService.readAll());
}
@PostMapping(value = "", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> createDbConfig(@RequestBody DbConfigEntity config) {
dynamicDataService.create(config);
return ResponseEntity.created(
ServletUriComponentsBuilder.fromCurrentRequest().path("/{dbId}").buildAndExpand(config.getId()).toUri())
.build();
}
@PutMapping(value = "/{dbId}", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> updateDbConfig(@PathVariable Long dbId, @RequestBody DbConfigEntity config) {
config.setId(dbId);
dynamicDataService.update(config);
return ResponseEntity.accepted().build();
}
@GetMapping(value = "/{dbId}", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<DbConfigEntity> getDbConfig(@PathVariable Long dbId) {
return produceGetResponse(dynamicDataService, t -> dynamicDataService.read(dbId));
}
@DeleteMapping("/{dbId}")
public ResponseEntity<?> deleteDbConfig(@PathVariable Long dbId) {
DbConfigEntity config = new DbConfigEntity();
config.setId(dbId);
dynamicDataService.delete(config);
return ResponseEntity.noContent().build();
}
@GetMapping(value = "/{dbId}/sessions", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Set<SessionEntity>> getSessions(@PathVariable Long dbId, @RequestParam(name = "id",
required = false) String[] sessionIds
) {
final String[] finalSessionIds = Optional.ofNullable(sessionIds).orElse(new String[0]);
return produceDsResponse(dbId, dataService -> dataService.getSessions(Arrays.asList(finalSessionIds)));
}
@GetMapping(value = "/{dbId}/sessions/{sessionId}", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<SessionEntity> getSession(@PathVariable Long dbId, @PathVariable String sessionId) {
return produceDsResponse(dbId, dataService -> dataService.getSession(sessionId));
}
@GetMapping(value = "/{dbId}/sessions/{sessionId}/decision", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<DecisionPerSessionDto> getSessionDecision(@PathVariable Long dbId, @PathVariable String sessionId) {
return produceDsResponse(dbId, dataService -> dataService.getSessionDecisions(sessionId));
}
@GetMapping(value = "/{dbId}/sessions/{sessionId}/tests/{testName:.+}",
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<TestEntity> getTest(@PathVariable Long dbId, @PathVariable String sessionId,
@PathVariable String testName
) {
return produceDsResponse(dbId, dataService -> getTestByName(dataService, sessionId, testName));
}
private TestEntity getTestByName(DataService dataService, String sessionId, String testName) {
return dataService.getTestByName(sessionId, testName);
}
@GetMapping(value = "/{dbId}/sessions/{sessionId}/tests", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Set<TestEntity>> getTests(@PathVariable Long dbId, @PathVariable String sessionId) {
return produceDsResponse(dbId, dataService -> dataService.getTests(sessionId));
}
@GetMapping(value = "/{dbId}/tests/{testId}/metrics", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Set<MetricEntity>> getMetrics(@PathVariable Long dbId, @PathVariable Long testId) {
return produceDsResponse(dbId, dataService -> dataService.getMetrics(testId));
}
@GetMapping(value = "/{dbId}/sessions/{sessionId}/tests/{testName:.+}/metrics",
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Set<MetricEntity>> getMetrics(@PathVariable Long dbId, @PathVariable String sessionId,
@PathVariable String testName
) {
return produceDsResponse(dbId, dataService -> getMetrics(dataService, sessionId, testName));
}
private Set<MetricEntity> getMetrics(DataService dataService, String sessionId, String testName) {
return Optional.ofNullable(getTestByName(dataService, sessionId, testName)).map(dataService::getMetrics)
.orElse(Collections.emptySet());
}
@GetMapping(value = "/{dbId}/sessions/{sessionId}/tests/{testName:.+}/metrics/summary",
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Map<MetricEntity, MetricSummaryValueEntity>> getMetricsSummary(@PathVariable Long dbId,
@PathVariable String sessionId,
@PathVariable String testName
) {
return produceDsResponse(dbId, dataService -> dataService
.getMetricSummary(getMetrics(dataService, sessionId, testName)));
}
@GetMapping(value = "/{dbId}/sessions/{sessionId}/tests/{testName:.+}/metrics/plot-data",
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Map<MetricEntity, List<MetricPlotPointEntity>>> getMetricPlotData(@PathVariable Long dbId,
@PathVariable String sessionId,
@PathVariable String testName
) {
return produceDsResponse(dbId, dataService -> dataService
.getMetricPlotData(getMetrics(dataService, sessionId, testName)));
}
}