AccessionServiceImpl.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.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.gringlobal.api.exception.InvalidApiUsageException;
import org.gringlobal.api.exception.NotFoundElement;
import org.gringlobal.api.v1.MultiOp;
import org.gringlobal.application.config.GGCESecurityConfig;
import org.gringlobal.component.GGCE;
import org.gringlobal.custom.elasticsearch.SearchException;
import org.gringlobal.model.Accession;
import org.gringlobal.model.AccessionAction;
import org.gringlobal.model.AccessionInvGroup;
import org.gringlobal.model.AccessionInvName;
import org.gringlobal.model.AccessionSource;
import org.gringlobal.model.AccessionSourceMap;
import org.gringlobal.model.Inventory;
import org.gringlobal.model.InventoryMaintenancePolicy;
import org.gringlobal.model.Method;
import org.gringlobal.model.QAccession;
import org.gringlobal.model.QAccessionAction;
import org.gringlobal.model.QAccessionInvGroup;
import org.gringlobal.model.QAccessionInvName;
import org.gringlobal.model.QAccessionPedigree;
import org.gringlobal.model.QAccessionSource;
import org.gringlobal.model.QInventory;
import org.gringlobal.model.Site;
import org.gringlobal.model.community.AccessionMCPD;
import org.gringlobal.model.community.CommunityCodeValues;
import org.gringlobal.model.workflow.WorkflowActionStep;
import org.gringlobal.persistence.AccessionActionRepository;
import org.gringlobal.persistence.AccessionInvAnnotationRepository;
import org.gringlobal.persistence.AccessionInvAttachRepository;
import org.gringlobal.persistence.AccessionInvGroupRepository;
import org.gringlobal.persistence.AccessionInvNameRepository;
import org.gringlobal.persistence.AccessionRepository;
import org.gringlobal.persistence.AccessionSourceRepository;
import org.gringlobal.persistence.InventoryMaintenancePolicyRepository;
import org.gringlobal.persistence.InventoryRepository;
import org.gringlobal.persistence.MethodRepository;
import org.gringlobal.persistence.SiteRepository;
import org.gringlobal.service.AccessionActionService;
import org.gringlobal.service.AccessionActionService.AccessionActionRequest;
import org.gringlobal.service.AccessionActionService.AccessionActionScheduleFilter;
import org.gringlobal.service.ShortFilterService.FilterInfo;
import org.gringlobal.service.AccessionInvGroupService;
import org.gringlobal.service.AccessionService;
import org.gringlobal.service.AccessionSourceMapService;
import org.gringlobal.service.InventoryAttachmentService;
import org.gringlobal.service.InventoryService;
import org.gringlobal.service.MethodService;
import org.gringlobal.service.filter.AccessionActionFilter;
import org.gringlobal.service.filter.AccessionFilter;
import org.gringlobal.spring.TransactionHelper;
import org.gringlobal.util.CoordUtil;
import org.gringlobal.worker.AccessionMCPDConverter;
import org.hibernate.Hibernate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
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.security.access.AccessDeniedException;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.google.common.base.Stopwatch;
import com.google.common.collect.Lists;
import com.querydsl.core.types.EntityPath;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.NumberPath;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.querydsl.core.types.ExpressionUtils;
@Service
@Transactional(readOnly = true)
@Slf4j
public class AccessionServiceImpl extends FilteredCRUDService2Impl<Accession, AccessionFilter, AccessionRepository> implements AccessionService {
private static final String[] BOOST_FIELDS = { "accessionNumber", "names.plantName", "taxonomySpecies.name" };
@Autowired
protected JPAQueryFactory jpaQueryFactory;
@Autowired
private InventoryService inventoryService;
@Autowired
private AccessionSourceRepository accessionSourceRepository;
@Autowired
private AccessionInvNameRepository accessionInvNameRepository;
@Autowired
private AccessionInvAttachRepository accessionInvAttachRepository;
@Autowired
private AccessionInvAnnotationRepository annotationRepository;
@Autowired
private AccessionInvGroupService accessionInvGroupService;
@Autowired
private AccessionInvGroupRepository accessionInvGroupRepository;
@Autowired
private AccessionSourceMapService accessionSourceMapService;
@Autowired
private SiteRepository siteRepository;
@Autowired
private InventoryMaintenancePolicyRepository inventoryMaintenancePolicyRepository;
@Autowired
private InventoryRepository inventoryRepository;
@Autowired
private MethodRepository methodRepository;
@Autowired
private OverviewHelper overviewHelper;
@Autowired
private AccessionMCPDConverter accessionMCPDConverter;
@Autowired
private GGCESecurityConfig.GgceSec ggceSec;
@Autowired
private InventoryAttachmentService attachmentService;
@Component
protected static class ActionSupport extends BaseActionSupport<Accession, AccessionAction, AccessionActionFilter, AccessionActionRepository, AccessionActionRequest, AccessionActionScheduleFilter>
implements AccessionActionService {
@Autowired
private AccessionRepository accessionRepository;
@Autowired
private MethodService methodService;
@Override
protected EntityPath<Accession> getOwningEntityPath() {
return QAccessionAction.accessionAction.accession();
}
@Override
protected void initializeActionDetails(List<AccessionAction> actions) {
actions.forEach(action -> Hibernate.initialize(action.getAccession()));
}
@Override
protected void applyOwningEntityFilter(AccessionActionScheduleFilter filter, String owningEntityAlias, List<Predicate> predicates) {
QAccession qAccession = new QAccession(owningEntityAlias);
if (predicates != null && filter.accession != null) {
predicates.addAll(filter.accession.collectPredicates(qAccession));
}
}
@Override
@PostAuthorize("@ggceSec.actionAllowed('PassportData', 'ADMINISTRATION', returnObject.accession.site)")
protected AccessionAction createAction(Accession owningEntity) {
AccessionAction action = new AccessionAction();
action.setAccession(owningEntity);
action.setIsWebVisible("N");
return action;
}
@Override
protected void updateAction(AccessionAction action, AccessionActionRequest request) {
action.setIsWebVisible(request.webVisible);
if (request.method != null && !request.method.isNew()) {
action.setMethod(methodService.get(request.method.getId()));
}
}
@Override
@Transactional
@PostAuthorize("@ggceSec.actionAllowed('PassportData', 'ADMINISTRATION', returnObject.accession.site)")
public AccessionAction create(AccessionAction source) {
assert (source.getId() == null);
AccessionAction saved = repository.save(source);
return _lazyLoad(saved);
}
@Override
@Transactional
@PostAuthorize("@ggceSec.actionAllowed('PassportData', 'ADMINISTRATION', returnObject.accession.site)")
public AccessionAction remove(AccessionAction entity) {
return super.remove(entity);
}
@Override
@Transactional
@PostAuthorize("@ggceSec.actionAllowed('PassportData', 'ADMINISTRATION', returnObject.accession.site)")
public AccessionAction update(AccessionAction updated) {
return super.update(updated);
}
@Override
protected Iterable<Accession> findOwningEntities(Set<Long> id) {
return accessionRepository.findAll(QAccession.accession.id.in(id));
}
@Override
public AccessionAction prepareNextWorkflowStepAction(WorkflowActionStep nextStep, AccessionAction completedAction) {
AccessionAction nextAction = new AccessionAction();
nextAction.setAccession(new Accession(completedAction.getAccession().getId()));
nextAction.setIsWebVisible("N");
return nextAction;
}
}
@Override
protected NumberPath<Long> entityIdPredicate() {
return QAccession.accession.id;
}
@Override
protected JPAQuery<Accession> entityListQuery() {
return jpaQueryFactory.selectFrom(QAccession.accession)
// site (@OneToOne)
.join(QAccession.accession.site()).fetchJoin()
// species (@OneToOne)
.join(QAccession.accession.taxonomySpecies()).fetchJoin()
// pedigree (@OneToOne optional)
.leftJoin(QAccession.accession.accessionPedigree()).fetchJoin();
}
@Override
@Transactional
@PostAuthorize("@ggceSec.actionAllowed('PassportData', 'CREATE', returnObject.site)")
public Accession create(Accession source) {
assert (source.getId() == null);
Accession accession = repository.save(source);
if (CollectionUtils.isNotEmpty(source.getAccessionSources())) {
// Clone and fix reference
List<AccessionSource> sources = source.getAccessionSources().stream().map((accessionSource) -> {
AccessionSource copy = new AccessionSource();
copy.apply(accessionSource);
copy.setAccession(accession);
return copy;
}).collect(Collectors.toList());
accession.setAccessionSources(accessionSourceRepository.saveAll(sources));
}
// we assure system inventory inside the aspect, so mustn't be null
Inventory systemInventory = inventoryRepository.getSystemInventory(accession);
if (CollectionUtils.isNotEmpty(source.getNames())) {
// Clone and fix reference
List<AccessionInvName> names = source.getNames().stream().map((accessionInvName) -> {
AccessionInvName copy = new AccessionInvName();
copy.apply(accessionInvName);
copy.setInventory(systemInventory);
return copy;
}).collect(Collectors.toList());
accessionInvNameRepository.saveAll(names);
}
return accession;
}
@Override
@Transactional
@PreAuthorize("@ggceSec.actionAllowed('PassportData', 'WRITE', #updated.site)")
@PostAuthorize("@ggceSec.actionAllowed('PassportData', 'WRITE', returnObject.site)")
public Accession update(Accession updated) {
return super.update(updated);
}
@Override
@Transactional
@PreAuthorize("@ggceSec.actionAllowed('PassportData', 'WRITE', #target.site)")
public Accession update(Accession updated, Accession target) {
assert (target.getId() != null);
assert (target.getId().equals(updated.getId()));
log.debug("Update Accession. Input data {}", updated);
target.apply(updated);
final Accession saved = repository.save(target);
// FIXME This must be revised
if (Hibernate.isInitialized(updated.getAccessionSources()) && CollectionUtils.isNotEmpty(updated.getAccessionSources())) {
// Update references
updated.getAccessionSources().forEach((accessionSource) -> {
accessionSource.setAccession(saved);
});
accessionSourceRepository.saveAll(updated.getAccessionSources());
}
return saved;
}
@Override
@Transactional
@PreAuthorize("@ggceSec.actionAllowed('PassportData', 'WRITE', #target.site)")
public Accession updateFast(Accession updated, Accession target) {
target.apply(updated);
return repository.save(target);
}
@Override
@Transactional
@PreAuthorize("@ggceSec.actionAllowed('PassportData', 'DELETE', #entity.site)")
public Accession remove(Accession entity) {
return super.remove(entity);
}
@Override
@Transactional
@PreAuthorize("@ggceSec.actionAllowed('PassportData', 'DELETE', #accession.site)")
public void deleteDefaultInventory(Accession accession) {
final Inventory systemInventory = inventoryRepository.getSystemInventory(accession);
if (systemInventory != null) {
log.info("Removing the SYSTEM inventory for removed accession {}", accession.getId());
inventoryRepository.delete(systemInventory);
}
}
@Override
public Page<Accession> list(AccessionFilter filter, Pageable page) throws SearchException {
return super.list(Accession.class, filter, page, BOOST_FIELDS);
}
@Override
public Page<AccessionMCPD> listMCPD(AccessionFilter filter, Pageable page) throws SearchException {
var stopWatch = Stopwatch.createStarted();
var r = super.list(Accession.class, filter, page, BOOST_FIELDS);
log.warn("Loaded page {} in {}ms", page.getPageNumber(), stopWatch.elapsed(TimeUnit.MILLISECONDS));
// Populate JPA caches
var accessionIds = new ArrayList<Long>(); // r.getContent().stream().map(Accession::getId).collect(Collectors.toList())
Map<Long, Accession> accessionsById = new HashMap<>();
r.getContent().forEach(a -> {
accessionIds.add(a.getId());
a.setInventories(new ArrayList<>());
a.setAccessionSources(new ArrayList<>());
a.setNames(new ArrayList<>());
accessionsById.put(a.getId(), a);
});
var accessionInventories = jpaQueryFactory.selectFrom(QInventory.inventory)
.where(QInventory.inventory.accession().id.in(accessionIds)).fetch();
log.warn("Loaded {} inventories for page {} in {}ms", accessionInventories.size(), page.getPageNumber(), stopWatch.elapsed(TimeUnit.MILLISECONDS));
accessionInventories.forEach(inv -> {
var a = accessionsById.get(inv.getAccession().getId());
if (a != null) {
a.getInventories().add(inv);
}
});
log.warn("Generated inventories of accessions in page {} in {}ms", page.getPageNumber(), stopWatch.elapsed(TimeUnit.MILLISECONDS));
var accessionSources = jpaQueryFactory.selectFrom(QAccessionSource.accessionSource)
.leftJoin(QAccessionSource.accessionSource.cooperators).fetchJoin()
.where(QAccessionSource.accessionSource.accession().id.in(accessionIds)).fetch();
log.warn("Loaded {} accessionSources for page {} in {}ms", accessionSources.size(), page.getPageNumber(), stopWatch.elapsed(TimeUnit.MILLISECONDS));
accessionSources.forEach(source -> {
var a = accessionsById.get(source.getAccession().getId());
if (a != null) {
a.getAccessionSources().add(source);
}
});
log.warn("Generated accessionSources of accessions in page {} in {}ms", page.getPageNumber(), stopWatch.elapsed(TimeUnit.MILLISECONDS));
var accessionInvNames = jpaQueryFactory.selectFrom(QAccessionInvName.accessionInvName)
.join(QAccessionInvName.accessionInvName.inventory()).fetchJoin()
.where(QAccessionInvName.accessionInvName.inventory().accession().id.in(accessionIds).and(QAccessionInvName.accessionInvName.inventory().formTypeCode.eq(Inventory.SYSTEM_INVENTORY_FTC)))
.orderBy(QAccessionInvName.accessionInvName.plantNameRank.asc())
.fetch();
log.warn("Loaded {} accessionInvName for page {} in {}ms", accessionInvNames.size(), page.getPageNumber(), stopWatch.elapsed(TimeUnit.MILLISECONDS));
accessionInvNames.forEach(accessionInvName -> {
var a = accessionsById.get(accessionInvName.getInventory().getAccession().getId());
if (a != null) {
a.getNames().add(accessionInvName);
}
});
log.warn("Generated accessionInvName of accessions in page {} in {}ms", page.getPageNumber(), stopWatch.elapsed(TimeUnit.MILLISECONDS));
var accessionPedigrees = jpaQueryFactory.selectFrom(QAccessionPedigree.accessionPedigree)
.where(QAccessionPedigree.accessionPedigree.accession().id.in(accessionIds)).fetch();
log.warn("Loaded {} accessionPedigree for page {} in {}ms", accessionPedigrees.size(), page.getPageNumber(), stopWatch.elapsed(TimeUnit.MILLISECONDS));
accessionPedigrees.forEach(accessionPedigree -> {
var a = accessionsById.get(accessionPedigree.getAccession().getId());
if (a != null) {
accessionPedigree.lazyLoad();
a.setAccessionPedigree(accessionPedigree);
}
});
log.warn("Generated accessionPedigree of accessions in page {} in {}ms", page.getPageNumber(), stopWatch.elapsed(TimeUnit.MILLISECONDS));
var result = new PageImpl<>(r.getContent().stream().map(accessionMCPDConverter::convert).collect(Collectors.toList()), page, r.getTotalElements());
log.warn("Converted page {} to MCPD in {}ms", page.getPageNumber(), stopWatch.elapsed(TimeUnit.MILLISECONDS));
return result;
}
@Override
@Transactional
@PreAuthorize("@ggceSec.actionAllowed('PassportData', 'ADMINISTRATION')")
public MultiOp<Accession> update(List<Accession> accessions) {
List<AccessionSource> accessionSources = accessions.stream().map(Accession::getAccessionSources)
// filter
.filter((s) -> s != null && s.size() > 0)
// merge to single list
.reduce(new ArrayList<>(), (aggregated, sources) -> {
aggregated.addAll(sources);
return aggregated;
});
accessions = accessions.stream().map(a -> repository.save(a)).collect(Collectors.toList());
accessionSourceRepository.saveAll(accessionSources);
return new MultiOp<>(accessions);
}
@Override
public AccessionDetails getAccessionDetails(Accession accession) {
if (accession == null) {
throw new NotFoundElement();
}
accession = this.reload(accession);
// initialize lazy data
Hibernate.initialize(accession.getAccessionSources());
Hibernate.initialize(accession.getAccessionActions());
Hibernate.initialize(accession.getAccessionIprs());
Hibernate.initialize(accession.getAccessionPedigree());
Hibernate.initialize(accession.getAccessionQuarantines());
Hibernate.initialize(accession.getCitations());
Hibernate.initialize(accession.getBackupLocation1Site());
Hibernate.initialize(accession.getBackupLocation2Site());
Hibernate.initialize(accession.getExploration());
AccessionDetails accessionDetails = new AccessionDetails();
accessionDetails.accession = accession;
accessionDetails.sources = accession.getAccessionSources();
if (accessionDetails.sources != null) {
accessionDetails.sources.forEach((source) -> source.lazyLoad());
}
accessionDetails.actions = accession.getAccessionActions();
accessionDetails.ipr = accession.getAccessionIprs();
accessionDetails.pedigree = accession.getAccessionPedigree();
if (accessionDetails.pedigree != null) {
accessionDetails.pedigree.lazyLoad();
}
accessionDetails.quarantine = accession.getAccessionQuarantines();
if (accessionDetails.quarantine != null) {
accessionDetails.quarantine.forEach((quarantine) -> quarantine.lazyLoad());
}
accessionDetails.citations = accession.getCitations();
accessionDetails.names = accessionInvNameRepository.findAccessionNames(accession, Inventory.SYSTEM_INVENTORY_FTC);
accessionDetails.groups = accessionInvGroupService.listAccessionGroups(accession);
accessionDetails.attachments = accessionInvAttachRepository.findAccessionAttachments(accession, Inventory.SYSTEM_INVENTORY_FTC);
accessionDetails.attachments.forEach(accessionInvAttach -> {
if (accessionInvAttach.getAttachCooperator() != null) {
accessionInvAttach.getAttachCooperator().getId();
}
});
accessionDetails.annotations = annotationRepository.findAccessionAnnotations(accession, Inventory.SYSTEM_INVENTORY_FTC);
accessionDetails.sourceCooperators = accessionSourceMapService.listAccessionSourceMaps(accession);
return accessionDetails;
}
@Override
public AccessionMCPD getMCPD(Long id) {
return accessionMCPDConverter.convert(get(id));
}
@Override
@Transactional
@PreAuthorize("@ggceSec.actionAllowed('Acquisition', 'CREATE')")
public AccessionInvGroup acquire(AcquisitionData acquisitionBatch) {
if (acquisitionBatch.accessions == null || acquisitionBatch.accessions.size() == 0) {
throw new InvalidApiUsageException("No accessions in acquisition batch");
}
Method method = acquisitionBatch.methodId == null ? null : methodRepository.getReferenceById(acquisitionBatch.methodId);
if (method != null) {
log.info("Registering new material with method {}", method.getName());
}
Site site = siteRepository.getReferenceById(acquisitionBatch.siteId);
log.info("Registering new material with site {}", site.getSiteShortName());
InventoryMaintenancePolicy inventoryMaintPolicy = inventoryMaintenancePolicyRepository.getReferenceById(acquisitionBatch.inventoryMaintenancePolicyId);
log.info("Using policy {}", inventoryMaintPolicy.getMaintenanceName());
// Make accessions
List<Accession> accessions = acquisitionBatch.accessions.stream().map((newAcce) -> {
newAcce.setSite(site);
var acce = create(newAcce);
acce.setInitialReceivedDate(acquisitionBatch.sourceDate);
if (acce.getInitialReceivedDate() != null) {
acce.setInitialReceivedDateCode(StringUtils.defaultIfBlank(acquisitionBatch.sourceDateCode, CommunityCodeValues.DATE_FORMAT_DATE.value));
}
if (acquisitionBatch.sourceTypeCode != null) {
var accessionSource = new AccessionSource();
accessionSource.setAccession(acce);
accessionSource.setSourceTypeCode(acquisitionBatch.sourceTypeCode);
accessionSource.setSourceDate(acquisitionBatch.sourceDate);
accessionSource.setSourceDateCode(StringUtils.defaultIfBlank(acquisitionBatch.sourceDateCode, CommunityCodeValues.DATE_FORMAT_DATE.value));
accessionSource.setNote(acquisitionBatch.sourceNote);
accessionSource = accessionSourceRepository.save(accessionSource);
if (acquisitionBatch.sourceCooperator != null) {
accessionSourceMapService.create(new AccessionSourceMap(accessionSource, acquisitionBatch.sourceCooperator));
}
}
return acce;
}).collect(Collectors.toList());
log.warn("Created {} accessions", accessions.size());
// Make inventories
List<Inventory> inventories = accessions.stream().map((accession) -> {
Inventory inventory = new Inventory();
inventory.setAccession(accession);
inventory.setSite(site);
inventory.setInventoryNumberPart1(acquisitionBatch.inventoryNumberPart1);
inventory.setInventoryNumberPart2(AccessionService.AUTO_GENERATE_VALUE);
inventory.setInventoryMaintenancePolicy(inventoryMaintPolicy);
inventory.setFormTypeCode(acquisitionBatch.formTypeCode);
inventory.setAvailabilityStatusCode(acquisitionBatch.availabilityStatusCode);
return inventoryService.create(inventory);
}).collect(Collectors.toList());
log.warn("Created {} inventories", inventories.size());
// Register group
var groupName = acquisitionBatch.groupName;
if (StringUtils.isBlank(groupName)) {
throw new InvalidApiUsageException("Empty group name in acquisition batch");
}
AccessionInvGroup group;
group = accessionInvGroupRepository.findOne(QAccessionInvGroup.accessionInvGroup.groupName.eq(groupName)).orElse(null);
if (group == null) {
group = new AccessionInvGroup();
group.setGroupName(groupName);
group.setNote(acquisitionBatch.note);
group.setMethod(method);
group = accessionInvGroupService.create(group);
log.info("Registered group id={} {}", group.getId(), group.getGroupName());
}
group = accessionInvGroupService.addMembers(group, inventories, null);
return accessionInvGroupService.load(group.getId());
}
@Override
public Map<Object, Number> accessionOverview(String groupBy, AccessionFilter filter) {
return overviewHelper.getOverview(Accession.class, QAccession.accession, QAccession.accession.id.countDistinct(), groupBy, filter);
}
@Override
@PreAuthorize("hasRole('ADMINISTRATOR')")
public void recalculateAllAccessionNumbers() {
boolean lastPage = false;
int pageNumber = 0;
do {
Page<Accession> page = repository.findAll(PageRequest.of(pageNumber, 1000));
lastPage = page.isLast();
pageNumber += 1;
log.warn("Updating accessionNumber for {} records, page {}", page.getNumberOfElements(), pageNumber);
Lists.partition(page.getContent(), 100).forEach(batch -> TransactionHelper.executeInTransaction(false, () -> {
batch.forEach(a -> repository.setAccessionNumber(a.getId(), GGCE.accessionNumber(a)));
return true;
}));
} while (!lastPage);
log.info("Done.");
}
@Override
@PreAuthorize("hasRole('ADMINISTRATOR')")
public void assignMissingAccessionNumbers() {
boolean lastPage = false;
int pageNumber = 0;
do {
Page<Accession> page = repository.findAll(QAccession.accession.accessionNumber.isNull(), PageRequest.of(0, 1000));
lastPage = page.isLast();
pageNumber++;
log.warn("Assigning accessionNumber for {} records, page {}", page.getNumberOfElements(), pageNumber);
Lists.partition(page.getContent(), 100).forEach(batch -> TransactionHelper.executeInTransaction(false, () -> {
batch.forEach(a -> repository.setAccessionNumber(a.getId(), GGCE.accessionNumber(a)));
return true;
}));
} while (!lastPage && pageNumber < 1000); // at most 1000 loops
log.info("Done.");
}
@Override
@Transactional
public void shareAttachment(Long attachId, List<Long> accessionIds) {
var accessions = repository.findAll(QAccession.accession.id.in(accessionIds), Pageable.unpaged()).getContent();
var hasUnavailableSite = accessions.stream()
.map(Accession::getSite)
.distinct()
.anyMatch(site -> !ggceSec.actionAllowed("PassportData", "ADMINISTRATION", site));
if (hasUnavailableSite) {
throw new AccessDeniedException("Don't have permission to create attachments for the selected accessions");
}
var attachment = attachmentService.get(attachId);
var accessionInventories = accessions.stream()
.map(a -> a.getInventories().stream().filter(inv -> Inventory.SYSTEM_INVENTORY_FTC.equals(inv.getFormTypeCode())).findFirst().orElse(null))
.collect(Collectors.toList());
attachmentService.shareAttachment(attachment, accessionInventories);
}
@Autowired
@Lazy
private TileMaker tileMaker;
@Override
@Transactional(readOnly = true)
public byte[] getTile(AccessionFilter filter, int zoom, int xtile, int ytile) throws IOException {
final double latN = CoordUtil.tileToLat(zoom, ytile);
final double latS = CoordUtil.tileToLat(zoom, ytile + 1);
final double diffLat = latN - latS;
final double lonW = CoordUtil.tileToLon(zoom, xtile);
final double lonE = CoordUtil.tileToLon(zoom, xtile + 1);
final double diffLon = lonE - lonW;
if (log.isDebugEnabled()) {
log.debug("{} <= lat <= {} corr={}", latS, latN, diffLat * .1);
log.debug("{} <= lon <= {} corr={}", lonW, lonE, diffLon * .1);
}
return tileMaker.makeTile(zoom, xtile, ytile, () -> {
var qAccSrc = QAccessionSource.accessionSource;
return jpaQueryFactory.select(qAccSrc.latitude, qAccSrc.longitude).distinct().from(qAccSrc)
.where(qAccSrc.isOrigin.eq("Y").and(qAccSrc.latitude.between(latS - diffLat * .1, latN + diffLat * .1)).and(qAccSrc.longitude.between(lonW - diffLon * .1, lonE + diffLon * .1)).and(ExpressionUtils.allOf(filter.collectPredicates(qAccSrc.accession()))))
.stream().map(tuple -> new Double[] { tuple.get(qAccSrc.latitude), tuple.get(qAccSrc.longitude) });
});
}
@Override
@Transactional(readOnly = true)
public MapInfo<AccessionFilter> mapInfo(FilterInfo<AccessionFilter> filterInfo) {
var mapInfo = new MapInfo<AccessionFilter>();
mapInfo.filterCode = filterInfo.filterCode;
mapInfo.filter = filterInfo.filter;
var qAccSrc = QAccessionSource.accessionSource;
mapInfo.count = jpaQueryFactory.select(qAccSrc.accession().countDistinct()).from(qAccSrc).where(qAccSrc.isOrigin.eq("Y").and(ExpressionUtils.allOf(filterInfo.filter.collectPredicates(qAccSrc.accession())))).fetchOne();
var bounds = jpaQueryFactory.select(qAccSrc.latitude.min(), qAccSrc.longitude.min(), qAccSrc.latitude.max(), qAccSrc.longitude.max()).from(qAccSrc).where(qAccSrc.isOrigin.eq("Y").and(ExpressionUtils.allOf(filterInfo.filter.collectPredicates(qAccSrc.accession())))).fetchOne();
mapInfo.bounds = new Double[][] {
{ bounds.get(0, Double.class), bounds.get(1, Double.class) },
{ bounds.get(2, Double.class), bounds.get(3, Double.class) }
};
return mapInfo;
}
}