PGRFANetworkServiceImpl.java
/**
* Copyright 2014 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 java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.genesys.server.exception.InvalidApiUsageException;
import org.genesys.server.exception.NotFoundElement;
import org.genesys.server.exception.SearchException;
import org.genesys.server.model.genesys.Accession;
import org.genesys.server.model.impl.FaoInstitute;
import org.genesys.server.model.impl.PGRFANetwork;
import org.genesys.server.model.impl.QFaoInstitute;
import org.genesys.server.persistence.FaoInstituteRepository;
import org.genesys.server.persistence.PGRFANetworkRepository;
import org.genesys.server.service.ArticleService;
import org.genesys.server.service.ArticleTranslationService;
import org.genesys.server.service.ContentService;
import org.genesys.server.service.ElasticsearchService;
import org.genesys.server.service.PGRFANetworkService;
import org.genesys.server.service.filter.AccessionFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.common.collect.Sets;
@Service
@Transactional(readOnly = true)
@Validated
public class PGRFANetworkServiceImpl implements PGRFANetworkService {
private static final String CACHE_ORGANIZATION_INSTITUTEORGS = "hibernate.org.genesys.server.model.impl.PGRFANetwork.instituteOrganizations";
public static final Logger LOG = LoggerFactory.getLogger(PGRFANetworkServiceImpl.class);
private final Set<String> terms = Sets.newHashSet("institute.code", "institute.country.code3", "cropName", "crop.shortName",
"taxonomy.genus", "taxonomy.species", "taxonomy.genusSpecies", "taxonomy.grinTaxonomySpecies.name", "taxonomy.currentTaxonomySpecies.name",
"countryOfOrigin.code3", "sampStat", "available", "mlsStatus", "donorCode", "sgsv", "storage", "duplSite", "breederCode", "aegis");
@Autowired
private FaoInstituteRepository instituteRepository;
@Autowired
private PGRFANetworkRepository networkRepository;
@Autowired
private ArticleService articleService;
@Autowired(required = false)
private ElasticsearchService elasticsearchService;
@Override
public PGRFANetwork getNetwork(String slug) {
return lazyLoad(networkRepository.findBySlug(slug));
}
@PreAuthorize("hasRole('ADMINISTRATOR')")
@Override
@Transactional
@CacheEvict(value = CACHE_ORGANIZATION_INSTITUTEORGS, allEntries = true)
public PGRFANetwork delete(PGRFANetwork network) {
network = networkRepository.findById(network.getId()).orElseThrow(() -> new NotFoundElement("Network not found"));
networkRepository.delete(network);
network.setId(null);
return network;
}
@Override
public Page<PGRFANetwork> list(Pageable pageable) {
return networkRepository.findAll(pageable);
}
@Override
public ArticleTranslationService.TranslatedArticle getBlurb(PGRFANetwork network, Locale locale) {
return articleService.getArticle(network, ContentService.ENTITY_BLURB_SLUG, locale);
}
@Override
@PreAuthorize("hasRole('ADMINISTRATOR')")
@Transactional(readOnly = false)
public PGRFANetwork update(long id, String newSlug, String title, String accessionFilter) {
final PGRFANetwork network = new PGRFANetwork();
network.setId(id);
network.setSlug(newSlug);
network.setTitle(title);
network.setAccessionFilter(accessionFilter);
return update(network);
}
@Override
@PreAuthorize("hasRole('ADMINISTRATOR')")
@Transactional(readOnly = false)
public PGRFANetwork update(PGRFANetwork network) {
final PGRFANetwork toUpdate = networkRepository.findBySlug(network.getSlug());
if (toUpdate == null)
throw new NotFoundElement("Network not found");
toUpdate.setSlug(network.getSlug());
toUpdate.setTitle(network.getTitle());
toUpdate.setAccessionFilter(network.getAccessionFilter());
return lazyLoad(networkRepository.save(toUpdate));
}
@Override
@PreAuthorize("hasRole('ADMINISTRATOR')")
@Transactional(readOnly = false)
public PGRFANetwork create(String slug, String title) {
final PGRFANetwork network = new PGRFANetwork();
network.setSlug(slug);
network.setTitle(title);
return create(network);
}
@Override
@PreAuthorize("hasRole('ADMINISTRATOR')")
@Transactional(readOnly = false)
public PGRFANetwork create(PGRFANetwork network) {
final PGRFANetwork toCreate = new PGRFANetwork();
toCreate.setSlug(network.getSlug());
toCreate.setTitle(network.getTitle());
return networkRepository.save(toCreate);
}
@Override
public Map<String, ElasticsearchService.TermResult> overview(String slug) throws SearchException {
var network = networkRepository.findBySlug(slug);
var accessionFilter = new AccessionFilter();
if (StringUtils.isNotBlank(network.getAccessionFilter())) {
try {
accessionFilter = AccessionFilter.fromJson(network.getAccessionFilter());
} catch (JsonProcessingException e) {
LOG.error("Exception in parsing JSON filter: {}", network.getAccessionFilter()); //, e);
}
}
accessionFilter
.historic(false) // Force active accessions
.networks(Sets.newHashSet(slug));
if (elasticsearchService != null) {
return elasticsearchService.termStatisticsAuto(Accession.class, accessionFilter, 10, terms.toArray(new String[] {}));
}
return Map.of();
}
@Override
public List<FaoInstitute> getInstitutes(PGRFANetwork network) {
if (network == null) {
throw new InvalidApiUsageException("Network cannot be null");
}
return networkRepository.findInstitutesByNetwork(network);
}
@Override
public Page<FaoInstitute> getInstitutes(PGRFANetwork network, Pageable pageable) {
return instituteRepository.findAll(QFaoInstitute.faoInstitute.in(network.getMembers()), pageable);
}
@Override
public Set<FaoInstitute> getMembers(Set<String> networkSlugs) {
return networkRepository.findInstitutesInNetworks(networkSlugs);
}
@Override
@Transactional
@PreAuthorize("hasRole('ADMINISTRATOR')")
@CacheEvict(value = CACHE_ORGANIZATION_INSTITUTEORGS, allEntries = true)
public PGRFANetwork setInstitutes(PGRFANetwork org, List<String> instituteList) {
LOG.info("Setting institutes for network {}", org);
final PGRFANetwork network = networkRepository.findById(org.getId()).orElseThrow(() -> new NotFoundElement("Network not found"));
final List<FaoInstitute> toRemove = new ArrayList<FaoInstitute>();
// Make set of INSTCODEs
final Set<String> existingMembers = new HashSet<String>();
for (final FaoInstitute member : network.getMembers()) {
if (instituteList.contains(member.getCode())) {
existingMembers.add(member.getCode());
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("Will remove {}", member);
}
toRemove.add(member);
}
}
boolean updated = false;
for (final FaoInstitute institute : toRemove) {
LOG.info("Removing {}", institute);
network.getMembers().remove(institute);
updated = true;
}
for (final String wiewsCode : instituteList) {
if (!existingMembers.contains(wiewsCode)) {
final FaoInstitute newMemberInstitute = instituteRepository.findByCode(wiewsCode);
if (newMemberInstitute == null) {
LOG.warn("No such institute {}", wiewsCode);
} else {
LOG.info("Adding {}", newMemberInstitute);
network.getMembers().add(newMemberInstitute);
updated = true;
}
}
}
if (!updated) {
throw new InvalidApiUsageException("Network cannot be updated");
}
LOG.info("Saving {}", network);
return lazyLoad(networkRepository.save(network));
}
@Override
@Transactional
@PreAuthorize("hasRole('ADMINISTRATOR')")
@CacheEvict(value = CACHE_ORGANIZATION_INSTITUTEORGS, allEntries=true)
public PGRFANetwork addInstitutes(final PGRFANetwork network, final List<String> instituteList) {
LOG.info("Adding institutes to network {}", network);
// Make set of INSTCODEs
final Set<String> existingMembers = new HashSet<String>();
for (final FaoInstitute member : network.getMembers()) {
existingMembers.add(member.getCode());
}
boolean updated = false;
for (final String wiewsCode : instituteList) {
if (!existingMembers.contains(wiewsCode)) {
final FaoInstitute newMemberInstitute = instituteRepository.findByCode(wiewsCode);
if (newMemberInstitute == null) {
LOG.warn("No such institute {}", wiewsCode);
} else {
network.getMembers().add(newMemberInstitute);
updated = true;
}
}
}
if (!updated) {
throw new InvalidApiUsageException("Network cannot be updated");
}
return lazyLoad(networkRepository.save(network));
}
@Override
@Cacheable(value = CACHE_ORGANIZATION_INSTITUTEORGS, key = "#faoInstitute.id")
public List<PGRFANetwork> getNetworksFor(FaoInstitute faoInstitute) {
if (faoInstitute == null) {
throw new NullPointerException("faoInstitute");
}
return networkRepository.getNetworks(faoInstitute);
}
private PGRFANetwork lazyLoad(PGRFANetwork input) {
if (input == null)
return null;
if (input.getMembers() != null)
input.getMembers().size();
return input;
}
}