CropTraitServiceImpl.java

/*
 * Copyright 2020 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.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Set;

import lombok.extern.slf4j.Slf4j;
import org.gringlobal.api.exception.InvalidApiUsageException;
import org.gringlobal.api.v1.MultiOp;
import org.gringlobal.custom.elasticsearch.SearchException;
import org.gringlobal.model.Crop;
import org.gringlobal.model.CropTrait;
import org.gringlobal.model.CropTraitAttach;
import org.gringlobal.model.CropTraitLang;
import org.gringlobal.model.QCropTraitAttach;
import org.gringlobal.persistence.CropTraitLangRepository;
import org.gringlobal.persistence.CropTraitRepository;
import org.gringlobal.service.CropTraitAttachmentService;
import org.gringlobal.service.CropTraitAttachmentService.CropTraitAttachmentRequest;
import org.gringlobal.service.CropTraitCodeTranslationService;
import org.gringlobal.service.CropTraitCodeTranslationService.TranslatedCropTraitCode;
import org.gringlobal.service.CropTraitService;
import org.gringlobal.service.CropTraitTranslationService;
import org.gringlobal.service.CropTraitTranslationService.TranslatedCropTrait;
import org.gringlobal.service.filter.CropTraitCodeFilter;
import org.gringlobal.service.filter.CropTraitFilter;
import org.hibernate.Hibernate;
import org.springframework.beans.factory.annotation.Autowired;
// import org.springframework.cache.annotation.CacheConfig;
// import org.springframework.cache.annotation.CacheEvict;
// import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;


/**
 * The Class CropTraitServiceImpl.
 */
@Service
@Transactional(readOnly = true)
@Validated
// @CacheConfig(cacheNames = { "cropTraits" })
@Slf4j
public class CropTraitServiceImpl extends FilteredTranslatedCRUDServiceImpl<CropTrait, CropTraitLang, TranslatedCropTrait, CropTraitFilter, CropTraitRepository> implements CropTraitService {

	private static final String[] BOOST_FIELDS = { "langs.title", "langs.description" };
	
	@Autowired
	private CropTraitCodeTranslationService cropTraitCodeTranslationService;

	@Component(value = "cropTraitAttachmentSupport")
	@Transactional(readOnly = true)
	protected static class CropTraitAttachmentSupport extends BaseAttachmentSupport<CropTrait, CropTraitAttach, CropTraitAttachmentRequest> implements CropTraitAttachmentService {

		public CropTraitAttachmentSupport() {
			super(QCropTraitAttach.cropTraitAttach.cropTrait().id, QCropTraitAttach.cropTraitAttach.id);
		}

		@Override
		protected Path createRepositoryPath(CropTrait cropTrait) {
			cropTrait = owningEntityRepository.getReferenceById(cropTrait.getId());

			Hibernate.initialize(cropTrait.getCrop());
			Crop crop = cropTrait.getCrop();

			return Paths.get("/crop", crop.getName(), "trait", cropTrait.getId().toString());
		}

		@Override
		@PreAuthorize("hasAuthority('GROUP_ADMINS') or @ggceSec.actionAllowed('CropTrait', 'WRITE')")
		protected CropTraitAttach createAttach(CropTrait entity, CropTraitAttach source) {
			CropTraitAttach attach = new CropTraitAttach();
			attach.apply(source);
			attach.setVirtualPath(source.getVirtualPath()); // SOAP uses this to create the record
			attach.setCropTrait(entity);
			return attach;
		}

		@Override
		@PreAuthorize("hasAuthority('GROUP_ADMINS') or @ggceSec.actionAllowed('CropTrait', 'WRITE')")
		public CropTraitAttach create(CropTraitAttach source) {
			var owningEntity = owningEntityRepository.getReferenceById(source.getCropTrait().getId());

			var attach = createAttach(owningEntity, source);
			var savedAttach = repository.save(attach);
			return _lazyLoad(savedAttach);
		}

		@Override
		@PreAuthorize("hasAuthority('GROUP_ADMINS') or @ggceSec.actionAllowed('CropTrait', 'WRITE')")
		public CropTraitAttach update(CropTraitAttach updated, CropTraitAttach target) {
			target.apply(updated);
			return _lazyLoad(repository.save(target));
		}

		@Override
		@PreAuthorize("hasAuthority('GROUP_ADMINS') or @ggceSec.actionAllowed('CropTrait', 'WRITE')")
		public CropTraitAttach remove(CropTraitAttach entity) {
			return super.remove(entity);
		}
	}

	@Component(value = "cropTraitTranslationSupport")
	protected static class CropTraitTranslationSupport extends BaseTranslationSupport<CropTrait, CropTraitLang, TranslatedCropTrait, CropTraitFilter, CropTraitLangRepository> implements CropTraitTranslationService {

