SourceDescObservationServiceImpl.java

/*
 * Copyright 2021 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.gringlobal.service.impl;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import lombok.extern.slf4j.Slf4j;
import org.gringlobal.api.exception.InvalidApiUsageException;
import org.gringlobal.custom.elasticsearch.SearchException;
import org.gringlobal.model.SourceDescObservation;
import org.gringlobal.model.SourceDescriptor;
import org.gringlobal.model.SourceDescriptorCode;
import org.gringlobal.persistence.AccessionSourceRepository;
import org.gringlobal.persistence.SourceDescObservationRepository;
import org.gringlobal.service.SourceDescObservationService;
import org.gringlobal.service.SourceDescriptorCodeService;
import org.gringlobal.service.SourceDescriptorCodeTranslationService.TranslatedSourceDescriptorCode;
import org.gringlobal.service.SourceDescriptorService;
import org.gringlobal.service.SourceDescriptorTranslationService.TranslatedSourceDescriptor;
import org.gringlobal.service.filter.SourceDescObservationFilter;
import org.gringlobal.service.filter.SourceDescriptorCodeFilter;
import org.gringlobal.service.filter.SourceDescriptorFilter;
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.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional(readOnly = true)
@Slf4j
public class SourceDescObservationServiceImpl extends FilteredCRUDService2Impl<SourceDescObservation, SourceDescObservationFilter, SourceDescObservationRepository>
	implements SourceDescObservationService {

	@Autowired
	private SourceDescriptorService sourceDescriptorService;

	@Autowired
	private SourceDescriptorCodeService sourceDescriptorCodeService;
	
	@Autowired
	private AccessionSourceRepository accessionSourceRepository;

	@Override
	@Transactional
	@PostAuthorize("@ggceSec.actionAllowed('PassportData', 'WRITE', returnObject.accessionSource.accession.site)")
	public SourceDescObservation create(SourceDescObservation source) {
		source.setSourceDescriptor(sourceDescriptorService.get(source.getSourceDescriptor().getId()));
		if (source.getSourceDescriptorCode() != null) {
			source.setSourceDescriptorCode(sourceDescriptorCodeService.get(source.getSourceDescriptorCode().getId()));
		}

		SourceDescObservation target = new SourceDescObservation();
		target.apply(source);

		SourceDescObservation saved = repository.save(target);
		saved.lazyLoad();

		var accessionSource = accessionSourceRepository.getReferenceById(saved.getAccessionSource().getId());
		accessionSource.getAccession().lazyLoad();
		saved.setAccessionSource(accessionSource);

		return saved;
	}

	@Override
	@Transactional
	@PreAuthorize("@ggceSec.actionAllowed('PassportData', 'WRITE', #target.accessionSource.accession.site)")
	public SourceDescObservation update(SourceDescObservation updated, SourceDescObservation target) {
		if (updated == null) {
			throw new InvalidApiUsageException("SourceDescObservation must be provided.");
		}
		updated.setSourceDescriptor(sourceDescriptorService.get(updated.getSourceDescriptor().getId()));
		if (updated.getSourceDescriptorCode() != null) {
			updated.setSourceDescriptorCode(sourceDescriptorCodeService.get(updated.getSourceDescriptorCode().getId()));
		}

		log.debug("Update SourceDescObservation. Input data {}", updated);
		target.apply(updated);

		SourceDescObservation saved = repository.save(target);
		return _lazyLoad(saved);
	}

	@Override
	@Transactional
	@PreAuthorize("@ggceSec.actionAllowed('PassportData', 'WRITE', #target.accessionSource.accession.site)")
	public SourceDescObservation updateFast(SourceDescObservation updated, SourceDescObservation target) {
		target.apply(updated);
		return repository.save(target);
	}

	@Override
	@Transactional(readOnly = true)
	public Page<SourceDescObservation> list(Class<SourceDescObservation> clazz, SourceDescObservationFilter filter, Pageable page, String... boostFields) throws SearchException {
		Page<SourceDescObservation> sourceDescObservations = super.list(clazz, filter, page, boostFields);
		sourceDescObservations.getContent().forEach(SourceDescObservation::lazyLoad);
		return sourceDescObservations;
	}

	@Override
	public TranslatedSourceDescObservation getTranslated(long id) {
		SourceDescObservation loadedObservation = super.load(id);

		TranslatedSourceDescObservation translated = new TranslatedSourceDescObservation();
		translated.observation = loadedObservation;

		SourceDescriptor loadedSourceDescriptor = loadedObservation.getSourceDescriptor();
		if (loadedSourceDescriptor != null) {
			translated.translatedSourceDescriptor = sourceDescriptorService.loadTranslated(loadedSourceDescriptor.getId());
		}

		SourceDescriptorCode loadedSourceDescriptorCode = loadedObservation.getSourceDescriptorCode();
		if (loadedSourceDescriptorCode != null) {
			translated.translatedSourceDescriptorCode = sourceDescriptorCodeService.loadTranslated(loadedSourceDescriptorCode.getId());
		}

		return translated;
	}

	@Override
	@Transactional(readOnly = true)
	public Page<TranslatedSourceDescObservation> listTranslated(SourceDescObservationFilter filter, Pageable page) throws SearchException {
		Page<SourceDescObservation> loadedSourceDescObservationPage = super.list(filter, page);

		// fetch translated source descriptors by ids from observations

		SourceDescriptorFilter sourceDescriptorFilter = new SourceDescriptorFilter();
		sourceDescriptorFilter.id = loadedSourceDescObservationPage.stream()
			.map(SourceDescObservation::getSourceDescriptor)
			.map(SourceDescriptor::getId)
			.collect(Collectors.toSet());

		List<TranslatedSourceDescriptor> translatedSourceDescriptors = sourceDescriptorService.listFiltered(sourceDescriptorFilter, PageRequest.of(0, loadedSourceDescObservationPage.getSize())).getContent();

		// fetch translated source descriptor codes by ids from observations

		SourceDescriptorCodeFilter sourceDescriptorCodeFilter = new SourceDescriptorCodeFilter();
		sourceDescriptorCodeFilter.id = loadedSourceDescObservationPage.stream()
			.map(SourceDescObservation::getSourceDescriptorCode)
			.filter(Objects::nonNull)
			.map(SourceDescriptorCode::getId)
			.collect(Collectors.toSet());

		List<TranslatedSourceDescriptorCode> translatedSourceDescriptorCodes = sourceDescriptorCodeService.listFiltered(sourceDescriptorCodeFilter, PageRequest.of(0, loadedSourceDescObservationPage.getSize())).getContent();

		Page<TranslatedSourceDescObservation> translatedSourceDescObservations = loadedSourceDescObservationPage.map(observation -> covert(observation, translatedSourceDescriptors, translatedSourceDescriptorCodes));

		return translatedSourceDescObservations;
	}

	private TranslatedSourceDescObservation covert(SourceDescObservation observation, List<TranslatedSourceDescriptor> translatedDescriptors, List<TranslatedSourceDescriptorCode> translatedCodes) {
		TranslatedSourceDescObservation translatedObservation = new TranslatedSourceDescObservation();
		translatedObservation.observation = observation;

		var translatedDescriptor = translatedDescriptors.stream()
			.filter(translatedSourceDescriptor -> Objects.equals(translatedSourceDescriptor.entity.getId(), observation.getSourceDescriptor().getId()))
			.findFirst().orElse(null);

		translatedObservation.translatedSourceDescriptor = translatedDescriptor;

		if (Objects.nonNull(observation.getSourceDescriptorCode())) {
			translatedObservation.translatedSourceDescriptorCode = translatedCodes.stream()
				.filter(translatedCode -> Objects.equals(translatedCode.entity.getId(), observation.getSourceDescriptorCode().getId()))
				.findFirst().orElse(null);
		}

		return translatedObservation;
	}

}