DescriptorApiServiceImpl.java
/*
* Copyright 2024 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.collections4.CollectionUtils;
import org.genesys.filerepository.InvalidRepositoryFileDataException;
import org.genesys.filerepository.InvalidRepositoryPathException;
import org.genesys.filerepository.NoSuchRepositoryFileException;
import org.genesys.filerepository.model.RepositoryImage;
import org.genesys.server.api.v2.facade.DescriptorApiService;
import org.genesys.server.api.v2.model.dataset.DatasetInfo;
import org.genesys.server.api.v2.model.impl.DescriptorDTO;
import org.genesys.server.api.v2.model.impl.DescriptorLangDTO;
import org.genesys.server.api.v2.model.impl.DescriptorListInfo;
import org.genesys.server.api.v2.model.impl.TranslatedDescriptorDTO;
import org.genesys.server.exception.InvalidApiUsageException;
import org.genesys.server.exception.NotFoundElement;
import org.genesys.server.exception.SearchException;
import org.genesys.server.model.filters.DescriptorFilter;
import org.genesys.server.model.traits.Descriptor;
import org.genesys.server.model.traits.DescriptorLang;
import org.genesys.server.service.DescriptorService;
import org.genesys.server.service.DescriptorTranslationService;
import org.genesys.server.service.TranslatorService;
import org.genesys.server.service.VocabularyTermService;
import org.genesys.server.service.TranslatorService.TranslatorException;
import org.genesys.server.service.worker.dupe.DescriptorDuplicateFinder;
import org.genesys.server.service.worker.dupe.DuplicateFinder;
import org.hibernate.validator.internal.util.stereotypes.Lazy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.OutputStream;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;
@Service("descriptorV2APIService")
@Validated
public class DescriptorApiServiceImpl extends APIFilteredTranslatedServiceFacadeImpl<DescriptorService, DescriptorDTO,
TranslatedDescriptorDTO, DescriptorLangDTO, Descriptor, DescriptorLang,
DescriptorTranslationService.TranslatedDescriptor, DescriptorFilter> implements DescriptorApiService {
@Autowired
private DescriptorDuplicateFinder duplicateFinder;
@Autowired
@Lazy
private VocabularyTermService vocabularyTermSerice;
@Override
protected TranslatedDescriptorDTO convertTranslation(DescriptorTranslationService.TranslatedDescriptor source) {
return mapper.map(source);
}
@Override
protected DescriptorLang convertLang(DescriptorLangDTO source) {
return mapper.map(source);
}
@Override
protected DescriptorLangDTO convertLang(DescriptorLang source) {
return mapper.map(source);
}
@Override
protected Descriptor convert(DescriptorDTO source) {
return mapper.map(source);
}
@Override
protected DescriptorDTO convert(Descriptor source) {
return mapper.map(source);
}
@Override
@Transactional(readOnly = true)
public List<DescriptorDTO> searchMatchingDescriptor(DescriptorDTO descriptor) {
return mapper.map(service.searchMatchingDescriptor(mapper.map(descriptor)), mapper::map);
}
@Override
@Transactional
public DescriptorDTO updateImage(DescriptorDTO descriptor, MultipartFile file, RepositoryImage imageMetadata) throws IOException, InvalidRepositoryPathException, InvalidRepositoryFileDataException, NoSuchRepositoryFileException {
return mapper.map(service.updateImage(mapper.map(descriptor), file, imageMetadata));
}
@Override
@Transactional
public DescriptorDTO removeImage(DescriptorDTO descriptor) throws NoSuchRepositoryFileException, IOException, InvalidRepositoryPathException {
return mapper.map(service.removeImage(mapper.map(descriptor)));
}
@Override
@Transactional
public DescriptorDTO forceUpdateDescriptor(DescriptorDTO descriptor) {
return mapper.map(service.forceUpdateDescriptor(mapper.map(descriptor)));
}
@Override
@Transactional(readOnly = true)
public DescriptorDTO loadDescriptor(UUID uuid) throws NotFoundElement {
return mapper.map(service.loadDescriptor(uuid));
}
@Override
@Transactional(readOnly = true)
public TranslatedDescriptorDTO loadTranslatedDescriptor(UUID uuid) throws NotFoundElement {
return mapper.map(service.loadTranslatedDescriptor(uuid));
}
@Override
@Transactional(readOnly = true)
public DescriptorDTO loadDescriptor(UUID uuid, int version) throws NotFoundElement {
return mapper.map(service.loadDescriptor(uuid, version));
}
@Override
@Transactional(readOnly = true)
public Page<DescriptorDTO> listDescriptorsForCurrentUser(DescriptorFilter filter, Pageable page) throws IOException, SearchException {
return mapper.map(service.listDescriptorsForCurrentUser(filter, page), mapper::map);
}
@Override
@Transactional(readOnly = true)
public Page<DescriptorDTO> listAccessibleDescriptors(DescriptorFilter filter, Pageable page) throws IOException, SearchException {
return mapper.map(service.listAccessibleDescriptors(filter, page), mapper::map);
}
@Override
@Transactional(readOnly = true)
public Page<DescriptorDTO> listDescriptors(DescriptorFilter descriptorFilter, Pageable page) throws SearchException {
return mapper.map(service.listDescriptors(descriptorFilter, page), mapper::map);
}
@Override
@Transactional(readOnly = true)
public Page<TranslatedDescriptorDTO> listDescriptorsDetails(DescriptorFilter filter, Pageable page) throws SearchException {
return mapper.map(service.listDescriptorsDetails(filter, page), mapper::map);
}
@Override
@Transactional
public DescriptorDTO removeDescriptor(DescriptorDTO descriptor) throws InvalidRepositoryPathException, IOException {
return mapper.map(service.rejectDescriptor(mapper.map(descriptor)));
}
@Override
@Transactional
public List<DescriptorDTO> upsertDescriptors(List<DescriptorDTO> source) {
return mapper.map(service.upsertDescriptors(mapper.map(source, mapper::map)), mapper::map);
}
@Override
@Transactional
public DescriptorDTO upsertDescriptor(DescriptorDTO source) {
return mapper.map(service.upsertDescriptor(mapper.map(source)));
}
@Override
@Transactional
public DescriptorDTO approveDescriptor(DescriptorDTO descriptor) {
return mapper.map(service.approveDescriptor(mapper.map(descriptor)));
}
@Override
@Transactional
public DescriptorDTO reviewDescriptor(DescriptorDTO descriptor) {
return mapper.map(service.reviewDescriptor(mapper.map(descriptor)));
}
@Override
@Transactional
public DescriptorDTO rejectDescriptor(DescriptorDTO descriptor) {
return mapper.map(service.rejectDescriptor(mapper.map(descriptor)));
}
@Override
@Transactional(readOnly = true)
public List<DescriptorListInfo> getDescriptorLists(UUID uuid) {
return mapper.map(service.getDescriptorLists(service.getDescriptor(uuid)), mapper::mapInfo);
}
@Override
@Transactional(readOnly = true)
public List<DatasetInfo> getDatasets(UUID uuid) {
return mapper.map(service.getDatasets(service.getDescriptor(uuid)), mapper::mapInfo);
}
@Override
@Transactional
public DescriptorDTO nextVersion(DescriptorDTO descriptor, boolean major) {
return mapper.map(service.nextVersion(mapper.map(descriptor), major));
}
@Override
public void exportDescriptors(DescriptorFilter filter, OutputStream outputStream) throws IOException {
service.exportDescriptors(filter, outputStream);
}
@Override
@Transactional(readOnly = true)
public long countDescriptors(DescriptorFilter filter) throws SearchException {
return service.countDescriptors(filter);
}
@Override
@Transactional(readOnly = true)
public DescriptorDTO getDescriptor(UUID uuid) {
return mapper.map(service.getDescriptor(uuid));
}
@Override
public DescriptorLangDTO machineTranslate(long entityId, String targetLanguage) throws TranslatorException {
var descriptor = service.get(entityId);
var dto = mapper.map(service.machineTranslate(descriptor, targetLanguage));
dto.setTerms(mapper.map(service.machineTranslateTerms(descriptor, targetLanguage), mapper::map));
return dto;
}
@Override
@Transactional(readOnly = true)
public DescriptorLangDTO machineTranslate(UUID uuid, String targetLanguage) throws TranslatorService.TranslatorException {
var descriptor = service.getDescriptor(uuid);
var dto = mapper.map(service.machineTranslate(descriptor, targetLanguage));
dto.setTerms(mapper.map(service.machineTranslateTerms(descriptor, targetLanguage), mapper::map));
return dto;
}
@Override
public DescriptorLangDTO upsertTranslation(DescriptorDTO entity, DescriptorLangDTO input) {
var dto = super.upsertTranslation(entity, input);
if (CollectionUtils.isNotEmpty(input.getTerms())) {
var descriptor = service.get(dto.getEntityId());
if (CollectionUtils.isEmpty(descriptor.getTerms())) {
throw new InvalidApiUsageException("Descriptor does not have terms!");
}
dto.setTerms(new LinkedList<>());
for (var dt : descriptor.getTerms()) {
var it = input.getTerms().stream().filter(t -> Objects.equals(t.getEntityId(), dt.getId())).findFirst().orElse(null);
if (it != null) {
var tdt = vocabularyTermSerice.upsertTranslation(dt, mapper.map(it));
dto.getTerms().add(mapper.map(tdt));
}
}
}
return dto;
}
@Override
@Transactional(readOnly = true)
public List<DuplicateFinder.Hit<DescriptorDTO>> findSimilar(SimilarRequest similarRequest) {
DescriptorDTO target = similarRequest.select;
if (target.getUuid() != null) {
target = loadDescriptor(target.getUuid());
}
var result = duplicateFinder.findSimilar(mapper.map(target), similarRequest.target);
return result.stream().map(hit -> {
var dtoHit = new DuplicateFinder.Hit<>(mapper.map(hit.result), hit.score);
dtoHit.hitRating = hit.hitRating;
dtoHit.matches = hit.matches;
return dtoHit;
}).collect(Collectors.toList());
}
@Override
@Transactional(readOnly = true)
public DescriptorDetails getDescriptorDetails(UUID uuid) {
DescriptorDetails details = new DescriptorDetails();
details.descriptor = mapper.map(service.loadTranslatedDescriptor(uuid));
details.descriptorLists = getDescriptorLists(uuid);
details.datasets = getDatasets(uuid);
return details;
}
}