Java tutorial
/* * Copyright (c) 2018 OBiBa. All rights reserved. * * This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.obiba.mica.core.service; import com.google.common.base.Splitter; import com.google.common.base.Strings; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; import org.apache.shiro.SecurityUtils; import org.joda.time.DateTime; import org.obiba.mica.core.domain.DocumentSet; import org.obiba.mica.core.domain.InvalidDocumentSetTypeException; import org.obiba.mica.core.event.DocumentSetDeletedEvent; import org.obiba.mica.core.event.DocumentSetUpdatedEvent; import org.obiba.mica.core.repository.DocumentSetRepository; import org.obiba.mica.dataset.event.DatasetDeletedEvent; import org.obiba.mica.dataset.event.DatasetUnpublishedEvent; import org.obiba.mica.micaConfig.domain.MicaConfig; import org.obiba.mica.micaConfig.service.MicaConfigService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.Scheduled; import javax.annotation.Nullable; import javax.inject.Inject; import javax.validation.constraints.NotNull; import java.util.List; import java.util.NoSuchElementException; import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; public abstract class DocumentSetService { private static final Logger log = LoggerFactory.getLogger(DocumentSetService.class); @Inject private DocumentSetRepository documentSetRepository; @Inject private EventBus eventBus; @Inject private MicaConfigService micaConfigService; /** * Get document with ID and ensure the type is valid. * * @param id * @return */ public DocumentSet get(String id) { DocumentSet documentSet = findOne(id); ensureType(documentSet); return documentSet; } /** * Find document with ID. * * @param id * @return */ public DocumentSet findOne(String id) { DocumentSet documentSet = documentSetRepository.findOne(id); if (documentSet == null) throw new NoSuchElementException("No '" + getType() + "' set with id: " + id); return documentSet; } /** * Get all documents of type. * * @return */ public List<DocumentSet> getAll() { return documentSetRepository.findByType(getType()); } /** * Get all documents of type associated with current user. * * @return */ public List<DocumentSet> getAllCurrentUser() { return documentSetRepository.findByTypeAndUsername(getType(), SecurityUtils.getSubject().getPrincipal().toString()); } /** * Get document type. * * @return */ public abstract String getType(); /** * Create a set of documents associated to the current user. * * @param name * @param identifiers * @return */ public DocumentSet create(@Nullable String name, List<String> identifiers) { DocumentSet documentSet = new DocumentSet(); if (!Strings.isNullOrEmpty(name)) documentSet.setName(name); documentSet.setIdentifiers(identifiers); documentSet.setType(getType()); return save(documentSet, null); } /** * Delete definitely a document set. * * @param documentSet */ public void delete(DocumentSet documentSet) { ensureType(documentSet); if (!documentSet.isNew()) { documentSetRepository.delete(documentSet); eventBus.post(new DocumentSetDeletedEvent(documentSet)); } } /** * Extract a list of identifiers separated by new lines. * * @param importedIdentifiers * @return */ public List<String> extractIdentifiers(String importedIdentifiers) { if (Strings.isNullOrEmpty(importedIdentifiers)) return Lists.newArrayList(); return Splitter.on("\n").splitToList(importedIdentifiers).stream().filter(id -> !Strings.isNullOrEmpty(id)) .collect(Collectors.toList()); } /** * Add identifiers to a set. * * @param id * @param identifiers * @return */ public DocumentSet addIdentifiers(String id, List<String> identifiers) { DocumentSet documentSet = get(id); if (identifiers.isEmpty()) return documentSet; List<String> concatenatedIdentifiers = Stream .concat(documentSet.getIdentifiers().stream(), identifiers.stream()).distinct() .limit(micaConfigService.getConfig().getMaxItemsPerSet()).collect(Collectors.toList()); documentSet.setIdentifiers(concatenatedIdentifiers); return save(documentSet, null); } /** * Remove the given identifiers from the document set and notify about the removal. * * @param id * @param identifiers * @return */ public DocumentSet removeIdentifiers(String id, List<String> identifiers) { DocumentSet documentSet = get(id); if (identifiers.isEmpty()) return documentSet; documentSet.getIdentifiers().removeAll(identifiers); return save(documentSet, Sets.newLinkedHashSet(identifiers)); } /** * Set the new list of identifiers to a document set and notifies that some of them have been removed (if any). * * @param id * @param identifiers * @return */ public DocumentSet setIdentifiers(String id, List<String> identifiers) { DocumentSet documentSet = get(id); Set<String> removedIdentifiers = Sets.difference(documentSet.getIdentifiers(), Sets.newLinkedHashSet(identifiers)); documentSet.setIdentifiers(identifiers); return save(documentSet, removedIdentifiers); } /** * Verifies that a document set applies to the current service. * * @param documentSet * @return */ public boolean isForType(DocumentSet documentSet) { return documentSet != null && getType().equals(documentSet.getType()); } public void touch(DocumentSet documentSet) { saveInternal(documentSet); } @Async @Subscribe public void datasetUnpublished(DatasetUnpublishedEvent event) { // FIXME ignore for now as the dataset could be republished? } @Async @Subscribe public void datasetDeleted(DatasetDeletedEvent event) { // TODO find sets containing documents String datasetId = event.getPersistable().getId(); List<DocumentSet> sets = documentSetRepository.findByIdentifiers("^" + datasetId + ":"); // query fails: bug in spring data? } @Async @Scheduled(cron = "${sets.cleanup.cron:0 0 * * * ?}") public void cleanupOldSets() { MicaConfig config = micaConfigService.getConfig(); documentSetRepository.findAll().forEach(set -> { int timeToLive = set.hasName() ? config.getSetTimeToLive() : config.getCartTimeToLive(); DateTime deadline = DateTime.now().minusDays(timeToLive); if (set.getLastModifiedDate().isBefore(deadline)) { log.debug("Last updated {} - expiration {}", set.getLastModifiedDate(), deadline); log.info("{} {} has expired, deleting...", (set.hasName() ? "Set" : "Cart"), set.getId()); delete(set); } }); } protected List<String> extractIdentifiers(String importedIdentifiers, Predicate<String> predicate) { if (Strings.isNullOrEmpty(importedIdentifiers)) return Lists.newArrayList(); return Splitter.on("\n").splitToList(importedIdentifiers).stream().filter(id -> !Strings.isNullOrEmpty(id)) .filter(predicate).collect(Collectors.toList()); } protected void ensureType(@NotNull DocumentSet documentSet) throws InvalidDocumentSetTypeException { if (!getType().equals(documentSet.getType())) throw InvalidDocumentSetTypeException.forSet(documentSet, getType()); } private DocumentSet save(DocumentSet documentSet, Set<String> removedIdentifiers) { DocumentSet saved = saveInternal(documentSet); eventBus.post(new DocumentSetUpdatedEvent(saved, removedIdentifiers)); return saved; } private DocumentSet saveInternal(DocumentSet documentSet) { ensureType(documentSet); documentSet.setLastModifiedDate(DateTime.now()); if (Strings.isNullOrEmpty(documentSet.getUsername())) { Object principal = SecurityUtils.getSubject().getPrincipal(); if (principal != null) { documentSet.setUsername(principal.toString()); } } documentSet = documentSetRepository.save(documentSet); return documentSet; } }