PartnerServiceImpl.java
/*
* Copyright 2018 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.service.impl;
import static org.genesys.server.model.QPartner.partner;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.genesys.blocks.security.service.CustomAclService;
import org.genesys.server.component.security.SecurityUtils;
import org.genesys.server.exception.NotFoundElement;
import org.genesys.server.exception.SearchException;
import org.genesys.server.model.Partner;
import org.genesys.server.model.UserRole;
import org.genesys.server.model.dataset.Dataset;
import org.genesys.server.model.filters.DatasetFilter;
import org.genesys.server.model.filters.DescriptorListFilter;
import org.genesys.server.model.filters.PartnerFilter;
import org.genesys.server.model.impl.FaoInstitute;
import org.genesys.server.model.impl.QFaoInstitute;
import org.genesys.server.model.impl.Subset;
import org.genesys.server.model.traits.DescriptorList;
import org.genesys.server.persistence.FaoInstituteRepository;
import org.genesys.server.persistence.PartnerRepository;
import org.genesys.server.service.DatasetService;
import org.genesys.server.service.DescriptorListService;
import org.genesys.server.service.PartnerService;
import org.genesys.server.service.SubsetService;
import org.genesys.server.service.filter.InstituteFilter;
import org.genesys.server.service.filter.SubsetFilter;
import org.genesys.util.JPAUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.orm.ObjectOptimisticLockingFailureException;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.acls.domain.BasePermission;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import com.querydsl.core.types.Predicate;
/**
* {@inheritDoc}.
*/
@Slf4j
@Service
@Transactional(readOnly = true)
@Validated
public class PartnerServiceImpl extends FilteredCRUDService2Impl<Partner, PartnerFilter, PartnerRepository> implements PartnerService, InitializingBean {
@Autowired
private SubsetService subsetService;
@Autowired
private DatasetService datasetService;
@Autowired
private DescriptorListService descriptorListService;
@Autowired
private FaoInstituteRepository instituteRepository;
@Autowired
private SecurityUtils securityUtils;
@Autowired
private CustomAclService aclService;
@Value("${partner.primary.uuid}")
private UUID primaryPartnerUuid;
@Override
@Transactional
public void afterPropertiesSet() throws Exception {
try {
getPrimaryPartner();
} catch (NotFoundElement e) {
var primaryPartner = new Partner();
primaryPartner.setUuid(primaryPartnerUuid);
primaryPartner.setName("Genesys");
primaryPartner.setShortName("genesys");
primaryPartner = create(primaryPartner);
}
}
@Override
public Partner get(UUID uuid) {
return repository.findByUuid(uuid).orElseThrow(() -> new NotFoundElement("No record with uuid=" + uuid));
}
@Override
public Partner load(UUID uuid) {
return _lazyLoad(get(uuid));
}
@Override
public Partner getPrimaryPartner() {
return get(primaryPartnerUuid);
}
@Override
public List<Partner> autocompletePartners(final String term, final int limit) {
if (!StringUtils.isBlank(term) && term.length() >= 1) {
log.debug("Autocomplete partners for={}", term);
Predicate predicate = partner.name.startsWithIgnoreCase(term).or(partner.shortName.startsWithIgnoreCase(term).or(partner.name.containsIgnoreCase(term)));
return repository.findAll(predicate, PageRequest.of(0, Math.min(100, limit), Sort.by("name"))).getContent();
} else {
return Collections.emptyList();
}
}
/**
* {@inheritDoc}
*/
@Transactional
@Override
@PreAuthorize("hasRole('ADMINISTRATOR')")
public Partner create(final Partner input) {
log.debug("Creating partner: {} - {}", input.getShortName(), input.getName());
final Partner partner = new Partner();
partner.setUuid(input.getUuid());
partner.apply(input);
final Partner saved = repository.save(partner);
// Ensure ACL SID entry for the partner shortName
aclService.ensureAuthoritySid(saved.getAuthorityName());
return _lazyLoad(saved);
}
/**
* {@inheritDoc}
*/
@Override
@Transactional
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#target, 'write')")
public Partner update(Partner updated, Partner target) {
return _lazyLoad(updateFast(updated, target));
}
@Override
@Transactional
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#target, 'write')")
public Partner updateFast(Partner updated, Partner target) {
target.apply(updated);
return repository.save(target);
}
/**
* {@inheritDoc}
*/
@Override
public Page<Partner> listPartnersForCurrentUser(final PartnerFilter filter, final Pageable page) {
if (securityUtils.hasRole(UserRole.ADMINISTRATOR)) {
Pageable markdownSortPageRequest = JPAUtils.toMarkdownSort(page, "name");
Page<Partner> res = repository.findAll(filter.buildPredicate(), markdownSortPageRequest);
return new PageImpl<>(res.getContent(), page, res.getTotalElements());
} else {
final HashSet<Long> ids = new HashSet<>(securityUtils.listObjectIdentityIdsForCurrentUser(Partner.class, BasePermission.WRITE));
Pageable markdownSortPageRequest = JPAUtils.toMarkdownSort(page, "name");
Page<Partner> res = repository.findAll(partner.id.in(ids).and(filter.buildPredicate()), markdownSortPageRequest);
return new PageImpl<>(res.getContent(), page, res.getTotalElements());
}
}
/**
* {@inheritDoc}
*/
@Override
public List<Partner> listAllPartnersForCurrentUser() {
if (securityUtils.hasRole(UserRole.ADMINISTRATOR)) {
return repository.findAll();
} else {
final HashSet<Long> ids = new HashSet<>(securityUtils.listObjectIdentityIdsForCurrentUser(Partner.class, BasePermission.WRITE));
return Lists.newArrayList(repository.findAll(partner.id.in(ids)));
}
}
/**
* {@inheritDoc}
*/
@Override
public Page<Partner> list(final PartnerFilter partnerFilter, final Pageable page) throws SearchException {
Pageable markdownSortPageRequest = JPAUtils.toMarkdownSort(page, "name");
Page<Partner> res = super.list(partnerFilter, markdownSortPageRequest);
return new PageImpl<>(res.getContent(), page, res.getTotalElements());
}
@Override
@Transactional
@PreAuthorize("hasRole('ADMINISTRATOR')")
public Partner addInstitutes(Partner partner, Set<String> instituteCodes) {
final Partner savedPartner = get(partner.getUuid());
List<FaoInstitute> institutes = instituteRepository.findAllByCodes(instituteCodes);
institutes.forEach((inst) -> inst.setOwner(savedPartner));
institutes.forEach((institute -> aclService.createOrUpdatePermissions(institute)));
savedPartner.getInstitutes().addAll(institutes);
return _lazyLoad(repository.save(savedPartner));
}
@Override
@Transactional
@PreAuthorize("hasRole('ADMINISTRATOR')")
public Partner removeInstitutes(Partner partner, Set<String> instituteCodes) {
partner = get(partner.getUuid());
List<FaoInstitute> institutesToRemove = instituteRepository.findAllByCodes(instituteCodes);
institutesToRemove.forEach((institute -> institute.setOwner(null)));
institutesToRemove.forEach((institute -> aclService.createOrUpdatePermissions(institute)));
instituteRepository.saveAll(institutesToRemove);
partner.getInstitutes().removeAll(institutesToRemove);
return _lazyLoad(repository.save(partner));
}
@Override
public PartnerDetails loadPartnerDetails(UUID uuid) {
Partner partner = load(uuid);
PageRequest pageRequest = PageRequest.of(0, 10, Sort.by(Sort.Direction.DESC, "lastModifiedDate"));
SubsetFilter subsetFilter = new SubsetFilter();
subsetFilter.owner().uuid(Set.of(partner.getUuid()));
List<Subset> recentSubsets = null;
try {
recentSubsets = subsetService.list(subsetFilter, pageRequest).getContent();
} catch (SearchException e) {
log.error("Error occurred during search", e);
}
DatasetFilter datasetFilter = new DatasetFilter();
datasetFilter.owner().uuid(Set.of(partner.getUuid()));
List<Dataset> recentDatasets = null;
try {
recentDatasets = datasetService.list(datasetFilter, pageRequest).getContent();
} catch (SearchException e) {
log.error("Error occurred during search", e);
}
DescriptorListFilter descriptorListFilter = new DescriptorListFilter();
descriptorListFilter.owner().uuid(Set.of(partner.getUuid()));
List<DescriptorList> recentDescriptorLists = null;
try {
recentDescriptorLists = descriptorListService.list(descriptorListFilter, pageRequest).getContent();
} catch (SearchException e) {
log.error("Error occurred during search", e);
}
return PartnerDetails.from(partner, recentSubsets, recentDatasets, recentDescriptorLists);
}
@Override
public Page<FaoInstitute> loadPartnerInstitutes(UUID uuid, InstituteFilter filter, Pageable page) {
return instituteRepository.findAll(QFaoInstitute.faoInstitute.owner().uuid.eq(uuid).and(filter.buildPredicate()), page);
}
@Override
public Set<FaoInstitute> loadInstitutes(Set<UUID> partnersUUIDs) {
return repository.findInstitutesInPartners(partnersUUIDs);
}
/**
* {@inheritDoc}
*/
@Override
public Partner loadPartner(final UUID uuid, final int version) {
return _lazyLoad(repository.findByUuidAndVersion(uuid, version).orElseThrow(() -> new ObjectOptimisticLockingFailureException(Partner.class, uuid)));
}
/**
* {@inheritDoc}
*/
@Transactional
@Override
@PreAuthorize("hasRole('ADMINISTRATOR')")
public Partner remove(final Partner partner) {
Partner removedPartner = super.remove(partner);
aclService.removeAuthoritySid(partner.getAuthorityName());
return removedPartner;
}
@Override
public long countPartners(PartnerFilter filter) {
return repository.count(filter.buildPredicate());
}
}