KPIApiServiceImpl.java
/*
* Copyright 2025 Global Crop Diversity Trust
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.genesys.server.api.v2.facade.impl;
import org.apache.commons.lang3.StringUtils;
import org.genesys.server.api.v2.facade.KPIApiService;
import org.genesys.server.api.v2.mapper.MapstructMapper;
import org.genesys.server.api.v2.model.kpi.DimensionDTO;
import org.genesys.server.api.v2.model.kpi.ExecutionDTO;
import org.genesys.server.api.v2.model.kpi.ExecutionInfo;
import org.genesys.server.api.v2.model.kpi.ExecutionRunDTO;
import org.genesys.server.api.v2.model.kpi.KPIParameterDTO;
import org.genesys.server.api.v2.model.kpi.ObservationDTO;
import org.genesys.server.exception.NotFoundElement;
import org.genesys.server.model.kpi.Execution;
import org.genesys.server.model.kpi.ExecutionRun;
import org.genesys.server.model.kpi.Observation;
import org.genesys.server.service.KPIService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.stream.Collectors;
@Service
@Transactional(readOnly = true)
public class KPIApiServiceImpl implements KPIApiService {
@Autowired
private MapstructMapper mapper;
@Autowired
private KPIService service;
@Override
@Transactional
public KPIParameterDTO save(KPIParameterDTO parameter) {
return mapper.map(service.save(mapper.map(parameter)));
}
@Override
@Transactional
public KPIParameterDTO deleteParameter(String name) {
return mapper.map(service.delete(service.getParameter(name)));
}
@Override
public Page<KPIParameterDTO> listParameters(Pageable page) {
return mapper.map(service.listParameters(page), mapper::map);
}
@Override
public DimensionDTO getDimension(String name) {
return mapper.map(service.getDimension(name));
}
@Override
@Transactional
public DimensionDTO save(DimensionDTO dimension) {
return mapper.map(service.save(mapper.map(dimension)));
}
@Override
@Transactional
public DimensionDTO deleteDimension(String name) {
return mapper.map(service.delete(service.getDimension(name)));
}
@Override
public Page<DimensionDTO> listDimensions(Pageable page) {
return mapper.map(service.listDimensions(page), mapper::map);
}
@Override
@Transactional
public ExecutionDTO save(ExecutionDTO execution) {
return mapper.map(service.save(mapper.map(execution)));
}
@Override
@Transactional
public ExecutionDTO deleteExecution(String name) {
return mapper.map(service.delete(service.getExecution(name)));
}
@Override
public Page<ExecutionDTO> listExecutions(Pageable page) {
return mapper.map(service.listExecutions(page), mapper::map);
}
@Override
@Transactional
public ExecutionRunDTO runExecution(String name) {
return mapper.map(service.executeAndSave(service.getExecution(name)));
}
@Override
@Transactional
public long purgeExecutionRuns(String name) {
long deleted = service.purgeExecutionRuns(service.getExecution(name));
System.err.println("Done deleting!");
return deleted;
}
@Override
public ExecutionDetailsDTO executionDetails(String name) {
Execution execution = service.loadExecution(name);
var details = KPIService.ExecutionDetails.from(execution, service.findLastExecutionRun(execution), service.listExecutionRuns(execution, PageRequest.of(0, 10)));
var detailsDTO = new ExecutionDetailsDTO();
detailsDTO.setExecution(mapper.map(execution));
detailsDTO.setLastRun(mapper.map(details.lastRun));
detailsDTO.setRuns(details.runs.map(mapper::map));
return detailsDTO;
}
@Override
public ExecutionInfo getExecution(String name) {
return mapper.mapInfo(service.getExecution(name));
}
@Override
public Page<ExecutionRunDTO> executionRuns(String name, Pageable page) {
return mapper.map(service.listExecutionRuns(service.getExecution(name), page), mapper::map);
}
@Override
public ExecutionRunDTO executionRunByDate(String name, LocalDate date) {
return mapper.map(service.findExecutionRunByDate(service.getExecution(name), date));
}
@Override
public ExecutionRunDTO executionRun(String name, long runId) {
ExecutionRun run = service.getExecutionRun(runId);
if (! StringUtils.equals(run.getExecution().getName(), name)) {
throw new NotFoundElement("No run " + runId + " for execution " + name);
}
return mapper.map(run);
}
@Override
@Transactional
public ExecutionRunDTO deleteExecutionRun(String name, long runId) {
var executionRun = service.getExecutionRun(runId);
if (! StringUtils.equals(executionRun.getExecution().getName(), name)) {
throw new NotFoundElement("No run " + runId + " for execution " + name);
}
return mapper.map(service.delete(executionRun));
}
@Override
public SortedMap<LocalDate, List<ObservationDTO>> executionRuns(String name, Integer days, LocalDate from, LocalDate to, Map<String, Set<String>> keys) {
Execution execution = service.getExecution(name);
if (execution == null) {
throw new NotFoundElement("No execution " + name);
}
if (days != null) {
LocalDate startDate = LocalDate.now();
if (to != null) {
startDate = to;
} else {
to = startDate;
}
startDate = startDate.minusDays(days);
from = startDate;
}
return mapExecutionObservations(service.calculateRunDiff(execution, from, to, keys));
}
@Override
public SortedMap<LocalDate, List<ObservationDTO>> executionRunsObservations(String name, ExecutionRunsRequestDTO runsRequest) {
Execution execution = service.getExecution(name);
if (execution == null) {
throw new NotFoundElement("No execution " + name);
}
return mapExecutionObservations(service.findExecutionRuns(execution, mapper.map(runsRequest)));
}
@Override
public List<GroupedRunObservationsDTO> getObservationsGroupedByDimension(String name, String dimensionName, LocalDate toDate, Integer maxRuns) {
Execution execution = service.getExecution(name);
if (execution == null) {
throw new NotFoundElement("No execution " + name);
}
return mapper.map(service.getObservationsGroupedByDimension(execution, dimensionName, toDate, maxRuns));
}
private SortedMap<LocalDate, List<ObservationDTO>> mapExecutionObservations(SortedMap<LocalDate, List<Observation>> sortedMap) {
return sortedMap.entrySet()
.stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
e -> mapper.map(e.getValue(), mapper::map),
(e1, e2) -> e1,
TreeMap::new
));
}
}