		@Autowired
		@Lazy
		private CropTraitCodeTranslationService cropTraitCodeTranslationService;

		public CropTraitTranslationSupport() {
			super();
		}

		@Override
		protected TranslatedCropTrait toTranslated(CropTrait entity, String title, String description) {
			return TranslatedCropTrait.from(entity, title, description, cropTraitCodeTranslationService.getTranslated(entity.getCodes()));
		}

		@Override
		public CropTraitLang update(CropTraitLang updated, CropTraitLang target) {
			target.setTitle(updated.getTitle());
			target.setDescription(updated.getDescription());
			return _lazyLoad(repository.save(target));
		}
	}

	@Override
	public Page<TranslatedCropTrait> listFiltered(CropTraitFilter filter, Pageable page) throws SearchException {
		return super.listFiltered(CropTrait.class, filter, page, BOOST_FIELDS);
	}

	@Override
	public TranslatedCropTrait loadTranslated(long id) {
		var translatedCropTrait = super.loadTranslated(id);

		// initialize lazy data
		if (translatedCropTrait.entity.getAttachments() != null) {
			translatedCropTrait.entity.getAttachments().size();
			translatedCropTrait.entity.getAttachments().forEach((cta) -> {
				Hibernate.initialize(cta.getRepositoryFile());
				if (cta.getAttachCooperator() != null) {
					cta.getAttachCooperator().getId();
				}
			});
		}
		translatedCropTrait.attachments = translatedCropTrait.entity.getAttachments();

		var traitCodeFilter = new CropTraitCodeFilter();
		traitCodeFilter.cropTrait().id(Set.of(id));

		List<TranslatedCropTraitCode> codes = cropTraitCodeTranslationService.list(traitCodeFilter, PageRequest.of(0, Integer.MAX_VALUE, Sort.by("title"))).getContent();

		translatedCropTrait.codes = codes;
		return translatedCropTrait;
	}

	@Override
	// @Cacheable(key = "'ct-' + #id", unless = "#result == null")
	public CropTrait get(long id) {
		return super.get(id);
	}

	@Override
	@Transactional
	@PreAuthorize("@ggceSec.actionAllowed('CropTrait', 'CREATE')")
	public CropTrait create(CropTrait source) {
		assert(source.getId() == null);
		var target = new CropTrait();
		target.apply(source);
		return _lazyLoad(repository.save(target));
	}

	@Override
	@Transactional
	@PreAuthorize("@ggceSec.actionAllowed('CropTrait', 'CREATE')")
	public CropTrait createFast(CropTrait source) {
		return repository.save(source);
	}
	
	@Override
	@Transactional
	@PreAuthorize("@ggceSec.actionAllowed('CropTrait', 'CREATE')")
	public TranslatedCropTrait create(TranslatedCropTrait source) {
		return super.create(source);
	}
	
	@Override
	@Transactional
	@PreAuthorize("@ggceSec.actionAllowed('CropTrait', 'CREATE')")
	public MultiOp<CropTrait> create(List<CropTrait> inserts) {
		return super.create(inserts);
	}
	
	@Override
	@Transactional
	@PreAuthorize("@ggceSec.actionAllowed('CropTrait', 'CREATE')")
	public MultiOp<CropTrait> createFast(List<CropTrait> inserts) {
		return super.createFast(inserts);
	}

	@Override
	@Transactional
	@PreAuthorize("@ggceSec.actionAllowed('CropTrait', 'WRITE')")
	// @CacheEvict(key = "'ct-' + #target.id")
	public CropTrait update(CropTrait input, CropTrait target) {
		if (input == null) {
			throw new InvalidApiUsageException("CropTrait must be provided.");
		}

		log.debug("Update CropTrait. Input data {}", input);
		target.apply(input);

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

	@Override
	@Transactional
	@PreAuthorize("@ggceSec.actionAllowed('CropTrait', 'WRITE')")
	// @CacheEvict(key = "'ct-' + #target.id")
	public CropTrait updateFast(CropTrait updated, CropTrait target) {
		target.apply(updated);
		return repository.save(target);
	}

	@Override
	@PreAuthorize("@ggceSec.actionAllowed('CropTrait', 'WRITE')")
	// @CacheEvict(allEntries = true)
	public MultiOp<CropTrait> update(List<CropTrait> updates) {
		return super.update(updates);
	}

	@Override
	@PreAuthorize("@ggceSec.actionAllowed('CropTrait', 'DELETE')")
	// @CacheEvict(key = "'ct-' + #entity.id")
	public CropTrait remove(CropTrait entity) {
		return super.remove(entity);
	}

	@Override
	@PreAuthorize("@ggceSec.actionAllowed('CropTrait', 'DELETE')")
	// @CacheEvict(allEntries = true)
	public MultiOp<CropTrait> remove(List<CropTrait> deletes) {
		return super.remove(deletes);
	}

}